
sprintf関数について教えて下さい。
#include <stdio.h>
int main(void)
{
int i;
char ns[20][6];
for (i = 0; i < 20; i++)
sprintf(ns[i], "No.%02d", i + 1);
for (i = 0; i < 2; i++)
printf("%s\n", ns[i]);
return 0;
}
上のプログラムでは結果が
No.01
No.02
(中略)
No.19
No.20
ですが、sprintf関数内の書式指定を"No.%02d\n"に変更した場合、
結果が
No.01
No.02
(中略)
No.19
No.20
No.02
No.03
(中略)
No.19
No.20
No.03
No.04
(中略)
No.19
No.20
(中略)
No.19
No.20
No.20
になります。
どうしてこのようなことが起きてしまうのか自分では説明できません。
sprintf関数の説明も読んで納得はしたのですが
上のようになることがわかりません。
長々と書いてしまいましたが
よろしくお願い致します。
No.3ベストアンサー
- 回答日時:
まず
char ns[20][6];
と宣言したときnsの占めるメモリ領域は
ns[0][0],ns[0][1],ns[0][2],ns[0][3],ns[0][4],ns[0][5],ns[1][0],ns[1][1],...,ns[19][5]
のように並びます。
sprintfで"No.%02d"を使って設定すると設定される文字列は
ns[0][0]='N',ns[0][1]='o',ns[0][2]='.',ns[0][3]='0',ns[0][4]='1',ns[0][5]='\0',...
のようになり、特に問題なく設定されていきますが
sprintfで"No.%02d\n"を使うと
ns[0][0]='N',ns[0][1]='o',ns[0][2]='.',ns[0][3]='0',ns[0][4]='1',ns[0][5]='\n',ns[1][0]='\0',...
のように範囲をあふれて設定されます。
このns[1][0]='\0'の部分は次のループで'N'で上書きされるため、ns[19]を除くns[i]は文字列の終わりがない状態になり、後のループのprintfは一回ごとにns[i]の初めからns[19]の直後のメモリ領域に書き込まれた'\0'までを一つの文字列とみなして表示します。
その結果が質問で書かれた表示です。
No.2
- 回答日時:
これは単にsprintfの問題では無いですね。
最初に二次元配列(ns)を宣言してる部分がありますが、
ns[20][6]だと5文字しか入力できません。
(文字列終端文字[\0]を含むので)
"No.%02d"の場合は[\0]を含んで6文字ですが、
"No.%02d\n"の場合は[\0]を含んで7文字になります。
なので、メモリオーバーフローが起きているので、おかしな結果がでているようです。
二次元配列を宣言するときに、
char ns[20][7]
とすればいけますよ。
/////////////////////////////////////////////////////////
#include <stdio.h>
int main(void)
{
int i;
char ns[20][7];
for (i = 0; i < 20; i++)
sprintf(ns[i], "No.%02d", i + 1);
for (i = 0; i < 20; i++)
printf("%s\n", ns[i]);
return 0;
}
/////////////////////////////////////////////////////////
No.1
- 回答日時:
>for (i = 0; i < 2; i++)
20では?
sprintfで格納される文字数が6を超えます。
>"No.%02d"
は 5文字 + 終端文字('\0') で6文字必要です。
>"No.%02d\n"
は先ほどより '\n'分文字が必要なので7文字必要です。
>char ns[20][6];
より
ns[i]は6文字分しか入らないので、はみ出した1文字は
ns[i + 1][0]に格納されます。
(2次元配列の場合連続した領域が割り当てられる。
ns[0][0] ns[0][1] ・・・・・ n[0][5] n[1][0] n[1][1] ・・・ n[19][5])
※ここで、ns[19]にsprintfで格納時、はみ出た1文字は
nsの領域外に設定されてしまいます→不正アクセスで落ちる可能性がある。
printfで書式文字 %s を指定した場合、\0 までを表示するので、\0はループの中で次々と上書きされているわけなので、
出現するのは ns[19][5]の次になるすなわち全ての文字が一度のprintfで表示されるのです。
>char ns[20][6];
を
char ns[20][7];
>for (i = 0; i < 2; i++)
>printf("%s\n", ns[i]);
を
for (i = 0; i < 20; i++)
printf("%s", ns[i]);
とすると同じ結果になるでしょう。
この回答への補足
すいません、訂正します。
プログラム中の2番目のfor文ですが
(誤)for (i = 0; i < 2; i++)
(正)for (i = 0; i < 20; i++)
です。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
人気Q&Aランキング
-
4
%dなどの違い
-
5
プログラムによく出てくるst...
-
6
char型配列の最大要素数
-
7
C#でstringをポインタとして渡す
-
8
Shift_JIS(16進)を文字に変換す...
-
9
c#で他のアプリの文字入力フォ...
-
10
16進数を2文字ずつ配列に格納し...
-
11
C言語の課題で困っています;
-
12
シリアル通信で0x00を送信した...
-
13
数字の入った配列をファイルへ...
-
14
VB6.0でのバイナリデータの扱い...
-
15
_tcscpy_s(wcscpy_s)の第二引数...
-
16
アルファベットをカウント、
-
17
構造体→文字列→構造体 をする方法
-
18
TCL言語で文字列検索方法を教え...
-
19
char a[]="thank you for comin...
-
20
C言語についてです学籍番号、名...
おすすめ情報
公式facebook
公式twitter