• ベストアンサー

ポインタ配列をfscanfで読み込むと・・・

現在BorlandのC言語で人の名前をセーブする処理を 作っています。そこで以下の様に書いたのですが、 コンパイラでは通るのに、実行してセーブをして ロードをすると必ず強制終了させられてしまいます。 これは一体何がいけなかったのでしょうか? また、どのように書いたらキチンと動作するのでしょう? #include <stdio.h> char *name[10]; void save(void){ FILE *file; file = fopen("name.txt", "w+"); fprintf(file,"%s %s %s ", name[1], name[2], name[3]); fclose(file); } void load(void){ FILE *file; file = fopen("name.txt", "r+"); fscanf(file,"%s %s %s ", &name[1], &name[2], &name[3]); fclose(file); } int main( void ){ name[1] = "いち"; name[2] = "に"; name[3] = "さん"; while ( 1 ){ int i; printf("name[1]:%s name[2]:%s name[3]:%s \n", name[1], name[2], name[3]); puts("1:セーブ 2:ロード"); scanf("%d",&i); if ( i == 1 ) save(); else load(); } return 0; }

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

  • ベストアンサー
  • moritan2
  • ベストアンサー率25% (168/670)
回答No.1

2つ間違いがあります。 fscanf(file,"%s %s %s ", &name[1], &name[2], &name[3]); これは明らかな fscanfの使い方の間違いで、文字列へののポインタが格納されているはずの所に、文字列そのものを書き込んでしまいます。&を取ればとりあえず、環境によっていは動くこともあるでしょう。 しかし、これでも、文字列リテラルに直接書き込んでいるという間違いが依然としてあります。ご質問のプログラムのように最初と同じ文字列を書き込むのではなく"に"のところに"いち"を書く込むと領域を越えてしまいます。また、処理系によっては同じ大きさの文字列を書き込んでも、書き込み禁止の場所に場所に書き込んだ、というエラーが発生し、落ちます。ポインタではなく文字列の二次元配列で、char name[10][256]とか十分な大きさの文字列をとっておくか、ポインタを使うなら、読み込んだ時に malloc で文字列を入れる領域を確保してやるのがいいでしょう。

amazontester
質問者

お礼

なるほど!そういうことだったのですか。 さすがにポインタを完全には理解できませんでしたが、 この話のお陰でかなり理解できました。 mallocを試しに使ってみて&をはずしたところ見事に 動作しました。ありがとうございました!

その他の回答 (1)

  • mac_res
  • ベストアンサー率36% (568/1571)
回答No.2

この問題の場合ポインタの配列を使うよりcharの2次元配列を使ったほうが適しているように思います。 -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> char name[4][80]; void save(void) { FILE *file; if ((file = fopen("name.txt", "w+")) == NULL) { perror("name.txt"); exit(errno); } fprintf(file, "%s %s %s ", name[1], name[2], name[3]); fclose(file); } void load(void) { FILE *file; if ((file = fopen("name.txt", "r+")) == NULL) { perror("name.txt"); exit(errno); } fscanf(file, "%s %s %s ", name[1], name[2], name[3]); fclose(file); } int main(void) { int i, j; char buf[BUFSIZ]; strcpy(name[1], "いち"); strcpy(name[2], "に"); strcpy(name[3], "さん"); while (1) { printf("name[1]:%s name[2]:%s name[3]:%s \n", name[1], name[2], name[3]); printf("1:セーブ 2:ロード 3:インプット >> "); fgets(buf, BUFSIZ, stdin); i = atoi(buf); switch (i) { case 1: save(); break; case 2: load(); break; case 3: for (j = 1; j < 4; j++) { printf("name[%d] => ", j); fgets(buf, BUFSIZ, stdin); buf[strlen(buf) - 1] = 0; strcpy(name[j], buf); } break; } } return 0; }

amazontester
質問者

お礼

具体的なソースをありがとうございます。 そういえば二次元配列で実現する方法もありますね・・。 ただ今回の場合どうしてもポインタでやる必要が あったので・・・でもとても参考になりました。 ありがとうございます。

関連するQ&A

専門家に質問してみよう