• ベストアンサー

テキストファイルから文字列を読み込んで二次元配列に格納するには

毎回お世話になっています。 ただいまC言語を勉強中の学生です。 基本的な文法は頭に入れたつもりでしたが、まだポインタと ファイルの入出力に苦手意識があり 実際うまくできないでいるので どなたか ご存知の方にアドバイスいただければと思って書き込ませていただきます。 今回練習しているのは 先に述べたように、テキストファイルに abc def ghi jkl などと文字列を書いておき、そのファイルを読み込んで 二次元配列に格納したいのですが、何を勘違いしているのか、 うまく実現できません。 参考書などを見て 一次元配列へ格納する場合は できたようなのですが、今後このプログラムを発展させる段階で 二次元配列に文字列を 格納できたほうが好都合なので 今模索しています。。。 ちなみに 一次元配列に格納する場合は 以下のように書きました。 #include<stdio.h> #include<stdlib.h> main() { char a[10]; FILE *fp; fp = fopen("word.dat", "r"); if (fp == NULL) { printf("File does not exist.\n"); exit(1); } while(fscanf(fp,"%s",a)==1){ printf("%s\n",a); } fclose(fp); return 0; } 実はコレに関しても分からない点があり、それは 目的の配列変数 a[]に格納できたのだから それを確認したいと思い printfで a[0]~a[10]を表示してみようとしたところ 変に文字化け したものが表示されたり、何も表示されなかったり よく分からないことが起きます。私は何を勘違いしてしまっているのでしょうか(>_<) 長々と書いてしまいましたが、今回 御教授いただきたいのは (1)、テキストファイルから 英字の文字列を読み込んで二次元配列に格納するために用いるのに 一番最適な関数はどれか(fscanfやfgetsなど) そして、その関数を使って 一番シンプルな記述をするにはどのように記述すればよいのか (2)、上のようなプログラムの書き方で、配列aにテキストファイルから読み込んで格納できたようなのに、a[0]~a[10]をprintfしたときに うまく中身が表示されないのはなぜか。 という点なのですが、(1)をとりあえず急いでおりますので、(2)はおまけ程度に考えていただければと思います。 なぜかファイルの入出力がいまだに把握できなくて苦手としておりますので、どうか よろしくお願いいたします。

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

  • ベストアンサー
  • mac_res
  • ベストアンサー率36% (568/1571)
回答No.5

#include <stdio.h> int main(void) { char a[10][10]; int i, maxi; FILE *fin; if ((fin = fopen("test.dat", "r")) == NULL){ fprintf(stderr, "Can't open file\n"); } for (i = 0; i<10; i++) { if (fgets(a[i], 10, fin) == 0) { maxi = i; break; } } for (i = 0; i < maxi; i++) { printf("a[%d] = %s", i, a[i]); } fclose(fin); return 0; }

donntakosu
質問者

お礼

ご親切に プログラムの書き方まで教えてくださったのにお礼が遅くなってしまい 大変申し訳ございませんでした!学生で 日々C言語を使っておりますが、普段使わない文法はどうしても苦手意識があり、路頭に迷っていました(>_<)そして、大まかには書けているのですが、把握しきれていないためにこまごまとバグがみつかるのですが どう間違っていてどう直せば良いのかというのが 本当に分からなくなっていたので 実際にソースを書いていただけて 読めて さらに理解することができました!本当に助かりました!ありがとうございました!

その他の回答 (5)

  • crew21
  • ベストアンサー率26% (58/222)
回答No.6

二次元配列の件は他の方が模範を書かれているので省くけど、 >...それは 目的の配列変数a[]に格納できたのだから それを確認したいと思い >printfで a[0]~a[10]を表示してみようとしたところ そらあかんだろ。 10個しか用意してない配列に a[10] はダメよ。最大で a[9]までね。配列のインデックスは0から始まるから a[10] とやった時点で、配列はみ出しちゃうよ。 たぶんコンパイラの親切で「文字化けしたものが表示されたり、何も表示されなかったり」で済むけど、ふつうは「即死」だよ。

