忍者ブログ

2025
05
10

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

2025/05/10 (Sat.)

2012
06
30

strncpyを使った安全な文字列コピー(C言語)

コピー元の文字列の長さが不明な時用のメモリ破壊を起こさない
文字列コピーの方法について、strncpyの動作を見ながら確認したメモ
結論から言うと
strncpy(dst, src, DST_BUFF_LEN);
dst[DST_BUFF_LEN-1] = '\0';
すれば破壊は起きない、ただsrcをコピーしきれないことがある。
下記のソースを試したコンパイラバージョンは
gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)です。

ソースコード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* nex2t_strncpy.c */
#include <stdio.h>
#include <string.h>
 
#define EX_STR "0123456789abcdefghij"
#define EX_STR2 "01234"
#define BUF_LEN     16
#define DEBUG_LINE "---------------------------------------------------------\n"
 
int main(void)
{
    int i;
    char buf[BUF_LEN];
 
    /* -------------------------------------------------------------- */
    printf(DEBUG_LINE);
    printf("use buffer buf[BUF_LEN] BUF_LEN=%d\n", BUF_LEN);
    printf(DEBUG_LINE);
    printf("EX_STR:%s [strlen(EX_STR):%ld, sizeof(EX_STR):%ld]\n", EX_STR,
           strlen(EX_STR), sizeof(EX_STR));
    printf("       (over buf[BUF_LEN] size!!)\n");
    printf(DEBUG_LINE);
    printf("EX_STR2:%s [strlen(EX_STR2):%ld, sizeof(EX_STR2):%ld]\n",
           EX_STR2, strlen(EX_STR2), sizeof(EX_STR2));
    printf("       (not over buf[BUF_LEN] size)\n");
    printf(DEBUG_LINE "\n");
 
 
    /* ---- Init after ----------------------------------------------- */
    printf("Init after\n");
    printf(DEBUG_LINE);
    for (i = 0; i < BUF_LEN; i++) {
        buf[i] = '\0';
    }
    for (i = 0; i < BUF_LEN; i++) {
        printf("buf[%d] = %d\n", i, buf[i]);
    }
    printf("buf[BUF_LEN] = %d  (secretly watch.)\n\n", buf[BUF_LEN]);
 
 
    /* ---- Normal_1 ------------------------------------------------ */
    printf("Normal_1\n");
    printf(DEBUG_LINE);
    strncpy(buf, EX_STR, 5);
    printf("strncpy(buf, EX_STR, 5);\n");
    printf("result:string:%s [strlen(buf):%ld, sizeof(buf):%ld]\n", buf,
           strlen(buf), sizeof(buf));
    for (i = 0; i < BUF_LEN; i++) {
        printf("buf[%d] = %d\n", i, buf[i]);
    }
    printf("buf[BUF_LEN] = %d  (secretly watch.)\n\n", buf[BUF_LEN]);
    /* init */
    for (i = 0; i < BUF_LEN; i++) {
        buf[i] = '\0';
    }
 
    /* ---- Normal_2 ----------------------------------------------- */
    printf("Normal_2\n");
    printf(DEBUG_LINE);
    strncpy(buf, EX_STR, BUF_LEN);
    printf("strncpy(buf, EX_STR, BUF_LEN);\n");
    printf("result:string:%s [strlen(buf):%ld, sizeof(buf):%ld]\n", buf,
           strlen(buf), sizeof(buf));
    for (i = 0; i < BUF_LEN; i++) {
        printf("buf[%d] = %d\n", i, buf[i]);
    }
    printf("buf[BUF_LEN] = %d  (secretly watch.)\n\n", buf[BUF_LEN]);
    printf("***Not write '\\0' automatically!! (buf[%d] = %d)\n",
           BUF_LEN-1, buf[BUF_LEN-1]);
    printf("***Not write buf[BUF_LEN] (buf[%d] = %d)\n\n",
           BUF_LEN, buf[BUF_LEN]);
    /* not init */
    /*
    for (i = 0; i < BUF_LEN; i++) {
        buf[i] = '\0';
    }
    */
 
    /* ---- Normal_3 ----------------------------------------------- */
    printf("Normal_3\n");
    printf(DEBUG_LINE);
    strncpy(buf, EX_STR2, BUF_LEN);
    printf("strncpy(buf, EX_STR2, BUF_LEN);\n");
    printf("result:string:%s [strlen(buf):%ld, sizeof(buf):%ld]\n", buf,
           strlen(buf), sizeof(buf));
    for (i = 0; i < BUF_LEN; i++) {
        printf("buf[%d] = %d\n", i, buf[i]);
    }
    printf("buf[BUF_LEN] = %d  (secretly watch.)\n\n", buf[BUF_LEN]);
    printf("***automatically write '\\0' to buf[15]\n");
 
    /* ---- Extra ------------------------------------------------- */
    printf("\nExtra\n");
    printf(DEBUG_LINE);
    strncpy(buf, EX_STR, 0);
    printf("strncpy(buf, EX_STR, 0);\n");
    printf("result:string:%s [strlen(buf):%ld, sizeof(buf):%ld]\n", buf,
           strlen(buf), sizeof(buf));
    for (i = 0; i < BUF_LEN; i++) {
        printf("buf[%d] = %d\n", i, buf[i]);
    }
    printf("buf[BUF_LEN] = %d  (secretly watch.)\n\n", buf[BUF_LEN]);
    printf("Not write any.\n\n");
 
 
    /* ---- Right usage ------------------------------------------- */
    printf("Right usage\n");
    printf(DEBUG_LINE);
    strncpy(buf, EX_STR, BUF_LEN);
    buf[BUF_LEN-1] = '\0';
    for (i = 0; i < BUF_LEN; i++) {
        printf("buf[%d] = %d\n", i, buf[i]);
    }
    printf("buf[BUF_LEN] = %d  (secretly watch.)\n\n", buf[BUF_LEN]);
 
    printf("strncpy(buf, EX_STR, BUF_LEN); after buf[BUF_LEN-1] = '\\0';");
 
    return 0;
 
}

