• ベストアンサー

配列をいれても表示がおかしい

data.txtから英文を読み込んで配列にいれ、それをさらに英単語に分類して配列に入れるプログラムを作っています。動作確認のために画面表示させているのですが、表示に変な文字が入ってしまい、わけがわからなくなっています。 どこか、おかしい点があれば指摘をお願いします<(_ _)> //tango1から英単語を取り出し、tango2に入れる。------------------------------- fp=fopen("data.txt","r"); /*つぎにtango1の中にある英文を空白、改行ごとに*/ n=0;s=1; /*一つの英単語とみなしてtango2に入力する。*/ while((c=fgetc(fp))!=EOF){ if (c==' '){ /*上記の前に空白、改行をpointに入れて*/ point[s]=n;s++; /*pointとpointの間が英単語であることを認識させる。*/ } else if(c=='\n'){ point[s]=n;s++; } n++; } fclose(fp); s=1; while(s<20){ for(h=0,i=point[s];i<point[s+1];h++,i++){ tango2[j][h]=tango1[i]; } s++; printf("tango2[%d]は%sです。\n",j,tango2[j]); j++; } }

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

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

No1, No3, No5です 2行以上でも正常に読み込むには…… ・1行読み込むごとに単語に分ける ・前にtango1に格納した範囲を記憶しておき、次の行は続きに格納する ・tango1を2次元配列にして、行ごとに読み込む などの方法があります(他にもあると思いますが……)。 なお、No6のtaka_tetsuさんが回答されているように、C言語の文字列は'\0'で終わることになっているので、これを忘れないように付け足す必要があります。

gurizuri4649
質問者

補足

・tango1を2次元配列にして、行ごとに読み込む これでやってみようと思います。アドバイスありがとうございます。

その他の回答 (7)

回答No.7

私は、最初のソースコードを見た時点では、 buf の長さ>1行の長さ(改行までの長さ) の場合に、単語の途中で切れる可能性があるので、それが嫌で fgets を使用していないのかと勝手に推測していたんですが、#3 の補足を見ましたが、fgets 使用してるんですね。 単語が途中で切れる場合があることを考慮しなければなりませんが、fgets を使用するんでしたら strtok() 関数で単語を切り出せばいいと思います。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.6

//for(i=0;buf[i]!=0;i++){ //tango1[i]=buf[i]; //printf("%c",tango1[i]); /*ここで、data.txtの中身を画面に表示する。*/ ///*つまり、tango1にdata.txtの中身が入っている事が証明される。*/ //} 証明されません。 buf[i] の値が'\0'だったときに格納されていません。 つまり、tango1は'\0'で終了していません。

回答No.5

たとえばdataファイルが以下のようなものだとします ------ abc def ghi jkl mn opq rst ------ この場合、『//data.txtの中身をtango1に入れる』のwhile内で fgets(buf,100,fp)が(2行あるので)2回実行されます。 1回目でbufの内容は「abc def ghi jkl」となりこれがtango1にコピーされ、 2回目でbufの内容は「mn opq rst」となりこれがtango1に上書きされます。 つまり、最後に読み込んだ行の内容がtango1の内容となり、他の行は無視されます。

gurizuri4649
質問者

補足

なるほど!だから表示の時に最後の行のやつだけ表示されていたんですね。 上書きされないためにはどこを変更すればいいですか?

回答No.4

以下の条件で「変な文字」が出力されるのでは? ・単語数が20未満しかない ・2行以上にわたってファイルに文章が書かれている ・ファイルの文字数が100文字以上ある 改行も単語の区切りとしたい、というわけですが このプログラムはそもそも2行以上の入力は読めません。 なぜなら、次の行を読み込むとき、前の行を読み込んだ部分に上書きしているからです。

gurizuri4649
質問者

補足

・単語数が20未満しかない ・ファイルの文字数が100文字以上ある この2つの意味は分かったのですが、 ・2行以上にわたってファイルに文章が書かれている の意味がわかりません。 「data.txtの文章が2行以上だとおかしくなる」という意味ですか?

回答No.3

