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で質問しましょう!
似たような質問が見つかりました
- UNIX・Linux Linuxの実行結果を修正したいです。 2 2022/11/23 08:32
- Excel(エクセル) vba シート名の一覧を2列に分けるには 5 2023/04/24 08:56
- UNIX・Linux Linuxの実行結果を修正したいです。 6 2022/11/22 12:57
- Visual Basic(VBA) マクロで設定時刻の入力がわかりません 2 2022/03/29 02:24
- ルーター・ネットワーク機器 ひとつのスイッチでルーターの冗長化を複数させたい 1 2023/04/12 22:46
- その他(プログラミング・Web制作) Pythonで会員サイトの自動ログイン ID Nameがない 1 2022/12/16 02:09
- 日本語 問題: A:トイレにだれ___いませんか。その2 1 2023/03/12 22:01
- Excel(エクセル) EXCEL 関数を教えてください。(A列の同じ値が複数ある場合vlookupで出来ますか) 4 2022/12/07 20:54
- 英語 英語でNo.1がシッコ、No.2がウンコの事らしいですが、 たとえば No.1行ってくるー! って言 3 2022/10/20 22:21
- JavaScript 1日1回引けるJavaScriptおみくじについて 1 2022/12/12 22:28
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・【大喜利】【投稿~11/22】このサンタクロースは偽物だと気付いた理由とは?
- ・お風呂の温度、何℃にしてますか?
- ・とっておきの「まかない飯」を教えて下さい!
- ・2024年のうちにやっておきたいこと、ここで宣言しませんか?
- ・いけず言葉しりとり
- ・土曜の昼、学校帰りの昼メシの思い出
- ・忘れられない激○○料理
- ・あなたにとってのゴールデンタイムはいつですか?
- ・とっておきの「夜食」教えて下さい
- ・これまでで一番「情けなかったとき」はいつですか?
- ・プリン+醤油=ウニみたいな組み合わせメニューを教えて!
- ・タイムマシーンがあったら、過去と未来どちらに行く?
- ・遅刻の「言い訳」選手権
- ・好きな和訳タイトルを教えてください
- ・うちのカレーにはこれが入ってる!って食材ありますか?
- ・おすすめのモーニング・朝食メニューを教えて!
- ・「覚え間違い」を教えてください!
- ・とっておきの手土産を教えて
- ・「平成」を感じるもの
- ・秘密基地、どこに作った?
- ・【お題】NEW演歌
- ・カンパ〜イ!←最初の1杯目、なに頼む?
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
アルファベットをカウント、
-
nullと""、\\0とEOFの違いにつ...
-
C#でstringをポインタとして渡す
-
文字コードによる表記
-
binaryに対して正規表現を適用...
-
%dなどの違い
-
シリアル通信で0x00を送信した...
-
c言語によって文字列を逆順する...
-
C++で入力した文字列から数字を...
-
16進数を2文字ずつ配列に格納し...
-
VB6.0でのバイナリデータの扱い...
-
プログラムによく出てくるst...
-
_tcscpy_s(wcscpy_s)の第二引数...
-
WSH(VBS)でJSONの文字列を読み...
-
数字の入った配列をファイルへ...
-
TCL言語で文字列検索方法を教え...
-
C言語 配列の長さの上限
-
CStringからchar*への型変換に...
-
Integer変数をカラにしたいので...
-
セグメントエラー
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
プログラムによく出てくるst...
-
nullと""、\\0とEOFの違いにつ...
-
C++で入力した文字列から数字を...
-
WSH(VBS)でJSONの文字列を読み...
-
C#でstringをポインタとして渡す
-
TCL言語で文字列検索方法を教え...
-
%dなどの違い
-
VB6.0でのバイナリデータの扱い...
-
16進数を2文字ずつ配列に格納し...
-
[C++]WCHARの1文字目しか表示で...
-
char型配列の最大要素数
-
_tcscpy_s(wcscpy_s)の第二引数...
-
シリアル通信で0x00を送信した...
-
Shift_JIS(16進)を文字に変換す...
-
sprintf関数について教えて下さ...
-
バイナリファイル中の日本語文...
-
構造体→文字列→構造体 をする方法
-
引用符と二重引用符
-
C言語の勉強しています。すみま...
-
文字列にある特定文字の数
おすすめ情報