• ベストアンサー

このプログラムどこがおかしいですか?

コンパイルはできますが実行できません… どこがおかしいか分かる人教えてください。 このプログラムはファイルから名前 数学の点数、英語の点数を読み込んで文字データに入れた後構造体に入れて探し出す値の項目(キー)を入力して(何番目にあるか)探し出すというプログラムです。 #include <stdio.h> #include <string.h> #define NUMBER 10 //構造体を宣言する struct student { //名前、身長、体重を構造体オブジェクトのメンバに格納する関数の定義 char name[10]; char math[4]; char eng[4]; }; /*--- 要素数nの配列aからkeyと一致する要素を線形探索(番兵法) ---*/ int search(struct student *b, int n, char key) { int i=0; b[i].name[0]=key; // 番兵を追加 while (1) { if (b[i].name[0] == key) break; /* 見つけた */ i++; } return (i == n ? -1 : i); } int main(void) { FILE *fpin; struct student a[NUMBER]; int i=0, idx,ret; char buffer[20],ky; int nx=sizeof(buffer) / sizeof(buffer[0]); fpin=fopen("input2.txt","r"); //テキストファイルを読み取りモードで開く while(fgets(&buffer[0],sizeof(buffer),fpin) !=NULL ) { if(i>=100) break;//読み込む人数が100人を超えてる時の処理 ret=sscanf(&buffer[0],"%s %s %s",&a[i].name,&a[i].math,&a[i].eng); //データ文字列を3分割 if(ret!=3) //3に分割できなかったときの処理 { puts("代入された入力項目の個数が3でありません"); goto END; } printf("%s %s %s\n",&a[i].name,&a[i].math,&a[i].eng); i++; } printf("探す値:"); scanf("%s", &ky); idx = search(a, nx - 1, ky); /* 配列xから値がkyである要素を線形探索 */ if (idx == -1) puts("探索に失敗しました。"); else printf("%dは%d番目にあります。\n", ky, idx + 1); END: fclose(fpin); return 0; }

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

  • ベストアンサー
  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.6

>オーバーランをなくすにはどうしたらいいですか? #define NUMBER 10 を #define NUMBER 100 にする。 または、 if(i>=100) break;//読み込む人数が100人を超えてる時の処理 を if(i>=NUMBER) break;//読み込む人数が100人を超えてる時の処理 にする。(この場合、コメントがウソついていますが) ちなみに、データいっぱいまで読み込んだ場合、 このアルゴリズムでは最終データが番兵により書き換えられてしまいます。 そういう意味では、#4さんの書かれているとおりサイズ渡しているので最終まで行ったら検索を中断するようにすればよいです。

hiro3932
質問者

お礼

ありがとうございます。 おかげで解決しました。

その他の回答 (6)

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.7

search() が名前の最初の 1文字でしか検索しないので、100人もの生徒を扱うのは無理だな。 あと、フラグはコーディングの瞬間は「わかりやすい」ですが、 次の瞬間には何のフラグだったのか忘れてしまうので、使わないに越したことはないと思います。 この場合で言えば、単純にキーを発見したら return で関数から抜ければいいだけでフラグは不要です。

  • tig33
  • ベストアンサー率50% (6/12)
回答No.5

バッファオーバーランになるのは、search()関数で、 検索するテーブルの大きさを考慮に入れていないからです。 指定されたものが見つからないときは、テーブルの最後まで 検索したら、検索を止めなくては行けませんね。 このテーブルの最後を検出するロジックが抜けているからです。 while(1) { } でループを作成すると、見つかったときは、ループを抜けますが、 見つからなかったときは、テーブルの範囲を超えて検索しようと します。(大抵は、永久ループ) したがって、for() 文を使った方が、簡明です。また、見つかったかどうかもフラグを用いた方が分かりやすいです。 int search( ... ) {   int found;   found = 0;   for(i=0; i < (テーブル個数); i++) {     if(一致条件) {       found = 1;     }   }  return( found ? i : -1 ); } と言う具合ですね。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.4

そもそも search() 関数には配列の要素数を渡しているんだから、番兵を立てる意味はないよね。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.3

