• ベストアンサー

malloc関数について質問です。

整数を入力してその分だけ動的にメモリを確保し、その後文字列を入力して確保した領域に格納し、表示するプログラムなんですが、 int main(void) { int n; char *p; puts("整数を入力"); scanf("%d", &n); p = malloc(sizeof(char) *(n+1)); puts("文字を入力");   scanf("%s", p); printf("文字列は%s\n", p); free(p); return 0; } としたら、ちゃんとプログラムは動くんですが、 問題の意図にあっているんでしょうか?

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

  • ベストアンサー
  • mitoneko
  • ベストアンサー率58% (469/798)
回答No.2

 mallocの使い方の例文としてはあっていると思います。  でも、実用のプログラムとしては不合格です。  この差は、基本的なエラー処理ができているかどうかです。  まず、mallocの呼び出しですが、意図通りの領域が確保できている限りは、そのままでちゃんと動きます。  でも、何らかの事情で領域が確保できなかったとき(たとえば、入力した数値が巨大だったとか、OSと環境の都合でメモリー領域に空きがなかったとか・・・まぁ様々な理由でmallocは失敗します。)、この関数はnullを返します。  あなたのプログラムのままですと、このとき、pにnullが入りますから、scanf(%s,p)のところで、nullアドレスへの書き込みが発生しますから、運がよければランタイムエラーで落ちます。運が悪ければ何が起こっても文句はつけられませんという状況になります。  mallocの次の行に、  if (p == null) {    /* エラーの表示とプログラムの終了 */ }  を必ず入れるようにしましょう。  次に、scanf("%s", p); のところですが、これはちょっと問題があります。  このプログラムを使った人が、問題文に合わせて、最初に入力した数字以下の文字数の文字を入力してくれている間は問題ありません。でも、ソフトを作るときには、「使う人は、自分の思う以外の入力をするかもしれない」と考えて作るのが基本です。「人が入力した値は決して信用してはいけない」とも言います。  もし、入力した整数より大きな文字列を入力したらどうなるでしょう。もちろん、pの領域をはみ出して文字列が格納されますから、その結果は未定義です。(これをバッファオーバーフローと言います。この手のエラーがあると、これを利用して、システムを乗っ取ろうとする輩が多数発生します(笑))  これを解決するのは、実は、少々骨です。この類の文字列の入力には、基本的に、scanfの使用は向いていないと言うのが実は結論です。たとえば、getcで一文字ずつ文字を受け入れ、バッファの大きさになるか、リターンキーが入力されるまでループするとかいうのが基本かなと思います。  ほかにもたとえば、  ・負の整数を入力されたらどうなるでしょう?  ・整数が0だったら?  ・整数と指定しているのに、「abc」と入力する人が出れば?  などが考えられます。  この解消策は、自分で一度考えてみてください。  

その他の回答 (4)

回答No.5

こんな感じ? #include <stdio.h> #include <stdlib.h> /* malloc free */ int main(void) {  int i,n,ch;  char *s;    /* メモリ確保 */  puts("確保する文字数");  scanf("%d%*[^\n]%*c",&n); /* 数字のあと改行まで読み飛ばして改行を捨てる */  if (n<1) {   puts("out of range");  return -1;  }  if ((s=malloc(n+1))==NULL) { /* 終端文字の分までメモリ確保 */   puts("malloc error");  return -1;  }  /* 文字入力して表示 */  puts("文字を入力してください");  for (i=0; i<n; i++) { /* 確保した分まで読み込む */   ch=getchar();   if (ch==EOF || ch=='\n') break; /* エラーか改行なら終わり */   s[i]=ch;  }  s[i]='\0'; /* 文字の最後 */  printf("[%s]",s);  /* メモリ開放 */  free(s);  return 0; }

  • TT414
  • ベストアンサー率18% (72/384)
回答No.4

>整数を入力してその分だけ動的にメモリを確保し、 とあるので、 >malloc(sizeof(char) *(n+1)); はまずいのではないでしょうか? その分だけとあるのにn+1としています。一個余分に確保しています。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

エラーチェックはともかく、scanf("%s", p);とすると空白類文字の入力ができなくなります。

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.1

