dポイントプレゼントキャンペーン実施中!

現在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;
}

A 回答 (2件)

2つ間違いがあります。



fscanf(file,"%s %s %s ", &name[1], &name[2], &name[3]);
これは明らかな fscanfの使い方の間違いで、文字列へののポインタが格納されているはずの所に、文字列そのものを書き込んでしまいます。&を取ればとりあえず、環境によっていは動くこともあるでしょう。

しかし、これでも、文字列リテラルに直接書き込んでいるという間違いが依然としてあります。ご質問のプログラムのように最初と同じ文字列を書き込むのではなく"に"のところに"いち"を書く込むと領域を越えてしまいます。また、処理系によっては同じ大きさの文字列を書き込んでも、書き込み禁止の場所に場所に書き込んだ、というエラーが発生し、落ちます。ポインタではなく文字列の二次元配列で、char name[10][256]とか十分な大きさの文字列をとっておくか、ポインタを使うなら、読み込んだ時に malloc で文字列を入れる領域を確保してやるのがいいでしょう。
    • good
    • 0
この回答へのお礼

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

お礼日時:2006/05/06 13:45

この問題の場合ポインタの配列を使うより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;
}
    • good
    • 0
この回答へのお礼

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

お礼日時:2006/05/06 13:46

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!