donntakosu
質問者

補足

回答ありがとうございます。 それは私の表記ミスです! 上ではa[0]~a[10]をprintfさせようとした。 と書いてしまいましたが、 実際にはきちんと for(i=0;i<10;i++){ printf("a[%d]=%s \n"); } としておりますので その点に関しては大丈夫です(^_-)☆ ご指摘ありがとうございます!

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

>意図して代入したものでない 変な文字が入ってる可能性が >あるということでしょうか?! まちがえた。忘れてくれ。 >a[10][10]={"abc","def","ghi"} >と同じ状況になるように 二次元配列aに格納するには >どのように記述すればよいのか 先にも述べたように、「行単位」で処理する場合は fgets() を使った方がコードを読む人(自分を含む)が「1行ごとに何かをしてるんだな」とわかるので親切です。 要素数が同じだと説明しにくいので char a[5][10]; としよう。 これは「「要素数 10個の char 配列」の 5個の配列」です。a[0], a[1], .. , a[4] が各々 10個の char 配列ですね。 C 言語ではこれは同時に char[10] の先頭アドレス表現しているので fgets(a[0], 10, fp); で a[0] から始まる char 配列に fp から読んだ文字列を格納できます。 (改行コードは自前でカットしてね)。以下 a[1], a[2], ... も同様。 もちろん、テキストファイルの行数や 1行のバイト数などはバッファオーバーランしないように適当にやっといてくれ。

donntakosu
質問者

お礼

お礼が遅くなってしまいすみません!(>_<)ご親切に何度もアドバイスしていただいて 本当にありがとうございました!本当に助かりました!独学では 苦手意識のある部分がどうしてもつかみきれずにいて路頭に迷っていたのです。アドバイスしていただいてイメージがしやすかったです!ありがとうございました!

  • Werner
  • ベストアンサー率53% (395/735)
回答No.3

> printf("a[%s][%d]=%s \n",i,j,a[i][j]); %sは文字配列の先頭要素(※)へのポインタ(型は char *)を要求しますが、 a[i][j]は文字(型は char)なので書式指定子と後続の引数が合っていません。 そのためa[i][j]に入っている「文字」を 『「文字列の先頭アドレス」と解釈して、どことも知れぬメモリ領域にアクセスしている』 ことになります。 ※途中から表示したいなら別に先頭である必要はないけど、普通は先頭なので。 文字(char)を表示したいなら書式指定子は%cです。 ついでに最初の%sも%dの間違いでしょう。 しかし、printfが間違ってるのに > chara[10][10]={"abc","def","ghi","jkl"}; > のように定義しておいて 実行させたところ、上手く意図したように > 実行が成されたので、 というのは変ですね。こっちでは正しく書いていたのでは? > ANo.2 > fscanf() は空白を読み込まないので、単語単位で読む場合にしか使えません。 スキャンセットに空白文字も含めればscanf系でも一応空白読めますね。 まあ行単位の処理ならfgetsを使う方が良いでしょうけど。

donntakosu
質問者

お礼

お礼が遅くなってしまい 大変申し訳ありません(>_<) ご指摘いただいて、書式の指定が間違っていることに気がつきました!ありがとうございます! はい、正しく実行が成されたというのは、一番メインだったのは計算の内容でしたので、printfが間違っていてもそれはそこの表示だけが間違っているだけなので問題にはしなかったためです!printfは 正しく計算されているか確かめるために付加したものでしたのでねっ! とにもかくにも ご親切に教えていただいて本当に助かりました!どうもありがとうございました!

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

