sprintf関数について教えて下さい。

このQ&Aのポイント
  • sprintf関数を使用すると、任意の書式で文字列を作成することができます。
  • 上記のプログラムでは、sprintf関数を使用して配列nsに文字列を格納しています。
  • 書式指定を変更すると、出力結果が異なることがあります。具体的には、No.02からNo.20までの範囲で変化があります。
回答を見る
  • ベストアンサー

sprintf関数について教えて下さい。

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関数の説明も読んで納得はしたのですが 上のようになることがわかりません。 長々と書いてしまいましたが よろしくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • rinkun
  • ベストアンサー率44% (706/1571)
回答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'までを一つの文字列とみなして表示します。 その結果が質問で書かれた表示です。

kerberosMA
質問者

お礼

納得しました。 有難う御座いました。

その他の回答 (2)

  • sho1get
  • ベストアンサー率57% (20/35)
回答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; } /////////////////////////////////////////////////////////

kerberosMA
質問者

お礼

有難う御座いました。

回答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]); とすると同じ結果になるでしょう。

kerberosMA
質問者

お礼

有難うございました。 最初の2次元配列の定義部分を見落としていました。

kerberosMA
質問者

補足

すいません、訂正します。 プログラム中の2番目のfor文ですが (誤)for (i = 0; i < 2; i++) (正)for (i = 0; i < 20; i++) です。

