みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

構造体のプログラミング...練習です。

構造体のプログラミング...練習です。

#include <stdio.h>

int main ( void )
{

int i;

struct rool{
char name[20];
float height;
char bloodType;
}date[128];

for(i = 0;; i++)
{
printf("%d人目のデータ:", i + 1 );

scanf("%s %f %c",date[i].name[i], &date[i].height, &date[i].bloodType);

if((date[i].name[0] == '0') && (date[i].height == 0) && (date[i].bloodT\
ype == 0))
{
break;
}
}

printf("名前    体重     歳\n");

for(i = 0; (date[i].name[0] == '0') && (date[i].height == 0) && (date[i].bl\
oodType == 0); i++)
{
printf("%s, %10s, %10s\n",date[i].name[i], date[i].height, date[i].bloodTy\
pe);
}

return 0;

}


構造体を使ったプログラミングです。
名前と体重、歳を入力して0 0 0が入力されたら、今まで入力したものを表示する。というものです。
セグメントエラーが出て困っています。
入力をしてエンターキーを押すと、何人目のデータ:何人目のデータ:~と言うふうにでて、セグメントエラーで止まります。

よろしくお願いします。

投稿日時 - 2010-09-15 02:41:40

QNo.6183477

困ってます

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

http://ja.wikipedia.org/wiki/Scanf

scanfは、いろいろと面倒なことの多い関数です。
おそらく
scanf失敗:ファイルポインタはそのまま
→終了チェックにはひっからない
初期化していない構造体の中身は不定で、なにが入っているかわからない。
全部0で初期化されていたとしても、0と'0'とは違う。
→ i++してループ続行
→さっきエラーになったところか読み出し
→ずれていたり、最初から変化してなかったりで正確に読めない
→終了チェックにはひっからない
→ i++してループ続行
....
→ i >= 128 になる
→ 宣言より data[128]以上は保証されない
→セグメントエラー

という流れだと思われます。
・fgets等で1行読み込む→sscanfや別の方法で解析する
・scanfのエラーチェックと、エラーの際の復帰処理をきちんと行う
といった対策が必要です。

あと気付いたことは

> 名前と体重、歳を入力
とあるのに、構造体のメンバは
> float height;
> char bloodType;
と、身長と血液型を連想させるものになっている。
文法的にはあっているけど、作法としては問題。

また、歳を扱うのなら、charの範囲(普通は-128~127)を越えることはほぼ無いけれど、intを使うのが自然。

> scanf("%s %f %c",date[i].name[i], &date[i].height, &date[i].bloodType);
%sと%fの間に「全角スペース」が入っていますが、これは、ここへの打ち込み間違いでしょうか?

もし、プログラムをコピペしたものだとしたら、入力時には、名前と体重との間に「全角スペース」が無いとこのscanfは成功しません。
名前を読み込んだところで、読み込みポインタは体重の前で止ってしまい、次回のscanfはそこからに
→名前は空文字列、体重の前に「全角スペース」がないのでエラー、読み込みポインタは体重の前
→名前は空文字列、体重の前に「全角スペース」がないのでエラー、読み込みポインタは体重の前
....
と無限ループになります。

また、%cは文字を読み込むものです。
歳に25を入れたとして、%cで読み込まれるのは '2' だけであって、 通常は '2' != 2 です。
'5'はバッファにそのまま残り、次の入力はここからになります。
整数を読み込むなら 変換文字は d です。

> if((date[i].name[0] == '0')
これだと、 0taro氏も条件に合致します。

> (date[i].bloodType == 0))
現在のままだと、 歳に0を入れた場合は、 bloodType = '0' であって 0ではありません。

> printf("%s, %10s, %10s\n",date[i].name[i], date[i].height, date[i].bloodType)

2番目は %sに対して height、つまりfloatを指定しています。
floatをムリヤリchar *だと思いこんで、まったく意味のないアドレスから文字列として出力しようとします。

3番目は %sに対して bloodType、つまりcharを指定しています。
charをムリヤリchar *だと思いこんで、まったく意味のないアドレスから文字列として出力しようとします。
charは1文字を表現できる数値であって、文字列ではありません。

投稿日時 - 2010-09-15 10:04:31

お礼

大変細かい説明を、ありがとうございました。
一応やみなおしてみたら、思う通りに動くことができました。
とっても助かりました!

投稿日時 - 2010-09-17 17:34:01

ANo.3

このQ&Aは役に立ちましたか?

3人が「このQ&Aが役に立った」と投票しています

回答(4)

ANo.4

エラーになるのは

scanf("%s %f %c",date[i].name[i], &date[i].height, &date[i].bloodType);

の引数date[i].name[i]が
date[i].name または &date[i].name[0]
になっていないからです。

あとの変なところは他の回答者の指摘どうりです。

投稿日時 - 2010-09-15 11:30:15

ANo.2

>scanf("%s %f %c",date[i].name[i],

i は「何人目のデータか」を表わす変数ですよね。
name[i] の i は、どういう意味ですか?

>for(i = 0; (date[i].name[0] == '0') && (date[i].height == 0) && (date[i].bl\
oodType == 0); i++)

入力がうまくいったとしても、これだと何も出力しないのではありませんか?
for文の継続条件を見直す必要があると思います。

投稿日時 - 2010-09-15 08:16:56

ANo.1

データを手入力するときにscanf()をループで複数回呼ぶとうまくいかないようですね。
fgets()で1行ごと入力してからsscanf()を使うのがいいと思います。
(それと、載せられたプログラムは表示部のforループの継続条件の論理が逆ですよ。)

簡略化したサンプルプログラムを作ってみました。
これは整数を1行に1個ずつ入力して配列に格納し、0が入力されたら入力を終わって、
配列の中身を表示する、というものです。参考にしてください。

#define LINE_SIZE 1024

#include <stdio.h>

int main(void)
{
char line[LINE_SIZE + 1];
int numbers[256];
int count;
int i;

count = 0;
for (;;) {
int r;
int n;

if (fgets(line, LINE_SIZE, stdin) == NULL) {
break;
}
line[LINE_SIZE] = '\0';

r = sscanf(line, "%d", &n);
if (r != 1) {
break;
}
if (n == 0) {
break;
}
numbers[count] = n;

count++;
}

for (i=0; i<count; i++) {
printf("%d: %d\n", i, numbers[i]);
}

return 0;
}

投稿日時 - 2010-09-15 03:20:00

あなたにオススメの質問