>(1)、テキストファイルから 英字の文字列を読み込んで >二次元配列に格納するために用いるのに 一番最適な関数はどれか fscanf() は空白を読み込まないので、単語単位で読む場合にしか使えません。 fgets() は行単位で読んでくれるので汎用的です(逆に行を読んだ後の加工も自前でする) いずれにせよ、ファイルを二次元配列に「どのように格納するか」は要件次第なので、それに応じてコーディングして下さい。 >a[0]~a[10]をprintfしたときにうまく中身が表示されないのはなぜか。 例えば a[0] には文字 'x' などが格納されており、それを書式指定子 %s にかけると、これを文字列の先頭アドレスと解釈して、どことも知れぬメモリ領域にアクセスしているからです。

donntakosu
質問者

補足

ご親切な回答 ありがとうございます!(>_<) fscanfは 単語単位で読む場合しか使えない というのが 分かるようで分からないのですが、 読み込む元のテキストファイルに abc(改行) def(改行) ghi(改行) [EOF] と書いている場合で これらを  a[10][10]={"abc","def","ghi"} と同じ状況になるように 二次元配列aに格納するには どのように記述すればよいのかと 困っております(>_<) もう少しだけ アドバイスをいただけるととても助かります。 申し訳ございません(>_<) (2)a[0]には 文字'x'などが格納されており というのは 意図して代入したものでない 変な文字が入ってる可能性が あるということでしょうか?!最初に初期可をすれば 解消できるのでしょうか?!それとも どのような対策を 施せばこの問題をかいしょうできると思われますか?!(>_<) 大変 お手数をおかけしております(>_<)

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.1

(1)について、 例えば、a[10][10]という配列があるとして、 この中に文字をどんな風に格納したいですか? (2)について、 a[0]~a[10]を、どんな風にprintfしましたか? なお、配列の定義でa[10]と書いたら、使えるのはa[0]~a[9]です。

donntakosu
質問者

お礼

すみません 再び 補足です(>_<) 上の書き込みに書き間違いを発見しました。。。 定義したのは char a[10][10]です!(chara[10][10]と 書いてしまいましたが) あ、はい それからa[10]まで定義した場合 値が格納できるのは a[9]までであることは 理解しております(^^)

donntakosu
質問者

補足

>(1)について、 >例えば、a[10][10]という配列があるとして、 >この中に文字をどんな風に格納したいですか? はい。まず 最終的にはテキストファイルから読み込みたいのだけれど、読みこむ記述を足す前に、他の部分を完成させるために、 テストとして chara[10][10]={"abc","def","ghi","jkl"}; のように定義しておいて 実行させたところ、上手く意図したように 実行が成されたので、後は テキストファイルから読み込むように 記述を追加させるだけ!と意気ごんだのですが ダメでした。。。 上のような記述をした場合は、a[0][0]にaが入っていて、a[0][1]にbが入っていると考えていたのですが、それが勘違いであるために(2)の ような問題が起きているのでしょうか?!(>_<) >(2)について、 >a[0]~a[10]を、どんな風にprintfしましたか? >なお、配列の定義でa[10]と書いたら、使えるのはa[0]~a[9]です。 はい! for(i=0;i<10;i++){ for(j=0;j<10;j++){ printf("a[%s][%d]=%s \n",i,j,a[i][j]); } printf("\n"); } printf("\n"); と書きました。a[i][j]は最初にchara型として 定義していたので %sという書式を指定しました。何がおかしいのか わかりますでしょうか(>_<)

