c言語初心者のための構造体配列のバッファオーバーランエラーの原因と解決方法

このQ&Aのポイント
  • c言語初心者が構造体配列を作成した際にバッファオーバーランエラーが発生しています。エラーの原因や解決方法について教えてください。
  • プログラム上でのバッファオーバーランエラーの原因としてヒープ領域の問題が考えられます。具体的な解決方法についても教えてください。
  • 構造体配列のメンバを設定する際に起こるバッファオーバーランエラーの原因と解決方法について教えてください。
回答を見る
  • ベストアンサー

c 言語初心者です。

c 言語初心者です。 私は下記の構造体配列をつくりました。 しかしバッファオーバーランが起きてエラーが起きてしまいます。 ヒープ領域に問題があるのかもしれませんが、プログラム上どこに原因があるのかが良くわかりません。 どなたかよろしければ教えていただけないでしょうか? #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include<memory.h> struct s { int i; char name[25]; char huri[25]; char num[23]; }; void touroku(struct s *p); void hyouji(struct s *p); int main(void) { struct s data; touroku( &data ); hyouji( &data ); //data.num *= 1; /* dataはポインタではないのでドット演算子 */ hyouji( &data ); return 0; } /* 構造体のメンバを設定する */ void touroku(struct s *p) { int i=0; for(i=1;i<3;i++) { printf( "25文字以内の名前を入力して下さい\n" ); memset(p[i].name, 0, sizeof(p[i].name)); fgets( p[i].name,sizeof(p[i].name) , stdin ); if(strchr(p[i].name,'\n')==NULL)//バッファ処理 { while(getchar() != '\n'); } if(p[i].name[strlen(p[i].name)-1]=='\n')//改行解除 { p[i].name[strlen(p[i].name)-1] = '\0'; } printf("25文字以内のふりがなを入力してください\n"); memset(p[i].huri, 0, sizeof(p[i].huri)); fgets(p[i].huri,sizeof(p[i].huri),stdin); if(strchr(p[i].huri,'\n')==NULL)//バッファ処理 { while(getchar() != '\n'); } if(p[i].huri[strlen(p[i].huri)-1]=='\n')//改行解除 { p[i].huri[strlen(p[i].huri)-1] = '\0'; } printf( "整数を入力して下さい\n" ); memset(p[i].num, 0, sizeof(p[i].num)); fgets(p[i].num,sizeof(p[i].num),stdin ); if(strchr(p[i].num,'\n')==NULL)//バッファ処理 { while(getchar() != '\n'); } if(p[i].num[strlen(p[i].num)-1]=='\n')//改行解除 { p[i].num[strlen(p[i].num)-1] = '\0'; } } } /* 構造体のメンバを出力する */ void hyouji(struct s *p) { int i=0; for(i=1;i<3;i++) printf("%-8s %3s %3s %d\n" ,p[i].name , p[i].huri , p[i].num , i); puts("----------------------------------------------------------------"); return ; }

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

  • ベストアンサー
回答No.3

もっと簡単に考えて肩の力を抜いてプログラミングされてはいかがでしょうか。 プログラムの違いをチェックすればわかると思います。 頑張って下さい :-) (使用OS: Mac OSX、スペースは2バイトですので半角に変更のこと) #include <stdio.h> #include <string.h> #define SIZE 25   /* 文字の許容バイト数 */ #define MEMBER 3  /* 登録人数+α */ struct s {  // int n;     意味不明です。  char name[SIZE];  char huri[SIZE];  char num[SIZE]; } data[MEMBER];   /* main()の初めに置くと広域変数として使えるよ */ /* プロトタイプ宣言 */ void touroku(void); void hyouji(void); int main(void) {  touroku();  /* 広域変数としたから引数は考えなく良い */  hyouji();   /*   〃      */  return 0; } /* 構造体のメンバを設定する */ void touroku(void) {  int i, n;  for(i = 0; i < MEMBER; i++) {   fprintf(stderr, "%d文字以内の名前を入力して下さい\n", SIZE);   fgets( data[i].name, SIZE, stdin );   data[i].name[strlen(data[i].name) - 1] = '?0';   fprintf(stderr, "%d文字以内のふりがなを入力して下さい\n", SIZE);   fgets( data[i].huri, SIZE, stdin );   data[i].huri[strlen(data[i].huri) - 1] = '?0';   fprintf(stderr, "整数を入力して下さい\n");   fgets( data[i].num, SIZE, stdin );   data[i].num[strlen(data[i].num) - 1] = '?0';  } } /* 構造体のメンバを出力する */ void hyouji(void) {  int i;  for(i = 0; i < MEMBER; i++) {   printf("%-8s %3s %3s %d\n" ,data[i].name , data[i].huri , data[i].num , i);   printf("----------------------------------------------------------------?n");  } }