コンパイル例

1
gcc -W -Wall -o nex2t_strncpy nex2t_strncpy.c

実行結果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
./strncpy
---------------------------------------------------------
use buffer buf[BUF_LEN] BUF_LEN=16
---------------------------------------------------------
EX_STR:0123456789abcdefghij [strlen(EX_STR):20, sizeof(EX_STR):21]
       (over buf[BUF_LEN] size!!)
---------------------------------------------------------
EX_STR2:01234 [strlen(EX_STR2):5, sizeof(EX_STR2):6]
       (not over buf[BUF_LEN] size)
---------------------------------------------------------
 
Init after
---------------------------------------------------------
buf[0] = 0
buf[1] = 0
buf[2] = 0
buf[3] = 0
buf[4] = 0
buf[5] = 0
buf[6] = 0
buf[7] = 0
buf[8] = 0
buf[9] = 0
buf[10] = 0
buf[11] = 0
buf[12] = 0
buf[13] = 0
buf[14] = 0
buf[15] = 0
buf[BUF_LEN] = 0  (secretly watch.)
 
Normal_1
---------------------------------------------------------
strncpy(buf, EX_STR, 5);
result:string:01234 [strlen(buf):5, sizeof(buf):16]
buf[0] = 48
buf[1] = 49
buf[2] = 50
buf[3] = 51
buf[4] = 52
buf[5] = 0
buf[6] = 0
buf[7] = 0
buf[8] = 0
buf[9] = 0
buf[10] = 0
buf[11] = 0
buf[12] = 0
buf[13] = 0
buf[14] = 0
buf[15] = 0
buf[BUF_LEN] = 0  (secretly watch.)
 