関連するQ&A

  • C言語 文字列格納

    テキストファイルから整数データ又は文字列を読み込んで配列に格納する動作についての質問です。 テキストファイルが1行区切りの整数型なら1次元配列で for(i = 0; i < maxSize; i++) { fscanf(fp,"%d", &data[i]); } テキストファイルが1行区切りの文字列なら2次元配列で for(i = 0; i < MAXSIZE; i++) { if (fscanf(fp,"%s", &data[i][300]) == EOF) break; } for(j = 0; j < i; j++) printf("%s\n", data[j]); みたいな具合に格納できたんですが、 テキストファイルが1行区切りのデータではなく、空白文字区切りの文字データだった場合、それぞれどのようにして配列に格納すればいいかがわかりません。 イメージとしては、1文字目から見ていって空白が出ればそこで切って格納していくというかんじなのですが・・・ 質問の内容がわかりにくいかもしれませんが、是非教えてください。お願いします。

  • テキストファイルの内容を2次元配列に格納したい

    課題で用意されたテキストファイルを読み込み、空白を区切りとする文字列の単位で配列に格納したいのですが、やりかたがわかりません。 ソースプログラムですが #include<stdio.h> #include<string.h> #include<ctype.h> #define MAX 1000 int TextSplit(char *fname, char (*SpStr)[50]); int main(void) { int i, n; char fname[MAX], SpStr[MAX][50]; int Split; FILE *fp; printf("input File =>"); scanf("%s", fname); Split = TextSplit(fname, SpStr); printf("\n %d[文字列数] \n", Split); return 0; } int TextSplit(char *fname, char (*SpStr)[50]) { int i, j, k; char Readstr[MAX]; FILE *fp; fp = fopen(fname, "r"); if(fp == NULL) { printf("ファイルオープン失敗"); return 1; } i = 0; while(fscanf(fp, "%s", SpStr) != EOF) { i++; } fclose(fp); return i; } 以上のソースプログラムですが、内容は「空白で区切る文字列の単位の総数を表示する」ものになっています。 今日の20時までに終わらせないといけないので、ご教授お願いします。 使ってるソフトはMicrosoft Visual Studioです。

  • csvファイルを読み込んで二次元配列に格納したい

    200×250のある数字と文字の入力されたcsvファイル(またはtxtファイル)を読み込んで2次元配列に格納したいのです。 色々調べるとカンマの処理が必要ということがわかりましたが、どのようにソースを書けばよいかわかりません。使用言語はC言語です。 また、実際にcsvファイルを読み込むようにプログラムを書いてみましたが、すべて-858993460となって表示されます。 プログラミング初心者で勉強中なため困っています。 回答よろしくお願いします。 #include <stdio.h> #include <stdlib.h> #define row 200 #define column 250 int main() { int i, j; int data[row][column]; FILE *fp; fp = fopen("sample.csv", "r"); if (fp == NULL){ printf("ファイルがありません\n"); return 1; } for (i = 0; i < row; i++){ for (j = 0; j < column; j++){ fscanf(fp, "%lf", &data[i][j]); } } for (i = 0; i<row; i++){ for (j = 0; j < column; j++){ printf("%3d ", data[i][j]); } printf("\n"); } fclose(fp); return 0; }

  • txtファイルの文字を配列に格納

    ファイル関数を使ってoutput.txt(txtファイル)の文字を配列に格納するプログラムを作っているのですが、配列に文字を入れられない状態です。 ※参考になるページやアドバイスがあれば宜しくお願い致します。 ■プログラム #include <stdio.h> void main(){ int i; int data[10]; FILE *fp; fp = fopen("output.txt","r"); if(fp == NULL){ printf("ファイルが見つかりません。"); }else{ for(i=0;fp != EOF;i++){ data[i] = fgetc( fp ); } } } ■output.txt 001 100 猫A 好きな物 ねこまんま 002 200 猫B 好きな物 キャットフード

  • ファイル内の文字を配列に格納

    ファイル内の文字列をも表示させた上で、文字列を配列に1つずつ格納したいのですが、とっても簡単な方法で教えてください。 ファイル名は「abc」で配列名は「moji」でお願いします。

  • テキストファイルを二次元配列に

    お世話になります。 テキストファイルを1行ずつ読み込んで二次元配列に格納するプログラムですが、 //最大行数 #define LINE_MAX 10 //行内最大文字数 #define INPUT_MAX 128 char str[LINE_MAX][INPUT_MAX]; というようにして実現しています。 これを行数が分からないテキストファイルでも大丈夫なようメモリを動的に確保したいと考えています。 二つの次元の内、一つを動的に確保するにはどのようにしたら良いでしょうか。

  • char型の二次元配列の意味が分からないのです・・・。

    char型の二次元配列の意味が分からないのです・・・。 char namae[5][10] = { "a1", "a2", "a3", "a4"  }; printf("%s\n",namae[1]); という文があったのですが、これは実行するとa2と表示されました。どうしてなのでしょう。 そもそもcharは文字1文字ですよね。char[5]という一次元配列に5文字の文字列を入れることができるというのは分かります。でもchar[5][10]ってどんな文字列を入れるのでしょうか。 どうして初期化で"a1"という二文字を順々と並べるのか、printfでどうしてnamae[1]なのかが意味不明です。二次元配列だからnamae[1][0]とかで指定するのではないのかと思うのですが。 とにかく混乱です(>_<) ご存知の方、教えていただけませんか?

  • C言語  二次元配列

    C言語をやることになり苦戦しています。 CSVファイルからデータを呼び出し、二次元配列として出力したいのですが上手くいきません。 CSVファイルには英数字が混ざっており、エクセルでいう、11行と1440列ほどのデータがあります。初心者なりに書いてみたのですが、どこから手を付けたらいいかわかりません。 是非ヒントを頂けるとうれしいです。よろしくお願いします。 理想 [0][0] = [testtesttest] [0][1] = [testtesttesttest] 一行が終わりしだい [1][0] = [testtesttesttest] と変わっていくようにしたいです。 エラーが出ますが、コードを記載させていただきます。 コード #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> int main(void) { //ストリームポインタ FILE *fp; int kk = 0; int nn = 0; int hoge; //ファイルから読み込んだテキスト1行分を格納するためのchar配列を指定します int piyo[11][1440]; //*filename : 開くファイル名を指定 char *fname = "./test1/test2/201509/test.csv"; //ファイルが無かったり,指定フォルダでなければ、FILE変数fpはNULLが返ります。 fp = fopen(fname, "r"); //NULLが返ってきた場合の処理 if (fp == NULL) { printf("%sファイルが開けません¥n", fname); return -1; } //ファイルから1行ずつ読み込む成功すると、読み込んだ文字列のポインタを返し、失敗すると、NULLを返します。 while (1 == fscanf(fp, "%c,", &hoge)) { piyo[kk][nn] = hoge; printf("[%d][%d]=%d\n", kk, nn, piyo[kk][nn]); nn++; if (1440 == nn) { kk++; nn = 0; } } //FILE *fp : fopen()で取得したファイルポインタ fclose(fp); return 0; }

  • 2次元配列への格納方法について

    こんにちは。 FILE *fp; SIZE 1024; int n; char Buf[1025]; while((n = fread(Buf,1,SIZE,fp)) != 0){ } というように、fread関数を用いて1024バイトずつ配列Bufへ格納しています。 以下に示すようなことを行う場合、どのように記述すればよいのでしょうか? B:バイナリデータ T:数値 TBBBBBBBBB・・・・・・B←1024バイト目 TBBBBBBBBB・・・・・・B ・ ・ ・ ・ TBBBBBBBBB・・・・・・B というように、配列内に格納したいと思っています。 Tは、テキストデータで1,2,3・・・・100という整数型を格納。Bは、バイナリデータでfread関数から取得したバイナリデータを格納します。 なぜ、Tを格納したいかといいますと、どのバイナリデータを指しているか?を判別するためです。 上記のようなことを行うためには、2次元配列を使用すればよいのでしょうか? 例:char Buffer[100][1025]

  • 2次元の配列にデータを格納したい

    hoge.txtの様なファイルがあって、この値を2次元の配列に格納したいのですが、簡単に実現することは可能でしょうか? open (FILE, "hoge.txt"); foreach (<FILE>) { # この中で、2次元の配列に格納したい } hoge.txt A  1 B  2 C  3

    • ベストアンサー
    • Perl

専門家に質問してみよう