連続書き込みすみません… 番兵でバッファオーバーランする前に… > if(i>=100) break;//読み込む人数が100人を超えてる時の処理 >ret=sscanf(&buffer[0],"%s %s %s",&a[i].name,&a[i].math,&a[i].eng); //データ文字列を3分割 でオーバーランの可能性ありでした。 10行以上のデータを読み込ませた場合に…。

hiro3932
質問者

補足

連続書き込みありがとうございます。 オーバーランをなくすにはどうしたらいいですか?

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.2

> 対して、searchに渡している最大値(おそらく第2引数)は > > char buffer[20] > > int nx=sizeof(buffer) / sizeof(buffer[0]); > で20です。 > 番兵の位置を修正すると、a[19]の位置に書き込まれます。 「20です」って書いて、「a[19]」と書くと紛らわしいですね… > idx = search(a, nx - 1, ky); /* 配列xから値がkyである要素を線形探索 */ で-1しているので、a[19]ということになります。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.1

まず、「実行できません」とはどういう状況になるのでしょうか? 補足願います。 で、 search()の戻り値は必ず0になるかと思われますが、 意図した動作ですか? 何故0になるのかは番兵が行列の先頭に居るから…ですが。 さらに、番兵の位置を修正したとしてもバッファオーバーランします。 > student a[NUMBER]; でNUMBERは10、a[0]~a[9]です。 対して、searchに渡している最大値(おそらく第2引数)は > char buffer[20] > int nx=sizeof(buffer) / sizeof(buffer[0]); で20です。 番兵の位置を修正すると、a[19]の位置に書き込まれます。

hiro3932
質問者

補足

すみません b[i].name[0]=key;でなく b[n].name[0]=key;でした。 実行できないのは強制終了になる状況です。 バッファオーバーランをなくすには NUMBERの値を大きくすればいいんですか?