armpoint
質問者

お礼

ありがとうございます。 難しく考えすぎというのは自覚しているのですが、基本を理解できていないのでなかなか柔軟に考えてないみたいです。 ご丁寧にわかりやすく書いていただき大変参考になりました。

その他の回答 (3)

回答No.4

 解答がズレてしまいました m(_ _)m #1さんが正解ですよ。  単一の変数なのに for() を3つの変数枠があるかのようにプログラミングしてあるために不正なアクセスとなってバスエラーが出るということです。  後はエラーとは関係ありませんが、while(getchar()) を strlen() に換えれることでしょうか。また、変数枠は #define で先に決めて置くのがCの一般的な使い方になっています。理由は、その #define を直すだけでプログラム全体が更新できるからです。 #include <stdio.h> #include <string.h> #define SIZE 25 #define MEMBER 2 struct s { char name[SIZE]; char huri[SIZE]; char num[SIZE]; }; /* プロトタイプ宣言 */ void touroku(struct s *); void hyouji(struct s *); int main(void) { struct s data[MEMBER]; touroku(data); hyouji(data); return 0; } /* 構造体のメンバを設定する */ void touroku(struct s *p) { int i, n; for(i = 0; i < MEMBER; i++) { fprintf(stderr, "%d文字以内の名前を入力して下さい\n", SIZE); fgets( p[i].name, SIZE, stdin ); p[i].name[strlen(p[i].name) - 1] = '\0'; fprintf(stderr, "%d文字以内のふりがなを入力して下さい\n", SIZE); fgets( p[i].huri, SIZE, stdin ); p[i].huri[strlen(p[i].huri) - 1] = '\0'; fprintf(stderr, "整数を入力して下さい\n"); fgets( p[i].num, SIZE, stdin ); p[i].num[strlen(p[i].num) - 1] = '\0'; } } /* 構造体のメンバを出力する */ void hyouji(struct s *p) { int i; for(i = 0; i < MEMBER; i++) { printf("%-8s %3s %3s %d\n" ,p[i].name , p[i].huri , p[i].num , i); printf("----------------------------------------------------------------\n"); } }

armpoint
質問者

お礼

ありがとうございます。 まだまだ分からない事が多くて、書き方など大変参考になります。 今やってる構造体配列やポインタが混ざってくるといろいろ混乱してしまって、 ありがとうございました。

  • chie65535
  • ベストアンサー率43% (8512/19352)
回答No.2

>私は下記の構造体配列をつくりました。 >struct s data; これのどこが「構造体配列」なのか、小一時間問い詰めても宜しいか?

armpoint
質問者

補足

答えていただけないなら書き込みはご遠慮ください。他の方が不快に感じる文章です。

  • towad
  • ベストアンサー率80% (4/5)
回答No.1

mainの最初で  struct s data; と、単一の変数として定義されているのに、tourokuやhyouji関数では 渡された引数を構造体sの配列として使おうとしています。 とりあえずmainの処理を struct s data[3]; touroku( data ); hyouji( data ); とすれば辻褄が合うのではないでしょうか。

armpoint
質問者

お礼

ありがとうございます。 いろいろ理解できていなかったので、書き方が構造体になってました。 なんとかやってみます。