No1です。 文字列の最後に'\0'が入力されていなかったので、入力すれば解決するかもとおもったのです。 これで解決しないなら、どこに原因があるのか分かりません。どのように表示されているかが分かれば、どこにバグがあるか指摘できるかも知れませんが。。。

gurizuri4649
質問者

補足

これが全文です。文字列の最後に'\0'もいれておきました。 #include<stdio.h> #include<stdlib.h> #include<string.h> main(){ FILE *fp; char c,d,buf[100]; char tango1[100]; char tango2[30][50]; /*英単語を配列に入れる*/ char tango3[30]; int point[1000]; int kuhaku[1000]; /*スペース*/ int h,i,j=0,m,n,s; //data.txtの中身をtango1に入れる。------------------------------------------- fp=fopen("data2.txt","r"); while( fgets(buf,100,fp)!=NULL){ for(i=0;buf[i]!=0;i++){ tango1[i]=buf[i]; printf("%c",tango1[i]); /*ここで、data.txtの中身を画面に表示する。*/ /*つまり、tango1にdata.txtの中身が入っている事が証明される。*/ } } fclose(fp); printf("\n\n"); //tango1から英単語を取り出し、tango2に入れる。------------------------------- fp=fopen("data2.txt","r"); /*つぎにtango1の中にある英文を空白、改行ごとに*/ n=0;s=1; /*一つの英単語とみなしてtango2に入力する。*/ while((c=fgetc(fp))!=EOF){ if (c==' '){ /*上記の前に空白、改行をpointに入れて*/ point[s]=n;s++; /*pointとpointの間が英単語であることを認識させる。*/ } else if(c=='\n'){ point[s]=n;s++; } n++; } fclose(fp); s=1; while(s<20){ for(h=0,i=point[s];i<point[s+1];h++,i++){ tango2[j][h]=tango1[i]; } tango2[j][h] = '\0'; s++; printf("tango2[%d]は%sです。\n",j,tango2[j]); j++; } }

回答No.2

while((c=fgetc(fp))!=EOF){  ... } のループの中では、ファイルから読み取った c を tango1 にも tango2 にも格納してませんよね? tango1 も tango2 もどこでどう宣言されているのかわかりませんし、ちゃんと単語の長さ分だけ確保されているのかわかりません。このへんは大丈夫なんでしょうか? ちょっとやってみました。参考にしてみてください。 #include <stdio.h> #include <string.h> #include <malloc.h> char buffer[100]; #defin WORD_MAX 100 char *pWord[WORD_MAX]; int main(void) {   FILE *fp;   char *p;   char c;   int iCount;   int i;   int blnDelimiter;   fp = fopen("data.txt","r");   if( fp == NULL ) {     return( 0 );   }   p = buffer;   iCount = 0;   blnDelimiter = 0;   do {     c = fgetc(fp);     switch( c ) {     case ' ':     case '\n':     case EOF:       if( blnDelimiter == 0 ) { // 空白などが連続する場合は、そのまま読み飛ばす。         blnDelimiter = 1;         *p = '\0';         pWord[iCount] = (char *)malloc( sizeof(char) * ( strlen(buffer) + 1 ) );         if( pWord != NULL ) {           strcpy( pWord[iCount], buffer );           puts( pWord[iCount] );           iCount++;         }         p = buffer;       }       break;     default:       if( blnDelimiter == 1 ) {         blnDelimiter = 0;       }       *p = c;       p++;     }     if( iCount >= WORD_MAX ) {      break;     }   } while( c != EOF );   fclose(fp);   // ここで、何らかの処理を行う。   // 使用済みメモリ開放   i = 0;   while( pWord[i] ) {     free( pWord[i] );     i++;     if( i >= WORD_MAX ) {       break;     }   }   return( iCount ); }

gurizuri4649
質問者

補足

すみません。プログラム全体載せようと思ったのですが、800文字以上は書き込めないらしくて。主要部分を書きました。 プログラムを全部作っていただいてありがとうございます。この中で重要だと思われるプログラムがあれば教えていただきたいのですが・・