関連するQ&A

  • ファイルを読み込むプログラム

    氏名、英語、数学が保存されているファイル(記入されている人数は不明とし100人まで読み込めるとする)を関数内で読み込んで個人の点数の平均値と、皆の数学の平均値、英語の平均値を関数内で定義して出力するプログラムを作りましたが、コンパイルはできても実行するとエラーが出ます。どこがおかしいか分かる人教えてください。 #include <stdio.h> #include<stdlib.h> #include<string.h> #define number 100 int n=0; //構造体を宣言する struct student {char Name[6]; double Math; double Eng; }; struct student *sset_student(char *buffer) { struct student *pss[number]; int ret; ret=sscanf(&buffer[0],"%s %lf %lf",&pss[0]->Name,&pss[0]->Math,&pss[0]->Eng); if(ret!=3) { puts("代入された入力項目の個数が3でありません"); return NULL; } return pss[0]; } struct student *fset_all_student(void) { int i; struct student *pss[number]; FILE *fpin; char buffer[20]; fpin=fopen("input.txt","r"); if(fpin==NULL) { fprintf(stderr, "入力するファイルが開きません"); return NULL; } while(fgets(&buffer[0],sizeof(buffer),fpin) !=NULL ) { pss[i]=sset_student(&buffer[0]); i++; } n=i; fclose(fpin); return pss[0]; } void get_student_average(struct student *pss) { double heikin; heikin=(pss->Math+pss->Eng)/2.0; printf("%sの平均点は%dです\n",pss->Name,heikin); } void get_average(struct student *pss) { int i; double msum=0; double esum=0; for(i=0;i<3;i++) { msum+=pss[i].Math; esum+=pss[i].Eng; } printf("数学の平均点は%dです\n",msum/n); printf("英語の平均点は%dです\n",esum/n); } int main(void) { int i; struct student *a[number]; for(i=0;i<n;i++) { a[i]=fset_all_student(); } for(i=0;i<n;i++) get_student_average(a[i]); get_average(a); return 0; }

  • プログラムについて

    今スタっクのファイルから読み込んだ文字列をスタっクへプっシュしたりポっプしたりする過程がわかるプログラムを作ってます 。 作りかけのプログラムですがどこをどうすればいいか教えてください!! 一応コンパイルできます。 使ってない関数があるかもしれません。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define NUMBER 100 /*--- スタックを実現する構造体 ---*/ typedef struct { int max; /* スタックのサイズ */ int ptr; /* スタックポインタ */ char *stk; /* スタック(の先頭要素へのポインタ) */ } Stack; /*--- スタックの初期化 ---*/ int StackAlloc(Stack *s, int max) { s->ptr = 0; if ((s->stk = calloc(max, sizeof(int))) == NULL) { s->max = 0; /* 配列の確保に失敗 */ return (-1); } s->max = max; return (0); } /*--- スタックの後始末 ---*/ void StackFree(Stack *s) { if (s->stk != NULL) { free(s->stk); s->max = s->ptr = 0; } } /*--- スタックにデータをプッシュ ---*/ int StackPush(Stack *s, int x, int i,char *a[]) { if (s->ptr >= s->max) return (-1); if(x>=i) { puts("プッシュできる文字データはありません。"); return (-1); } strcpy(&s->stk[s->ptr++],&(*a)[x]); x++; return x; } /*--- スタックからデータをポップ ---*/ int StackPop(Stack *s, int x,char *a[]) { if (s->ptr <= 0) /* スタックは空 */ return (-1); strcpy(&s->stk[--s->ptr],&(*a)[x]); return (0); } /*--- スタックからデータをピーク ---*/ int StackPeek(const Stack *s, int *x) { if (s->ptr <= 0) /* スタックは空 */ return (-1); *x = s->stk[s->ptr - 1]; return (0); } /*--- スタックの大きさ ---*/ int StackSize(const Stack *s) { return (s->max); } /*--- スタックに積まれているデータ数 ---*/ int StackNo(const Stack *s) { return (s->ptr); } /*--- スタックは空か ---*/ int StackIsEmpty(const Stack *s) { return (s->ptr <= 0); } /*--- スタックは満杯か ---*/ int StackIsFull(const Stack *s) { return (s->ptr >= s->max); } /*--- スタックを空にする ---*/ void StackClear(Stack *s) { s->ptr = 0; } int main(void) { int i=0,j,ret,x=0; char *a[NUMBER]; char buffer[20]; FILE *fpin; Stack s; fpin=fopen("input2.txt","r"); //テキストファイルを読み取りモードで開く while(fgets(&buffer[0],sizeof(buffer),fpin) !=NULL ) { if(i>=NUMBER)//読み込む人数がNUMBERを超えてる時の処理 { puts("人数が100人を超えています"); goto END; } strcpy(&a[i][0],&buffer[0]); /*ret=sscanf(&buffer[0],"%s",&a[i][0]); //データ文字列を3分割 if(ret!=1) //1に分割できなかったときの処理 { puts("代入された入力項目の個数が3でありません"); goto END; }*/ i++; } for(j=0; j<i; j++) printf("%s\n",&(*a)[j]); if (StackAlloc(&s, 100) == -1) { puts("スタックの確保に失敗しました。"); return (1); } while (1) { int m; printf("現在のデータ数:%d/%d\n", StackNo(&s), StackSize(&s)); printf("(1) プッシュ (2) ポップ (0) 終了:"); scanf("%d", &m); if (m == 0) break; switch (m) { case 1: printf("データ:"); puts("こんちくしょ~"); if(StackPush(&s, x,i,&(*a)) == -1) puts("スタックへのプッシュに失敗しました。"); break; case 2: if(StackPop(&s, x,&(*a)) == -1) puts("ポップできません。"); else printf("ポップしたデータは%sです。\n", &s.stk[s.ptr]); break; } } StackFree(&s); END: fclose(fpin); return (0); }

  • このプログラムの説明合っていますか?

    /* 線形探索(for文で実現)*/ #include <stdio.h> /*--- 要素数nの配列aからkeyと一致する要素を線形探索 ---*/ int search(const int a[], int n, int key)    { int i;            /*iを宣言*/ for (i = 0; i < n; i++)     /*iの値を設定し宣言*/ if (a[i] == key)       /*iにkeyで入力*/ return (i); /* 探索成功 */ return (-1); /* 探索失敗 */ } int main(void)          /*main関数*/ { int i, ky, idx;/*i,ky,idxを宣言*/ int x[7]; /*xは配列で7つの数字を入れられる*/ int nx = sizeof(x) / sizeof(x[0]);/*配列を宣言*/ printf("%d個の整数を入力してください。\n", nx); for (i = 0; i < nx; i++) { printf("x[%d]:", i); scanf("%d", &x[i]); }printf("探す値:"); scanf("%d", &ky); idx = search(x, nx, ky); /* 配列xから値がkyである要素を線形探索 */ if (idx == -1) puts("探索に失敗しました。"); else printf("%dは%d番目にあります。\n", ky, idx + 1); return (0);      /*0の数字で戻る*/ } 1行ずつ理解したいのですが分からない個所多いんです。 分からないの文は説明が書いてないので教えてください。

  • Cのプログラムがどうしても動きません

    Cを勉強中なのですが、以下のプログラムがうまくいきません。 (studentは構造体で定義した型です。) iが0でない5の倍数の時にreallocでメモリを増やそうと思ったのですが、 「21行目」(reallocの行)で記述エラーを発見しました。 「lvalue」を付け忘れています。 と表示されます。 どこが間違っているのでしょうか?教えてくださいm(_ _)m #include<stdio.h> typedef struct{ char name[20]; int year; char sex[6]; }student; void read_data(int,student*); void write_data(int,student*); int main(void){ student data[5]; int i=0,j=0; do{ read_data(i,data); i++; if(i%5==0 && i!=0){ data=realloc(data,(sizeof(student))*(i+5)); } }while(data[i-1].year!=-1); } for(j=0;j<i-1;j++){ write_data(j,data); } free(heap); return 0; } void read_data(int i,student *data){ printf("%d人目\n",i); printf("名前?\n",i); scanf("%s",(data[i].name)); printf("年齢?\n",i); scanf("%d",&(data[i].year)); printf("性別?\n",i); scanf("%s",(data[i].sex)); return; } void write_data(int j,student *data){ printf("%d人目\t",j+1); printf("名前:%s\n",data[j].name); printf("年:%d\n",data[j].year); printf("性:%s\n",data[j].sex); return; }

  • プログラム問題(4)

    以下の問題のプログラムをやったのですが、コマンドプロンプトで実行してみるとエラーになってしまうのですが、どなたか問題点を指摘していただけないでしょうか? 【問題】 学籍番号、氏名、出席からなる10人分のデータがある。出席の悪いものから並び替  えて表示するプログラム。  例  CA180002 山田太郎 70  CA170001 山田次郎 60  データは、適当なものを使います。 【プログラム】 #include <stdio.h> #include <string.h> typedef struct student_t { char id[9]; char name[51]; unsigned int attendance; } student; student stu[10]; int stu_i = 0; void student_new(const char *, const char *, unsigned int); void student_sort(void); int main(void) { int i; student_new("5", "宮本恒靖", 5); student_new("14", "三都主アレサンドロ", 1); student_new("21", "加地亮", 9); student_new("22", "中澤佑二", 6); student_new("7", "中田英寿", 2); student_new("8", "小笠原満男", 8); student_new("10", "中村俊輔", 7); student_new("15", "福西崇史", 3); student_new("9", "高原直泰", 4); student_new("13", "柳沢敦", 0); student_sort(); for (i = 0; i < stu_i; ++i) { printf("%s %s %d\n", stu[i].id, stu[i].name, stu[i].attendance); } } void student_new(const char *id, const char *name, unsigned int att) { strcpy(stu[stu_i].id, id); strcpy(stu[stu_i].name, name); stu[stu_i].attendance = att; stu_i++; } void student_sort(void) { int i, j; student tmp; for (i = 0; i < stu_i; ++i) { for (j = i + 1; j < stu_i; ++j) { if (stu[i].attendance > stu[j].attendance) { tmp = stu[i]; stu[i] = stu[j]; stu[j] = tmp; } } } }

  • メンバのポインタについて。

    struct student { char *name; }student; int main(void) { student.name = "Saitou Takashi"; printf("%s",student.name); } に関してですが、なぜこのような事が可能なのでしょうか?nameでは不可能なのに、*nameでは可能です。それはなぜでしょうか?宜しくお願いします。

  • 構造体内のポインタのポインタにアクセスするには?

    たとえば、 struct a { char **name } という構造体があったとして、 struct *a; a->name = malloc(sizeof(char *) * 3); としたときに、 for(i = 0; i < 3; i++){ a->name[i] = malloc(sizeof(char) * 10); } とするとエラーになります。 a->name配列の各要素をmallocするにはどうすればよいのでしょうか?

  • 構造体についてです。

    typedef struct student{ int id; char name[20]; int kokugo; int sansu; int eigo; }STUDENT; と、 struct student{ int id; char name[20]; int kokugo; int sansu; int eigo; }; の違いはなんでしょう? 私は下記をよく使うのですが・・・。 typedefについて詳しく知りたいです。

  • このプログラムのポインタを配列に変換したいんですけど

    C言語初心者です。助けてください。 途中までがんばったのですがどうしてもできません。問題はこの構造体の*name→name[25],*email→email[30]に変換させたいのですが、そのまま変換すると左辺値が必要や移植性のないポインタ変換などのエラーが出てしまいます。どうすればいいですか?教えてください。あと関数getlineと構造体は変えないでください。(指定した部分は除く) このプログラムは名前、メールアドレス、年齢を保存していき-1を入力した時出力されるというものです。 よろしくお願いします。 入力例 10 hakata abc@・・・ 12 yokohama dfg@・・・ -1 -1 -1 出力例 -1 -1 -1 12 yokohama dfg@・・・ 10 hakata abc@・・・ #include <stdio.h> #include<stdlib.h> struct node { char *name; char *email; int age; struct node *next; } heap[100], *hp = heap; void getline(char *s,int n) { int c; while(--n>0&&((c=getchar())!=EOF && c!='\n')) *s++=c; *s='\0'; } char* dupstr(char* strg) { char* newstr; newstr=(char*)malloc(sizeof(char)*strlen(strg)); strcpy(newstr,strg); return newstr; } struct node *new(int n ,char* a, char* b) { hp->age=n; hp->email=a; hp->name=b; hp->next=NULL; return hp++; } struct node *add(struct node *p, struct node *q) { q->next=p; p=q; return p ; } void print_list(struct node *p) { while (p != NULL) { printf("%d ", p->age); printf("%s ", p->name); printf("%s ", p->email); p=p->next; } printf("\n"); } main() { int age,p; char buf[80],a[80],b[80],*email,*name; struct node *root=NULL; while(getline!=NULL) { getline(buf,sizeof(buf)); age=atoi(buf); getline(b,sizeof(b)); getline(a,sizeof(a)); email=dupstr(b); name=dupstr(a); root=add(root,new(age,email,name)); if(age==-1) break; } print_list(root); }

  • Cプログラムがどうしても動きません

    Cを勉強中です。 年齢に-1が入力されるまで、名前、年齢、性別を聞くプログラムを作っているのですが、どうしてもうまく動きません。 具体的には、年齢を聞かれず、年齢?性別?_とまとめて表示されてしまいます。 ぜひともどこが間違っているか教えてください。お願いしますm(_ _)m #include<stdio.h> typedef struct{ char name[20]; int year; char sex[6]; }student; void read_data(int,student*); void write_data(int,student*); int main(void){ student data[10]; int i=0,j=0; do{ read_data(i,data); i++; }while(data[i-1].year!=-1); for(j=0;j<=i-1;j++){ write_data(j,data); } return 0; } void read_data(int i,student *data){ printf("%d人目\n",i); printf("名前?\n",i); scanf("%s\n",&(data[i].name)); printf("年齢?\n",i); scanf("%d\n",&(data[i].year)); printf("性別?\n",i); scanf("%s\n",&(data[i].sex)); return; } void write_data(int j,student *data){ printf("%d人目\t",j+1); printf("名前:%s",data[j].name); printf("年:%d",data[j].year); printf("性:%s",data[j].sex); return; }

専門家に質問してみよう