関連するQ&A

  • c言語で質問なのですが

    c言語で質問なのですが 下に私の疑問点があるプログラムの一部を書き込みます。 printf("ふりがな:"); memset(p[i].huri, 0, sizeof(p[i].huri)); fgets(p[i].huri,sizeof(p[i].huri),stdin); if(strchr(p[i].huri,'\n')==NULL)//バッファ処理 { while(getchar() != '\n'); } if(p[i].huri[strlen(p[i].huri)-1]=='\n')//改行解除 { p[i].huri[strlen(p[i].huri)-1] = '\0'; } if(strlen(p[i].huri)>25) { puts("<<文字入力数が多すぎでしょうあんた>>"); puts("何かキーを押してください"); getchar(); system("cls"); continue; } ここで私は構造体配列にふりがなを登録します。 しかし25文字以上なら登録できないようにしたいのですが。 if文で制御しよう試みているのですがうまくいきません。 この場合fgetsを使った時点で格納されているのでしょうか? 結局25文字以上でも構造体配列に格納されてしまいます。 どなたか教えていただけませんでしょうか? よろしくおねがいします。

  • C言語のqsortについて

    現在、qsortのコードに取り組んでいます。 if (strcmp(ad, "ASC") == 0) { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_u); } else { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_d); } 恐らくこちらのqsortでの第二引数が書き方を間違えていると思うのですが、修正の方法が分からず、どなたか教えて頂けないでしょうか? #include <stdio.h> #include <time.h> #include <string.h> #include <stdlib.h> static char ad[10]; int cmp_u(const void* a, const void* d) { return strcmp((char*)a, (char*)d); } int cmp_d(const void* a, const void* d) { return strcmp((char*)d, (char*)a); } int main() { int num1, num2; char op; float answer; int r,i; FILE* fp; char c[11]; char sin[1000][1000]; char ad[8]; fp = fopen("log.txt", "a+"); if (fp == NULL) { printf("ファイルオープン失敗\n"); return -1; } while (1) { r = scanf("%d%c%d", &num1, &op, &num2); if (r != 3) { puts("input error"); return 1; } if (op == '+') { answer = num1 + num2; } else if (op == '-') { answer = num1 - num2; } else if (op == '*') { answer = num1 * num2; } else if (op == '/') { answer = (float)num1 / num2; } time_t t = time(NULL); struct tm* tm = localtime(&t); printf("%d/%02d/%02d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); printf("%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec); printf("%d%c%d,%f\n", num1, op, num2, answer); fprintf(fp, "%d/%02d/%02d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); fprintf(fp, "%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec); fprintf(fp, "%d%c%d,%f\n", num1, op, num2, answer); printf("計算を続けますか?"); scanf("%s\n", &c); if (strcmp(c, "no") == 0) { break ; } } fclose(fp); fp = fopen("log.txt", "r"); int cnt = 0; for (i = 0;i < 1000;i = i + 1) { if (fgets(sin[i], sizeof(sin[0]), fp)) ++cnt; else break; } fclose(fp); printf("ASC or DESC: "); scanf("%s", ad); if (strcmp(ad, "ASC") == 0) { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_u); } else { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_d); } for (i = 0;i < cnt;i = i + 1) { printf("%s", sin[i]); } return 0; }

  • リストの作成と出力(C言語)

    こんにちは<_ _> リストの問題についてなのですが出力と逆順に出力するプログラムで headと前のデータの間に新しいデータを追加するように作ったのですが 入力した値が帰ってきません・・・ http://www9.plala.or.jp/sgwr-t/c/sec15-5.html などを見て見ましたが原因がいまいちよくわかりません。 どなたか教えてください おねがいします<_ _> #include<stdio.h> #include<malloc.h> struct tfield{ char name[20]; char tel[20]; struct tfield *pointer; }; struct tfield *talloc(void); int main(void) { struct tfield *head,*p; char buffer[BUFSIZ]; head=NULL; while(1){ p=talloc(); if(scanf("%s",buffer) == EOF){ break; strcpy(p->name, buffer); } if(buffer == "^Z")break; printf(" "); if(gets(buffer) == EOF){ if(scanf("%s",buffer) == EOF){ break; strcpy(p->tel, buffer); } p->pointer=head; /*今までの先頭ポインタを次のポインタに*/ head=p; } p=head; while(p!=NULL){ printf("%6s %s\n",p->name,p->tel); p=p->pointer; } return 0; } struct tfield *talloc(void) /*記憶領域の取得*/ { return (struct tfield *)malloc(sizeof(struct tfield)); } 変数は変えるなとのことです。 あと、 「name tel name tel name tel ^z name tel name tel name tel」 と表示したいのですがCtrl+zを二回押さないとできません><、 当方プログラム1ヶ月の初心者です ご指導どうかよろしくお願いします<_ _>

  • strlen

    c言語初心者です。 10文字以上入力すると警告してくれるプログラムを考えています。 一応文字数を制限するにあたりstrlenを使おうとしてるのですが 思ったように機能してくれません。 以下が私の書いたプログラムです。 void main() { char name[10]={0}; memset( name, '\0', sizeof(name) ); loop: puts("*****登録*****"); printf(" 名前 :"); fgets(name,10,stdin); //バッファクリア**// if(strchr(name,'\n') == NULL) { while(getchar() != '\n'); } if(strlen(name)>10) { puts("<<文字入力数が多すぎです>>"); fgets(name,10,stdin); //バッファクリア**// if(strchr(name,'\n') == NULL) { while(getchar() != '\n'); } system("cls"); goto loop; } else { puts("OK"); } } よろしくお願いします。

  • C言語の初心者です。教えてください

    #include<stdio.h> #define NAME 4 void main() { char str[NAME]; int i; for (i = 0;i < NAME;i++){ scanf("%s", &str[i]); } for(i = 0; i < NAME;i++){ printf("%s\n", str[i]); } } どこか間違っているのですか?それとも何か足りないのでしょうか? お願いします。

  • C言語 家系図

    問題 構造体personを以下のように仮定する。 struct person { int age; char name[20]; struct person *father; struct person *mother; }; この構造体の表す人の名前、年齢、その人の父親の名前、およびその人の母親の名前を出力する関数 void print_person(struct person *p) を作成せよ。出力の形式は name: 本人の名前 age: 本人の年齢 father: 父親の名前 mother: 母親の名前 となるようにすること。 また、ポインタ father や mother の値が NULL のときには、名前のかわりに unknown と出力するようにせよ。 以上が問題なのですが自分でプログラムを作ってみたところ実行したら、エラーになって矯正終了されてしまいました。 以下が私の作ったプログラムです。 #include <stdio.h> struct person { int age; char name[20]; struct person *father; struct person *mother; }; void set_name(struct person *p, char name[]) { int i; i = 0; while (name[i] != 0) { p->name[i] = name[i]; i++; } p->name[i] = 0; } void print_person(struct person *p) { printf("name:%s", p->name); printf("age:%s\n",p->age); if(p->father != NULL){ printf("father:%s\n",p->father); } else{ printf("unknown"); } if(p->mother != NULL){ printf("mother:%s\n",p->mother); } else{ printf("unknown"); } } int main(void) { struct person me, dad, mom; set_name(&me, "Michael"); me.age = 16; me.father = &dad; me.mother = &mom; set_name(&dad, "David"); dad.age = 38; dad.father = NULL; dad.mother = NULL; set_name(&mom, "Susan"); mom.age = 36; mom.father = NULL; mom.mother = NULL; print_person(&me); print_person(&dad); print_person(&mom); return (0); } どこが違うのか教えていただけないでしょうか?

  • C言語

    3人分の、名前、年齢、性別、を入力して表示するプログラムを作りなさい。というプログラムなんですが、なぜかこのままだとコンパイルはとおるんですが文字入力を3回とfor文で定めているはずなのに、4回になってしまいます。なぜなんでしょうか・・・?prints関数内のfor文はちゃんと動作していて3つ出力されているんですが。コンパイルエラーは無しです。分かるかた教えて頂けないでしょうか? #include <stdio.h> struct tag{ char name[20]; int age; char sex[20]; }; void put (struct tag *ai); void prints(struct tag *sei); int main(void) { struct tag kansuu[3]; put(kansuu); prints(kansuu); return 0; } void put (struct tag *ai) { int i; for(i=0;i <3;i++){ scanf("%s %d %s\n",(ai+i)->name,& (ai+i)->age,(ai+i)->sex); } return;} void prints(struct tag *sei) { int i; for(i=0;i <3;i++) printf("%s %d %s\n",(sei+i)->name,(sei+i)->age,(sei+i)->sex); return;}

  • C言語でcsvファイルの日別の金額を足し合たいんですが..

    csvファイルのフィールドが15あるうちの2番目に日にち、15番目に金額が書いてあり、日にちには同じ日がいくつもあるので、その金額をそれぞれ足し合わせたものを出力するというものをやろうとしているのですが、C初心者何ですけど一応書いたプログラムが #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> int main(void) { char buffer1[512], buffer2[512],*p,*tp; FILE *fp; int i,j,num,sum; clock_t start,end; start = clock(); fp=fopen("j0.csv","r"); if(fp == NULL){ printf("ファイルが開けませんでした。\n"); exit(-1); } sum=0; while(fgets(buffer1,256,fp)!=NULL && fgets(buffer2,256,fp)!=NULL){ tp = strchr(buffer1, ','); p = strchr(buffer2, ','); tp = strchr(p+1, ','); for(j=0;j<13;j++) p = strchr(p+1, ','); num=atoi(p+1); sum+=num; if(tp==tp+1); sum+=atoi(p+1); else{ printf("%cでは%d円であった。\n",tp,sum); sum=0; } } return 0; } こんな感じなんですが、どうかご指導御願いします。

  • fwrite処理について

    fwrite処理を行っているのですが、うまくファイルに出力されません。どこがおかしいか分からない次第です。 返答のほど、よろしくお願いします。 #include <stdio.h> #include <string.h> #include <stdlib.h> struct ll{ long int bango; char name[20]; char denwa[15]; }; FILE *fpbin; /*FILE構造体(グローバル変数)*/ struct ll *memalloc(void); void main(void) { struct ll *p; p = memalloc(); fpbin = fopen("bin","w+b"); printf("追加するNo 名前 tel >\n"); scanf("%ld %s %s", &p -> bango, p -> name, p -> denwa); printf("%ld %s %s\n", p -> bango, p -> name, p->denwa); fwrite(p,sizeof(struct ll),1,fpbin); fclose(fpbin); } struct ll *memalloc(void) { struct ll *p; if ( (p = (struct ll *)malloc(sizeof(struct ll))) != NULL ){ return p; } printf("メモリの動的割当に失敗しました。\n"); exit (1); return p; }

  • C言語での構造体

    C言語の構造体で配列を扱うとき、 struct ○○{  char ○○[○] とすれば出来ますが、同じようにして構造体で二次元配列を扱うことは出来ますか? 一度組んでみたのですが、 #include<stdio.h> struct aaa{ int no; char name[128]; char y_name[128]; char n_name[128]; char s_name[128][128]; }; int main(void){ int i; struct aaa iryo[99]; printf("入力前\n"); /* 構造体配列に scanf()でデータを入力 */ for(i = 0; i < 3; i++) { // printf("input...\n"); scanf("%d", &iryo[i].no); scanf("%s", iryo[i].name); scanf("%s", iryo[i].y_name); scanf("%s", iryo[i].n_name); scanf("%s", iryo[i].s_name); } printf("入力後\n"); printf("出力前\n"); /* 入力データの確認 */ for(i = 0; i < 3; i++) { printf("番号:%02d 内容:%s Y分岐:%s N分岐:%s 他分岐:%s\n", iryo[i].no, iryo[i].name, iryo[i].y_name, iryo[i].n_name, iryo[i].s_name); } printf("出力後\n"); printf("%d",sizeof(struct aaa)); return 0; } としたら、エラーは出ませんが、実行すると何も表示されませんでした。

専門家に質問してみよう