Normal_2
---------------------------------------------------------
strncpy(buf, EX_STR, BUF_LEN);
result:string:0123456789abcdef [strlen(buf):16, sizeof(buf):16]
buf[0] = 48
buf[1] = 49
buf[2] = 50
buf[3] = 51
buf[4] = 52
buf[5] = 53
buf[6] = 54
buf[7] = 55
buf[8] = 56
buf[9] = 57
buf[10] = 97
buf[11] = 98
buf[12] = 99
buf[13] = 100
buf[14] = 101
buf[15] = 102
buf[BUF_LEN] = 0  (secretly watch.)
 
***Not write '\0' automatically!! (buf[15] = 102)
***Not write buf[BUF_LEN] (buf[16] = 0)
 
Normal_3
---------------------------------------------------------
strncpy(buf, EX_STR2, BUF_LEN);
result:string:01234 [strlen(buf):5, sizeof(buf):16]
buf[0] = 48
buf[1] = 49
buf[2] = 50
buf[3] = 51
buf[4] = 52
buf[5] = 0
buf[6] = 0
buf[7] = 0
buf[8] = 0
buf[9] = 0
buf[10] = 0
buf[11] = 0
buf[12] = 0
buf[13] = 0
buf[14] = 0
buf[15] = 0
buf[BUF_LEN] = 0  (secretly watch.)
 
***automatically write '\0' to buf[15]
 
Extra
---------------------------------------------------------
strncpy(buf, EX_STR, 0);
result:string:01234 [strlen(buf):5, sizeof(buf):16]
buf[0] = 48
buf[1] = 49
buf[2] = 50
buf[3] = 51
buf[4] = 52
buf[5] = 0
buf[6] = 0
buf[7] = 0
buf[8] = 0
buf[9] = 0
buf[10] = 0
buf[11] = 0
buf[12] = 0
buf[13] = 0
buf[14] = 0
buf[15] = 0
buf[BUF_LEN] = 0  (secretly watch.)
 
Not write any.
 
Right usage
---------------------------------------------------------
buf[0] = 48
buf[1] = 49
buf[2] = 50
buf[3] = 51
buf[4] = 52
buf[5] = 53
buf[6] = 54
buf[7] = 55
buf[8] = 56
buf[9] = 57
buf[10] = 97
buf[11] = 98
buf[12] = 99
buf[13] = 100
buf[14] = 101
buf[15] = 0
buf[BUF_LEN] = 0  (secretly watch.)
 
strncpy(buf, EX_STR, BUF_LEN); after buf[BUF_LEN-1] = '\0';

検索用タグ C言語 strncpy 安全

拍手[0回]

PR

2012/06/30 (Sat.) Comment(0) C言語

Comments

名前
メールアドレス
URL
コメント
PASS  Vodafone絵文字 i-mode絵文字 Ezweb絵文字

ブログ内検索

最新記事

カテゴリー

アーカイブ

フリーエリア





プロフィール

HN:
nex2t
年齢:
9
性別:
男性
誕生日:
2016/01/01
職業:
開発エンジニア(ソフト)
趣味:
ラグビー 犬 将棋 ラーメン サーフィン(ネット)
自己紹介:
入社2年目の組込みエンジニア
好きな言語:C言語
エディタ:emacs
シェル:zsh
ディストリ:Scientific Linux, Ubuntu
略歴
お仕事のほう
2011/3 調布にある大学卒業
2011/4~6月 研修
2011/7~12月? 10GのLANドライバをがんばる
2012/1~2012/4月? VDCPデーモンを作る
2012/5~2012/10月? genlockデーモンを作る
~(現在) 装置テストなど