回答No.1

他にも色々と疑問な点がありますが…… 以下の方法で解決できないでしょうか? for(h=0,i=point[s];i<point[s+1];h++,i++){ tango2[j][h]=tango1[i]; } // ここに tango2[j][h] = '\0'; を追加 s++; printf("tango2[%d]は%sです。\n",j,tango2[j]); j++;

gurizuri4649
質問者

補足

返答ありがとうございます。tango2[j][h] = '\0'; を追加して実行してみたのですが、表示結果はかわりませんでした。ちなみにこれはどういう意味なのでしょうか?

関連するQ&A

  • [動的配列]C言語の勉強で簡単な単語帳プログラム

    C言語の勉強として以下のような簡単なプログラムを作りました。 テキストファイルからユーザが入力した単語を検索し、ヒットしたものだけ その単語とその説明を表示するというプログラムです。 正常に動いているようなので、 つぎはループごとに、読み込んだ文字数に合わせて 配列(mean)の要素数を動的に確保するということを しようと思うのですがどのタイミングでmallocやreallocを入れればよいのか いまいちよくわかりません。 また、このプログラムの欠点などありましたら教えていただけると助かります。 よろしくお願いします。 --------------------------------------------------------------------- //マイ単語帳プログラム #include<stdio.h> #include<stdlib.h> #include<string.h> main(){ char input[100]; //ユーザが入力した文字列を格納 char tango[200]; //ファイルの単語 char mean[1000]; //ファイルの説明 char conti; //検索を続けるかどうかの入力 int flag; //検索単語がヒットした場合に立てるフラグ FILE *fp; //単語ファイルのopen if((fp=fopen("tango.txt","r"))==NULL){ printf("ファイルが開けません。"); exit(1); } /*******************ファイルからの文字列読み込み****************************/ //Yが入力されるまで検索を続ける do{ printf("検索する単語を入力してください。\n"); scanf("%s",input); printf("検索対象:%s\n\n",input); flag=0; //ヒットしたかどうかのフラグの初期化 while((fscanf(fp," %s %s",tango,mean))!=EOF){ //fscan 書式を指定して読み込める。 if(strcmp(tango,input)==0){ //strcmpは2つの引数が同じ時0を返す printf("%s\n%s\n\n\n",tango,mean); flag=1; //ファイル内に単語があった場合にフラグを立てる。 } } rewind(fp); if(flag==0){ printf("その単語は登録されていません。\n"); } printf("検索を終了しますか? ==> Y\n"); printf("検索を続けるにはY以外の文字を入力してください。\n"); scanf(" %c",&conti); //scanfの問題点を回避するために読み込み前に半角スペース } while(conti!='Y'); /**************************************************************************/ fclose(fp); return; } ---------------------------------------------------------------- tango.txt apple リンゴ SMTP 電子メールの送信や転送を行うためのプロトコル。 rewind 形式:rewind(ファイルポインタ); C言語のファイルシステム関数。ファイルの現在位置をファイルの先頭に置くことができる。

  • 配列のサイズ変更

    FILE *fp; char *fname = "test.txt"; unsigned char init[300]; int i = 0; int c; fp = fopen( fname, "r" ); if( fp == NULL ){ printf( "%sファイルが開けません\n", fname ); return -1; } while( (c = fgetc( fp )) != EOF ){ init[i] = c; i = i+1; } fclose( fp ); 自分のプログラムの中のこのようなテキストから文字を読んで配列に格納するような動作の中で、initを大きめにとっておいて配列に格納し終わったら余った空の配列を削除する、という機能を拡張したいのですがどのようにすればいいかわかりません。 どなたか教えていただけないでしょうか?

  • カウント配列

    while文で単語を読み込んでtango[i](単語を格納している)に同じ単語があれば、配列hindo[i](単語の出現回数を格納)に1を加える。tango[i]に同じ単語がなければtango[i]に単語を追加。aはtango[i]の最後の値、keyは読み込み単語とし、単語の出現頻度を出したいのですが、うまくいきません。ソースとしては以下のものを考えました。 for(i = 0; i <= a ;i = i + 1){ if(key == tango[i]){ hindo[i] = hindo[i] + 1; break; } if(key != tango[a]){ tango[a] = key; a = a + 1; } } どうすればうまくいきますか? たびたびすいませんが、初心者なのでよろしくお願いします。

  • C言語 csv 配列

    CSVファイルを2次元配列に格納したいのですが、書き方がわかりません。 csvファイルは1024×2048の0と1のみで構成されています。 fp=fopen(path,"r"); for(j=0; j<1024; j++) { for(i=0; i<2048; i++) { char c; do{c=(getc(fp));} while(c==','||c=='\n'||c=='\r'); map[j][i] = c-'0'; } } このように書きできたと思ったのですが、どうもうまくいっていないみたいです。 どこが悪いのか、どういう風に書けばいいのか教えていただげれば幸いです。

  • 辞書検索プログラムの続きです。

    void read_dic() { char eng2[20], jp2[40]; FILE *fp; int i=0; if((fp=fopen("dic.txt", "r"))==NULL) { printf("\n ファイルがありません\n"); exit(1); } else { printf("読み込み中...\n"); while (!feof(fp)) { fscanf(fp, "%s %s", eng2, jp2); strcpy(table[i].eng, eng2); strcpy(table[i].jp, jp2); i++; if(i>=100){ printf("辞書のテーブルがいっぱいです\n"); fclose(fp); exit(1); } } fclose(fp); printf("読み込み終了\n"); n = i; } } int hash(char *tango) { int h=0,p=256; while (*tango!='\0') { h = h*p + *tango; h = h%BUCKET_SIZE; tango++; } return(h); } struct cell *find(char *tango) { int a; struct cell *q; a=hash(tango); if(bucket[a].chain==NULL) return NULL; else{ q=bucket[a].chain; while ((strcmp(q->eng,tango))!=0){ if(q->next==NULL) return NULL; else q=q->next; } return q; } } 以前の投稿は http://oshiete1.goo.ne.jp/kotaeru.php3?qid=109202

  • 漢字を配列に入れたいのですが

    漢字を配列に入れたいのですが、うまくいきません。 3列、60行のcsvファイルを読み込んで配列に入れようをしているのですが、1列目、2列目、3列目にある漢字をそれぞれ配列に入れようとしているのですが、出力するとうまくいかないんです。誰か教えてください。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXBUFFSIZE 256 #define MAXWORDS 15 int split(char* words[], int length, char* split_ch,char* str){ int i,j; for(i=0;i<length;i++){ if((words[i] = strtok(str,split_ch))==NULL)break; str=NULL; } return(i); } int main(int argc, char* argv[]){ if(argc !=2){ printf("入力エラー"); return(0); } FILE *fp; char *ll, *words[MAXWORDS], ch, buff[MAXBUFFSIZE]; int i,j; unsigned int data1[60], data2[60], data3[60]; if((fp =fopen(argv[1],"r"))==NULL){ printf("ファイルが開けません。\n"); } j=0; ll= fgets(buff,MAXBUFFSIZE,fp); while((ll= fgets(buff,MAXBUFFSIZE,fp)) != NULL){ split(words, MAXWORDS, ",",ll); data1[j] = words[0]; data2[j] = words[1]; data3[j] = words[2]; j++; } printf("%s\n%s\n%s\n", data1,data2,data3); }

  • 構造体配列とポインタについて

    いつもお世話になっています。 皆様には、本当にお世話になっています。 先日、皆様にアドバイスをいただいたのですが、私の勉強不足で結局・・・並び替えて表示できなかったです。 大変申し訳ないのですが、どこがダメなのか教えてください。 /********************/ /*--- 英単語辞書 ---*/ /********************/ #include <stdio.h> #include <string.h> #define NUMBER 50 /*登録数*/ #define MAX_NAME 20 /*単語の最大文字数*/ #define MAX_WAYAKU 30 /*和訳の最大文字数*/ /************************/ /*--- 単語帳の構造体 ---*/ /************************/ typedef struct { char name[MAX_NAME]; /*単語*/ char wayaku[MAX_WAYAKU]; /*和訳*/ }words; /***********************************************/ /*----- 単語の交換 -----*/ /***********************************************/ void swaps(words x, words y) { words temp = x; temp = x; x = y; y = temp; } /************************************************/ /*------ 単語と和訳の登録 ------*/ /* 関数tourokuword()は引数words tango[]の、イン*/ /*クリメントしたtango_counの順番に格納する。  */ /************************************************/ void tourokuword(words tango[], int tango_count) { char word[MAX_NAME]; /*単語の名前*/ char wa[MAX_WAYAKU]; /*単語の和訳*/ int i = 0; int j; printf("[単語]:"); scanf("%s", word); /*単語を単語帳に登録*/ strcpy(tango[tango_count].name, word); printf("[和訳]:"); scanf("%s", wa); /*和訳を単語帳に登録*/ strcpy(tango[tango_count].wayaku, wa); for( i = 0; i < tango_count; i++){ if(strcmp(tango[tango_count].name, tango[i].name) > 0){ swaps(tango[tango_count], tango[i]); } } } /***********************************************/ /*----- 登録された単語を表示する -----*/ /* 関数printword()は引数words tango[]の、イン */ /*クリメントしたtango_counの並び替えて表示する */ /***********************************************/ void printword(words tango[], int tango_count) { int i = 0; puts("登録されている単語を表示します。\n"); for (i = 0 ; i < tango_count; i++) { printf("[単語]:%s\n", tango[i].name); /*単語の表示*/ printf("[和訳]:%s\n", tango[i].wayaku); /*和訳の表示*/ } } /****************/ /*--- メイン ---*/ /****************/ int main(void) { words tangochou[NUMBER]; /*単語帳に50件登録*/ int menu_num; /*メニュー番号*/ int slct_num; /*選択番号*/ int tango_count = 0; /*登録数のカウント*/ while(1){ /****************************/ /*--- メニュー番号の入力 ---*/ /****************************/ do { printf("1・・・登録. 2・・・表示. 3・・・終了.\n"); printf("メニュー番号を入力してください。:"); scanf("%d", &menu_num); /*メニュ番号の入力*/ if (menu_num > 0){ break; } }while(menu_num != 0); /*メニュ番号が該当しない時は再入力*/ switch (menu_num){ case 1 :/*--- メニュー 1:単語と和訳の登録 ---*/ while(1) { if (tango_count < NUMBER){ printf("英単語と和訳を入力してください。:\n"); /*単語と和訳の登録*/ tourokuword(tangochou, tango_count); tango_count++; }else { puts("50件以上です。\n"); return 0; /*50件以上は終了する*/ } /*登録を続けるか?*/ printf("続けますか【Yes・・・1/No…0】:"); scanf("%d", &slct_num); if(slct_num != 1){ /*0なら終了。1なら継続。*/ break; } } break; case 2 :/*--- メニュー 2:登録された単語と和訳の表示 ---*/ printword(tangochou, tango_count); /*単語と和訳の表示*/ break; case 3 :/*--- メニュー 3:終了 ---*/ puts("終了します。\n"); return (0); default:/*--- メニュー 4:非メニュー番号の処理 ---*/ puts("メニュー番号が間違っています。"); break; } } return (0); }

  • 配列がずれてしまう

    C言語初心者です。 二次配列を組んだのですが、初期では正常に配列に入ったのですが、 次回のループで入っていた筈の数値がズレてしまいます。 #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp; // FILE型構造体 char fname[] = "c:\\tmp\\test.txt"; int f1, f2, f3, f4, f5; int i,p,s; int r_table[1100][4]; //ファイル読み込み用構造体 for(i=0;i<1100;i++){ for(p=0;p<4;p++){ r_table[i][p]=0; } } fp = fopen(fname, "r"); // ファイルを開く。失敗するとNULLを返す。 if(fp == NULL) { printf("%s file not open!\n", fname); return -1; } i=0; while(fscanf(fp, "%d %d %d %d %d", &f1, &f2, &f3, &f4, &f5) != EOF) { //数字の格納 r_table[i][0]=f1; r_table[i][1]=f2; r_table[i][2]=f3; r_table[i][3]=f4; r_table[i][4]=f5; printf("%d %d %d %d %d\n", r_table[i][0],r_table[i][1],r_table[i][2],r_table[i][3],r_table[i][4]); i++; } fclose(fp); // ファイルを閉じる printf("\n"); for(s=0;s<10;s++){ //数字の抜出 10回ループ printf("%d %d %d %d %d\n", r_table[s][0],r_table[s][1],r_table[s][2],r_table[s][3],r_table[s][4]); } return 0; } 実行結果 9 13 14 19 22 1 14 25 29 31 4 12 15 22 25 3 13 18 19 22 2 8 14 17 26 1 3 4 9 16 2 18 19 28 30 9 10 16 17 28 9 13 14 19 1 1 14 25 29 4 4 12 15 22 3 3 13 18 19 2 2 8 14 17 1 1 3 4 9 2 2 18 19 28 9 9 10 16 17 28 どうやら、r_table[s][4]にr_table[s+1][0]が入ってしまっているように見られます。 どの部分が間違っているのかご教示頂けたらと思います。

  • カンマ区切りのデータを配列に読み込みたい

    趣味でゲームを製作しているのですが、その中で、 マップデータのテキストファイルを二次元配列に読み込むようにしています。 データファイルは、カンマ区切りで、例えば、 1,2,3,4,5 5,4,3,2,1 1,2,3,4,5 というようになっています。 fp=fopen(path,"r"); for(j=0; j<3; j++) { for(i=0; i<5; i++) { char c; do{c=(getc(fp));} while(c==','||c=='\n'||c=='\r'); map[j][i] = c-'0'; } } 配列の各要素に読み込む中身が、0~9など1文字に限られている場合、このgetc()を使う方法で問題ないのですが、0~255など、文字数がまちまちになると、1文字を取り出すgetc()ではできなくなってしまいます。 これがどうすれば可能になるのか、情けないのですがちょっと思いつかないので、アドバイスを頂ければ幸いです。

  • 配列の中身が変わってしまいます

    英単語中のアルファベットの数を数えるプログラムをCで作っています。 ------------------------------------------------ #include<stdio.h> #include<stdlib.h> #include<string.h> #define NS 69964 /* 入力の最大数 */ #define WC 64 /* 入力の1行の文字数 */ int main(int argc, char *argv[]) { FILE *fp; char str[NS][WC]; int al[NS][26] = {0}; int i, j, k; //コマンドライン引数でテキストファイルを読み込む fp = fopen(argv[1],"r"); //テキストファイル内の単語を1行ごとにstr[]に格納 //改行文字は除き,大文字は小文字にする for(i = 0; i < NS; i++){ fgets(str[i], WC, fp); strtok(str[i], "\n"); for(j = 0; j < WC; j++) str[i][j] = tolower(str[i][j]); } printf("File reading completed.\n"); //カウントする //'a'~'z'の数がal[][0]~al[][25]の値に対応 //例えば'a'が2個,'z'が3個ならal[][0]=2,al[][25]=3 for(i = 0; i < 5; i++) for(j = 0; j < 20; j++) al[i][str[i][j] - 'a']++; //al[][]の中身を表示 for(i = 0; i < 5; i++) for(j = 0; j < 26; j++) printf("al[%d][%d]:%d\n", i, j, al[i][j]); fclose(fp); return 0; } -------------------------------------------------- for(i = 0; i < 5; i++) for(j = 0; j < 20; j++) al[i][str[i][j] - 'a']++; の処理を終えた後、al[][]の中身を見てると al[][7]の値だけがおかしいのです。'h'の数を数えているはずなのですが・・・ for文中でprintfしてみたのですがこのときは正しく数えられています。 ですがfor文を抜けた途端al[][7]の値が変わってしまいます。 これはどういうことなのでしょうか? 修正もしくは別の方法があれば教えてください。

専門家に質問してみよう