関連するQ&A

  • 配列の動的確保を関数化

    main()内でいくつかの配列を動的確保するとごちゃごちゃするので、 関数化してみました。しかし、下のプログラムではうまい事いきませ んでした。 #include<stdio.h> #include<stdlib.h> void array1d(int *box,int n) { int i; box=(int *)malloc(n * sizeof(int)); for(i=0; i<n; i++) { box[i]=0; } } main() { int *pol,i,n; printf("N pol\nN = "); scanf("%d",&n); array1d(pol,n); for(i=0; i<n; i++) { printf("[%d]=%d\n",i,pol[i]); } } 実行結果は [0]=-14646387 [1]=-1819410433 [2]=-224 array1d内では0を格納していますが、このようになりました。 どのようにすれば 0になるでしょうか? 回答よろしくお願いします。

  • 行列の積を関数を使って求める・・?

    2つの行列の行と列を入力し、積を計算するプログラムを関数を使って書きたいのですが、上手く行きません。どこをどのように直したらよいか教えてください!お願いします!! 以下が私が書いたプログラムです。 #include<stdio.h> #define NUMBER 10 int first(int x1,int x2,int y1,int y2,int i,int j,int k) { int a[NUMBER][NUMBER] = {0}; int b[NUMBER][NUMBER] = {0}; int c[NUMBER][NUMBER] = {0}; do{ printf("2つの行列の行と列を入力してください\n"); scanf("%d", &x1); scanf("%d", &x2); scanf("%d", &y1); scanf("%d", &y2); if(x1 != y2){ printf("行列の積は計算できません\n"); } }while(x1 != y2); printf("行列Aの要素を入力してください\n"); for(i=0; i<x1; i++){ for(j=0; j<x2; j++) scanf("%d", &a[i][j]); } printf("行列Bの要素を入力してください\n"); for(j=0; j<y1; j++){ for(k=0; k<y2; k++) scanf("%d", &b[j][k]); } } int second(int x1,int x2,int y1,int y2,int i,int j,int k) { int a[NUMBER][NUMBER] = {0}; int b[NUMBER][NUMBER] = {0}; int c[NUMBER][NUMBER] = {0}; for(i=0; i<x1; i++){ for(k=0; k<y2; k++){ for(j=0; j<x2; j++) c[i][k] = c[i][k] + a[i][j]*b[j][k]; } } for(i=0; i<x2; i++){ for(k=0; k<y2; k++) printf("%3d", c[i][k]); printf("\n"); } } int main(void) { int a[NUMBER][NUMBER] = {0}; int b[NUMBER][NUMBER] = {0}; int c[NUMBER][NUMBER] = {0}; printf("行列の積を計算します\n %d\n", first(x1,x2,y1,y2,i,j,k)); printf("行列Aと行Bの積は\n %3d",second(x1,x2,y1,y2,i,j,k)); }

  • for文

    #include <stdio.h> int main(void) { int i; int sum=0; int num, tmp; printf("整数は何個かな:"); scanf("%d",&num); for(i=0; i<num; i++){ printf("No.%d:",i+1); scanf("%d",&tmp); sum+=tmp; } printf("合計値は:%d\n",sum); printf("平均値は:%.2f\n", (double)sum/num); return(0); } 上の文のforの箇所を for(i=1; i<=num; i++){ printf("No.%d:",i); scanf("%d",&tmp); sum+=tmp;   } としても結果的に同じですよね? どっちでもいいかどうか迷ってます。教えて下さい。

  • 関数について

    C言語の勉強をしているのですが、関数のところがよく理解できません。 ------------------------------ #include <stdio.h> int beki(int a, int b); int main(void) { int n; n=beki(2,3); printf("%d\n",n); printf("%d\n",beki(3,4)); } int beki(int a, int b) { int i,ans; ans=1; for(i=1; i<=b; i++) { ans=ans*a; } return ans; } ---------------------------- 実行結果 8 81 ----------------------------- 上のサンプルで int i,ans; ans=1; for(i=1; i<=b; i++) { ans=ans*a; } の部分は、解説書には「渡されたデータa,bを使って戻り値ansを計算 している」「aのb乗を計算している」などとありましたが、なぜaのb乗を計算しているのでしょうか?実行結果が8と81の何に関係しているのでしょう? ansやa,bの値を求めたら、何の値になるのでしょうか? これらについて、解説をお願いいたします。

  • 次のプログラムが作れません…

    キーボードから与えられた整数iに対して、iの階乗(i!)を求める関数"fact"を作成するというものなのですが… メイン関数は次のように与えられています。 #include<stdio.h> int fact(int); int main(void){ int in, i; printf("Input a number:"); scanf("%d",&in); for (i=1; i<=in; i++){ printf(" %d %d\n",i , fact(i) ); } return 0; } よろしくお願いします。

  • 書式制御'%d'と'%f'について

    以下のようなソースがあります。 実行すると、異常な、という処理において、 printf関数で、int型を'%f'で、処理すると 0.000000になります。 また、double型を'%d'で、処理すると 0になります。 これは何故、0になるのでしょうか。 説明できるかた、よろしくお願いいたします。 include <stdio.h> void main(){  int i;  double d;  i=100;  d=1.0;  printf("i=%d\n",i); /* 正常なprintf関数 */  printf("d=%f\n",d); /* 正常なprintf関数 */  printf("i=%f\n",i); /* 異常なprintf関数 */  printf("d=%d\n",d); /* 異常なprintf関数 */  return; }

  • C言語 エラー表示 break の位置が誤っている(関数 main ) 

    #include<stdio.h> int main(void){ int n,i,j,k; char c='*'; printf("正の整数:"); scanf("%d",&n); if(n>0){ for(i=1;i<=n;i++){ printf("%d",i); for(j=1;j<=n+1-i;j++){ if(j==1){ if(i-1>0){ for(k=i-1;k>0;k--){ printf(" "); } } } printf("%c",c); } printf("\n"); } } break; return 0; } これをコンパイルすると「break の位置が誤っている(関数 main )」と表示されるのですが何でですか? 困ってます↓

  • 素数 再帰関数

    メイン #include<stdio.h> extern void count_primes(void); extern void print_primes(void); int max; int count; int primes[1000] int main(void) { printf("Uper limit: "); scanf("%d",&max); count_primes(); print_primes(); } 素数を求める(関数呼び出し) extern int nextprime(int n); extern int max; extern int count; extern int primes[]; void count_primes(void) { int i; count=0; for(i=2;i<=max;i=nextprime(i)){ primes[count++]=i; } リカーバシブ(次の素数) int nextprime[int n] { int i; for(;;){ n++; for(i=2;i*i<=n;i=nextprime(i)){ if(n%i==0) break; } if(i*i>n) break; } return n; } 素数プリント #include<stdio.h> extern int count; extern int primes[]; void print_primes(void) { int i for(i=0;i<count;i++){ if((i>0)&&(i%10==0) printf("\n"); printf(" %6d",primes[i]); } printf("\n素数の数 %d\n",count); } これら4つのモジュールで素数 nが求められますがアルゴリズム理解できません。この2つの関数のアルゴリズムについて、ご教授ください。め

  • 2次元配列を引数とする関数について

    2次元配列を引数とする関数について 私は今、2次元配列を引数とする関数の表を作るという課題に取り組んでいます。 条件として、int a[数字][数字]={{1,2,3...}}という配列の宣言と同時の初期化は使わず、 関数内で表の値を代入し、値を表示する関数を作り、事実上二つの関数を作るというものです。 私は以下のようなプログラムを作り、動かしましたが、[数字][数字]=********のような本来 あるべき実行結果とは異なる数字の羅列が出てきてしまいました。 ↓ #include <stdio.h> void func(int a[][6]); void fund(int b[4][6]); void main(void) { int a[4][6]; fund(a); func(a); } void func(int a[][6]) { int i,j,b[4][6]; fund(b); for(i=0;i<4;i++)        { for(j=0;j<6;j++) { printf("a[%d][%d]=%d\n",i,j,a[i][j]); printf("\n"); } } } void fund(int b[4][6]) { int i,j; for(i=0;i<4;i++) { for(j=0;j<6;j++)          { scanf("b[%d]*[%d]=%d\n",&i,j,b[i][j]); } } } 本来の実行結果 1 2 3 4 5 6 2 4 6 8 10 12 3 6 9 12 15 18 4 8 12 16 20 24 紙にも書いて何回も見直しましたが、どこがおかしいのかわかりませんでした。 どうすれば良いのでしょうか? 何か良いアドバイスをよろしくお願いします。

  • C言語  九九表

    九九表を作ろうとしたのですが、うまくいきません、解説お願いします。 #include<stdio.h> main() { int i ; int j ; for( i=1 ; i<=10 ; i++){ for( j = 1 ; j<=10 ; j++) { printf("%4d\n") , i*j ; } printf("\n") ; } } 結果 10 -748408832 -748408832 -748408832 -748408832 -748408832 -748408832 -748408832 -748408832 -748408832     が10個続いてました・・・・

専門家に質問してみよう