趣味などのほう
~2012年4月 自由気ままに。仕事の勉強など。歯医者に時間を取られる。
2012年4月~2012年6月 機動力が増す(バイクの免許&バイク(125ccの原付をゲットする)
2012年6月~2012年8月 将棋のネットゲームを作る(引きこもる)((こころざし半ば)
2012年7月~2012年8月 通勤途中にバイクでこけて('自損)、1か月チャリ通の刑になる
2012年9月~現在(2013年3月) DDRばかりする(主にDP)

(↑2013/3/10更新)

DDRのほう
------------------------------------------
・199?年 小学校高学年。
よく遊ぶ友達内でDDRが流行る。
3rdが家にあり、家庭用マットもあったが、ゲーセンでプレイすることは皆無。
(コロコロコミックとガブリチュウを買うと小遣いがなくなるぐらいしかお金がない)
Burtyfly、DAM DARIRAMとかの誰でも聞いたことあるような曲、DEAD END、Paranoia Rebirth、AFRONOVAとかちょっと難しい曲、
BUMBLE BEE、End of the Centuryとかいい感じで印象に残っている。
GRADIUSIC CYBERが当時意味不明で難しいなと思っていた。
ハンドクラップの他にもメトロノームとかついてた気がする。
スコアとかを気にしたことはなかった。
------------------------------------------
・199?年 中学。
4thを中古で購入。半年に1回ぐらいプレイしてた?(手でやるだけ)。
ワンダ・古畑・HERO・ピンクダイナソー・オリオン・DROP OUT(当時とても速かった)とかが印象に残っている。
---------------------------------------------
・200?年 高校。
MAXを中古で買って、たまにやっていた。ゲーセンに1クレだけ踏みに行ったりしてた。
SO DEEP、天ヒー、象さん、ウィッチドクター、トワイライトゾーン、MAX300が印象に残っている。
この頃、MAX300 SPのリズム(ダンダン ダダンダ(ry)が体に染みついた模様笑。
なおMAXは友人に貸したままの模様。
------------------------------------------
・200?年 大学。
数か月に1回、ストレス発散がてら踏んでいた。確かXとかX2だった気がする。
踏むのは決まって8分でけっこう踏んだ気になる、AFRONOVA、天ヒー、象さん。
Aランクとか出せたことがなかった。
---------------------------------------------
・2012年9月 社会人 X3
コミケ準備のため引きこもっていた反動で、外出ばかりする。
ゲーセンで久々にプレイするととても楽しい(画面もきれいでパネルの反応も良い)。
今まで適当にやってきたが、少しシステムとかスコアを気にし始める。
自分のお金ということもあり、ゲーセンで千円単位でお金を使うことが自然になり、
真面目にDDRをするようになる。
------------------------------------------
・2012年12月 X3
SPしかやったことがなかったが、当時よく通ったゲーセンがDPする人が多く、
楽しそうだったので、DPをやり始める、足の裏の皮がむける。
---------------------------------------------
・2013年4月? X3終了。 DDR2013へ
X3はSP足鳳凰、DP足龍で終了。DPは足12以下の好きな曲のみフルコンができるような具合だった。
------------------------------------------
・2013年7月 ついったーで記録をつけるようになる。
8月4日 足10以下の激譜面AA埋め達成。鬼鯖初クリア
8月10日 足11以下の激譜面AA埋め達成。
8月24日 DDR2013 1000クレ行く。
9月8日 足12以下の激譜面AA埋め達成。
10月   (私用でドタバタする。)
11月2日 Skill pointが1000行く。
11月3日 岐阜のDDR大会 DPノンバー部門参加(予選通過ならず)
11月16日 DP足鳳凰。(エレクリDDPフルコン)
11月22日 足13以下の激譜面AA埋め達成。
11月24日 DP足紙さま?。(苺プリンDDPフルコン、鬼鯖810k同時だった)
Double AA Line 14になる。
現在~  足14のAA埋め、足15のA取得、足13の鳥取りを頑張り中。
------------------------------------------
(↑2013/11/28追加)

最新CM

[06/01 履歴書の書き方]

カウンター