必要なヘッダーファイルをインクルードしてくださいね。 nの値と、入力文字列の長さとの組み合わせによっては、 正しく動くこともあったり(この場合は問題の意図に合っているといえるでしょう)、 たまたま動いているように見えてどこかの領域を壊していることもあったり、 はたまたプログラムが落ちてしまうことがあったりするかもしれません。

関連するQ&A

  • malloc関数について。

    typedef struct a{ char *simei; int nenrei; }MEIBO; void main(void) { MEIBO a[5]; int wa; for(i = 0; i <= 4; i++ ) { a[i].simei = malloc(100 * sizeof(char) ); if( a[i].simei == NULL ) /* 領域確保に失敗したか */ { printf( "%dバイトの領域確保に失敗", 100 * sizeof(char) ); return 1; } printf("%d番目を入力してください\n",i+1); scanf("%s",&a[i].simei); printf("%s\n",a[i].simei); } C言語初心者です。これで入力したa[i].simeiが表示されないのですが、間違いを指摘していただけますでしょうか。宜しくお願いします。

  • mallocについて

    vine linux 3.0上でgccを使い下記のようなプログラム(読みにくいプログラムで申し訳ありません)を作成してみました。無事コンパイルも通りメモリも確保出来ました。 しかし、このプログラムを2つ起動しそれぞれでメモリを確保するとおかしな事が起きるのです。どういう症状かと言うとプログラム1もプログラム2も同じ先頭アドレスを確保しているのです。 例) プログラム1 keep memory size : 11 address : 0x8049700 プログラム2 keep memory size : 11 address : 0x8049700 なぜこのような事が起こるのでしょうか? ご教授宜しくお願いします。 #include <stdio.h> #include <stdlib.h> main(int argc, char *argv[]) { int size; unsigned int *p; char buf; size = atoi(argv[1]); printf("keep memory size : %d\n", size); p = (unsigned int *)malloc(size); printf("address : %p\n", p); scanf("%c", &buf); free(p); }

  • 関数の作り方

    文字列s1に文字列s2が含まれるか判定する関数search を作りたいのですが、コンパイルできません。 どこに問題がありますか?? #include<stdio.h> #include<string.h> int seach(char *s1,char *s2) { char *p; p = strstr(s1,s2); if(p == NULL){ return 0; }else{ return 1; } } main(void){ char s1[255]; char s2[255]; int res; printf("文字列s1を入力:"); scanf("%s",s1); printf("文字列s2を入力:"); scanf("%s",s2); res = search(s1,s2); if(res == 1){ printf("文字列s1に文字列s2が含まれます\n"); } if(res == 0){ printf("文字列s1に文字列f2は含まれません\n"); } return 0; }

  • mallocがうまく動かない

    コマンドライン引数で指定された文字列を逆順に返すプログラムを作るため 下記のようなプログラムを組みました。 ところが変数strの大きさがargv[1]より大きくなってしまいます。 どうすればよいのでしょうか。 #include <stdio.h> #include <stdlib.h> char *mstrrev (char *s); int main(int argc, char *argv[]){ char *str; str = mstrrev(*(argv+1)); printf("%s",str); free(str); } char *mstrrev (char *s){ int length,i; char *str; for(length=0;*(s+length)!='\0';length++); str = (char *)malloc(sizeof(char)*length); for(i=0;i<length;i++){ str[i] = s[length-1-i]; } return str; }

  • VC++ 再帰関数

    ■キーボードより読み込んだ文字列の長さを求めるプログラムを再帰関数を使って作る #include <stdlib.h> int unk_r(char*p)   {    if(*p == 0x00)    return(0);   else    return(1+unk_r(p+1));   } int main()   {    char *i;    i = (char *)malloc(20);    scanf("%s",i);    printf("%d\n",unk_r(i));   } このプログラムについて、行、単語ひとつひとつ細かいところまで具体的に解説お願いします。どういう働きをしているのか等。 例えば #include <stdlib.h> はmallocを使うのに必要などなど。 よろしくお願いします。

  • プロンプト入力 malloc( )

    #include <iostream.h> void f(char* str); main(){ char s[8] = "\0"; cout << "文字を入力" << '\n'; fgets(s, 8, stdin); f(s); } void f(char* str){ char* c; c = (char*)malloc(sizeof(char) * strlen(str)+1); cout << strlen(str) << '\n'; cout << sizeof(c); free(c); } - 結果 - 文字を入力 ( a、Ctrl+Z ) a 1 4 でした。 cout << sizeof(c); の結果は4でした。1バイトの入力だから\0を含めて 2バイトを確保したかった。 そのためにはどうしたらいいんですか? どうして4だったんですか? 文字を入力するとこで、Ctrl+Z の代わりに Enter を押すと Enter まで s に格納されてしまう。 cin を使うと8バイト以上の入力でも s に格納されてしまう。 そうならないためのよい方法があったら教えてください。

  • mallocで引数に変数を入れると警告がでます

    #include<stdio.h> int main(void){ int n,i; int* array; puts("n=?"); scanf("%d",&n); array = (int*)malloc(sizeof(int) * n); for(i=0;i<n;i++) *(array+i) = i; for(i=0;i<n;i++) printf("%d ",*(array+i)); puts(""); return 0; } C言語で、上述のプログラムをコンパイルしたところ、 9: warning: incompatible implicit declaration of built-in function ‘malloc’ と警告がでます。 ./a.outで普通に実行できるのですが、 警告がでるということは、もっと正しいやり方があるということでしょうか?

  • Cの文字列関連の質問です。よろしくお願いします。

    Cの文字列関連の質問です。よろしくお願いします。 『読み込んだ文字列がナル文字を含めて15文字以下であれば、その文字列をそのまま格納し、そうでない場合、読み込んだ文字列の先頭14文字とナル文字を格納する』 という条件を満たすプログラムを作成しました。 #include <stdlib.h> #include <string.h> #include <stdio.h> int main(void) { int num; char (*p)[15]; printf("文字列の個数: "); scanf("%d", &num); p = (char (*)[15])malloc(num * 15); if (p == NULL) puts("記憶域の確保に失敗"); else { int i; char tmp[100]; /* 書込み */ for (i = 0; i < num; i++) { printf("p[%d]: ", i); scanf("%s", tmp); sprintf(p[i], "%.14s", tmp); } /* 表示 */ for (i = 0; i < num; i++) printf("p[%d]: %s\n", i, p[i]); free(p); } return 0; } この場合は、ちゃんと条件を満たした結果が出ました。 ここで24行目の『sprintf(p[i], "%.14s", tmp);』を『strncpy(p[i], tmp, 14);』に変更する明らかに結果がおかしくなります。 strncpyを使った方法に変更する場合、どのように修正を行えばいいのでしょうか? 長々と書いてしまいましたが、よろしくお願い致します。

  • セグメンテーション違反とmalloc

    char *name この宣言でプログラムの組初めはこれでいけたのですが char *name = (char *)malloc(sizeof(char) * 10); 後からこのようにmallocで動的メモリ確保しないとセグメンテーション違反が起きるようになりました。 なぜこうなるのでしょうか? それとmallocの使うタイミング(どういう時)に使えばよいのでしょうか?

  • C言語の初歩的な質問

    質問1----------------------------------------- #include<stdio.h> int main() {  int a;  char b[10];  for(int i = 0;i < 2;i++){   scanf("%d",&a);   printf("整数%d\n",a);  }  scanf("%s",b);  printf("文字列%s\n",b); } /* この際に、例えばabと入力すると結果が 整数-858993460 整数-858993460 文字列ab となり整数入力を無視して進められるのはなぜでしょうか? */ 質問2----------------------------------------- #include<stdio.h> void func(int**); int main() {  int *p;  func(&p);  printf("%d",*p); } void func(int **pp) {  int n = 10;  *pp = &n; } /* func関数のnはスコープからはずれて変数の寿命がなくなるはずなのにprintfで表示されるのはなぜでしょうか? */ ---------------------------------------------- C言語は一冊の本とネットの入門サイトをかじった程度の理解です。

専門家に質問してみよう