• ベストアンサー

ファイルの読み込みとメモリ確保について。

ファイルから文字を読み込んで それを配列に入れて辞書順にソートさせようとしています。 それで、ソート以前の問題なのですが、ファイルから文字列を読み込んで配列にいれようとするのですが、 buffを動的にメモリ確保してその配列に入れたいと考えているのですが、なぜか入ってくれません。 whileでファイルの終わりがくるまで一行ずつ読み込んで それをsに入れていき、sをbuff[]の配列に順番にいれていこうとしているのですが・・・。 ファイルは aaaa aabc dda wer zie ced sdfe be など適当な文字の並びです。 malloc関数で動的に確保したメモリはその後普通の配列と同様に使えるのではなかったのでしょうか? なので普通にbuff[i]=s;といった処理で入れれると思ったのですが。 ファイルは一行の長さの最大が100で 行数が4000行あると仮定しています。 今は小さいファイルでテストしていますが。 以下ソースです。 #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 #define MAX_LINE 4000 main() { FILE *fp; char *buff,s[MAX_SIZE]; int i; fp=fopen("words.txt","r"); buff=(char*)malloc(sizeof(char)*MAX_LINE); i=0; while(fgets(s,MAX_SIZE-1,fp)!=NULL){ buff[i]=s; printf("%s",buff[i]); i++; } fclose(fp); } とりあえずファイルの内容を配列に入れないとソートできないので、配列に全て入れてしまいたいと考えています。 間違いがどこにあるのか指摘よろしくおねがいします。m(-_-)m

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

  • ベストアンサー
  • HogePiyo
  • ベストアンサー率57% (24/42)
回答No.6

訂正と補足です。 半分寝ぼけて書いたコードなので最後のメモリの解放の部分が間違ってました。 > free( buff ); for( i = 0; i < MAX_LINE; i++ ){ free( buff[i] ); } free( buff ); さて、まず問題はファイルから一行ずつ単語を読み込んでバッファへ保存しておき、 データをソートする。 その際にファイルから読み込んだ一行の単語を動的に用意した配列へうまく保存でき ないということでしたね。順を追ってみていきましょう。 #define MAX_SIZE 100 #define MAX_LINE 4000 char *buff, s[MAX_SIZE]; まず、大前提として「C言語では文字列は char 型の配列で表す」ということがあり ます。つまり、文字列データ型を標準ではサポートしてないのです。 確か、「ファイルから文字列を一行読み込んでそれを配列に保存する」ということを したいんでしたね。 と、いうことはただ単に配列を用意するのではなく「文字列を格納する配列」の配列 を用意してやる必要があります。 #define MAX_SIZE 100 #define MAX_LINE 4000 char** buff; char s[ MAX_SIZE ]; 配列の配列のためのポインタ変数は「ポインタのポインタ」を用意してやります。 この変数へ文字列保存用へ確保したバッファのアドレスを入れてやるのです。 buff=(char*)malloc(sizeof(char)*MAX_LINE); という風になっていますが、配列の配列を用意してやるので少し手順が変わってき ます。 buff = ( char** )malloc( sizeof( char* ) * MAX_LINE ); まず、それぞれ確保する文字列バッファのアドレスを格納するためのポインタ配列 を確保してやります。 for( i = 0; i < MAX_LINE; i++ ){ buff[i] = ( char* )malloc( sizeof( char ) * MAX_SIZE ); } その後に、それぞれのポインタに文字列のためのバッファへのアドレスを配列に保 存してやることで「文字配列の配列」が確保できるわけです。 確保したメモリは使い終わったらちゃんと解放してやる必要があります。さもない とメモリリークの原因となってしまいますから。 具体的にどうするかというとメモリの確保と逆の手順を踏みます。 for( i = 0; i < MAX_LINE; i++ ){ free( buff[i] ); } ポインタ配列に入っているそれぞれの文字列用のバッファを解放する。 free( buff ); 最後にポインタ配列を解放する。 さて、次に文字列のコピーですが、先に述べた通りC言語では文字列をサポートし ていません。 buff[i]=s; なので、ただ単に代入するだけではコピーできません。 for( j = 0; j < MAX_LINE; j++ ){ for( i = 0; i < MAX_SIZE; i++ ){ buff[j][i] = s[i]; } } このようにする必要があります。が、標準関数に文字列をコピーする関数が用意さ れていますのでそれを使いましょう。 その関数は string.h で定義されている strcpy 関数や stdio.h 出て異議されて いる sprintf 関数です。 sprintf 関数のほうが何かと使い勝手がいいのでこれを使います。 sprintf( buff[i], "%s", s ); この関数は printf 関数と同様にコンソール画面ではなくバッファへ文字列を出力 してくれます。 以上を踏まえたコードが先に投稿したソースです。 さて、ここでは単語の配列を文字配列の配列で扱いましたが、コードが結構うざく なったりします。 そんなときは文字配列を構造体として扱うとすっきりするかと思います。 #define MAX_SIZE 100 typedef struct { char str[ MAX_SIZE ]; } WORDS; WORDS* buf; buf = ( WORDS* )malloc( sizeof( WORDS ) * MAX_LINE ); sprintf( buf[i].str, "%s", str ); 一応サンプルコードを提示しておきます。 #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 #define MAX_LINE 4000 typedef struct { char str[ MAX_SIZE ]; } WORDS; int main(void){ FILE* fp; WORDS* buf; char str[ MAX_SIZE ]; int i; if( ( fp = fopen( "words.txt", "r" ) ) == NULL ){ return -1; } buf = ( WORDS* )malloc( sizeof( WORDS ) * MAX_LINE ); for( i = 0; i < MAX_LINE; i++ ){ if( fgets( str, MAX_SIZE - 1, fp ) == NULL ){ break; } sprintf( buf[i].str, "%s", str ); printf( "%s", buf[i].str ); } free( buf ); fclose( fp ); return 0; }

usui323
質問者

お礼

回答ありがとうございました!! おかげで、うまく配列に入れることができ、 配列に入れてしまってからは上手く辞書順にソートすることができました!! ポインタのポインタというのは思いつきませんでした。 こういう使い方をはじめてしたので勉強になりました。 わざわざ一行ずつ詳しい解説も書いていただき、非常にさんこうになりました! 本当にありがとうございました!(^-^)

その他の回答 (5)

  • HogePiyo
  • ベストアンサー率57% (24/42)
回答No.5

#include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 #define MAX_LINE 4000 int main(void){ FILE* fp; char** buff; char str[MAX_SIZE]; int i; if( ( fp = fopen( "words.txt", "r" ) ) == NULL ){ return -1; } buff = ( char** )malloc( sizeof( char* ) * MAX_LINE ); for( i = 0; i < MAX_LINE; i++ ){ buff[i] = ( char* )malloc( sizeof( char ) * MAX_SIZE ); } for( i = 0; i < MAX_LINE; i++ ){ if( fgets( str, MAX_SIZE - 1, fp ) == NULL ){ break; } sprintf( buff[i], "%s", str ); printf( "%s", buff[i] ); } free( buff ); fclose(fp); return 0; }

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

う~ん, リストは示しませんが, 1.ファイルの内容を一度 char の配列に入れてしまう. 2.各行の先頭を char * の配列に記憶する (ついでに各行の終端を '\0' に変える). 3.各行をソートする. の順でいけませんかね. 1.はあらかじめファイルの大きさがわかっていれば簡単 (fread) ですし, 2.も例外的な状況を考えなければわりと簡単にできるはずです. 2次元配列を使うなら char **lines; lines = malloc(MAX_LINE * sizeof lines[0]); for (i = 0; i < MAX_LINE; i++) { lines[i] = malloc(MAX_SIZE); } のようにメモリを確保しておく方が使い勝手はよいです. あと, buff という名前の配列に対しては &buff[i] と buff+i が同じ意味になります. ちなみに 「char buff[10000]ととっておいて, buff[0], buff[100]は, 問題ありませんが, ポインターに対しては, このような使い方はできません.」などと書かれていますが, char *buff でも十分なメモリを確保していれば全く同じように使えます... というか, 使えないと char buff[10000] のときに問題になる.

usui323
質問者

お礼

回答ありがとうございます。 なるほど、freadでできるんですね、fgetsよりそっちのほうがいいかもしれませんね。 &buff[i] と buff+i が同じなんですね、今理解できました。 ありがとうございました。m(-_-)m

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.3

#2です。 >buff[0]とかbuff[100]とかの書き方ではダメなのですか? buffはchar *buffと宣言しています。 buffはポインターですから、buff+jがbuffの先頭+jの位置を示します。 char buff[10000]ととっておいて、buff[0],buff[100]は、問題ありませんが、ポインターに対しては、このような使い方はできません。 >いっそのこと、2次元配列を使った方が分かりやすいですかね? mallocで4000×100バイトを確保すること自体が、考え方としては2次元配列の考え方になっています。 char buff[4000][100];として領域を確保すれば、本来の2次元配列になります。考え方としては、これが最もシンプルです。 strcpy(buff[i],s)で、データが格納出来ます。 但し、char buff[4000][100];はmain関数の内部で宣言するとサイズが大きすぎる為(たぶん)エラーになるでしょう。mainの外側で宣言して下さい。

usui323
質問者

お礼

再度回答ありがとうございました。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.2

提示されている方法では、4000個×4バイトのメモリを割り当てているだけですので、あなたの望んだ結果は得られません。 1.連続したメモリに格納するためには、メモリは4000行×100バイト必要になります。 2.上記で確保したメモリを100バイト単位で1行毎に使用します。 以下は、そのように修正した結果です。 ----------------------------------- #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_SIZE 100 #define MAX_LINE 4000 #define ALLOC_SIZE (MAX_LINE*MAX_SIZE) main() { FILE *fp; char *buff,s[MAX_SIZE]; int i; int j; fp=fopen("words.txt","r"); buff=(char*)malloc(ALLOC_SIZE); i=0; while(fgets(s,MAX_SIZE-1,fp)!=NULL){ j = i*MAX_SIZE; strcpy(buff+j,s); printf("%s",buff+j); i++; } fclose(fp); }

usui323
質問者

お礼

回答ありがとうございます。 for(i=0;i<40;i++){ printf("%d\n",i*100); printf("%s",buff+(i*100)); } をwhileの外に入れて確認したところ、100ずつの区切りで ちゃんと格納されていることがわかりました。 ですが、buff[0]とかbuff[100]とかの書き方ではダメなのですか? buff+(i*100)など+でその場所を表現するのを初めて見たもので・・・。 イマイチ、なぜこういう書き方をするのか正直わかりません。 とりあえずそういう風に指定したら入っているということは確認できましたが。 いっそのこと、2次元配列を使った方が分かりやすいですかね?

回答No.1

buff[i] の型は char s の型は char[] 両者の型が異なります。

usui323
質問者

お礼

回答ありがとうございます。 エラーメッセージの出る原因はそれだったんですね。 同じcharでも違うんですね、知りませんでした。

関連するQ&A

  • cygwinを使ってcsvファイルを読み込み、出力させようとしています

    cygwinを使ってcsvファイルを読み込み、出力させようとしています。 とりあえず、読み込みのみのプログラムを作成し、 実行させてみたのですが(run ファイル名.csv と入力) 「Error: could not start C:\cygwin\home\ユーザー名ファイル名.csv」 と出力され、読み込みができず、困っています。 プログラム初心者です。 恐縮ですがご回答よろしくお願いします。 以下に、読み込みプログラムとcsvファイルを記載します。 (プログラムは拾い物です。) <プログラム> #include <stdio.h> #define MAX_ITEM_SIZE 100 #define MAX_LINE_SIZE 1024 char *GetCSVItem(char *wp, char *buff, int size); void main(int argc, char *argv[]) { FILE *fp; char buff[MAX_LINE_SIZE], *wp, item[3][MAX_ITEM_SIZE]; int i1, len; if(argc != 2){ printf("comand error nyuuryoku keishiki\n"); return; } fp = fopen(argv[1], "r"); if(fp == NULL){ printf("can not open file[%s].\n", argv[1]); return; } for(;;){ if(fgets(buff, MAX_LINE_SIZE, fp) == NULL) break; len = strlen(buff); if(len == 0 || buff[len-1] != '\n'){ if(feof(fp) == 0){ printf("data error[%s].\n", buff); return; } } buff[len-1] = '\0'; wp = buff; if((wp = GetCSVItem(wp, item[0], MAX_ITEM_SIZE)) == NULL){ printf("error(1)\n"); break; } if((wp = GetCSVItem(wp, item[1], MAX_ITEM_SIZE)) == NULL){ printf("error(2)\n"); break; } if((wp = GetCSVItem(wp, item[2], MAX_ITEM_SIZE)) == NULL){ printf("error(3)\n"); break; } if(*wp != '\0'){ printf("error(4)\n"); break; } for(i1 = 0; i1 < 3; i1++){ printf("%d:%s\n", i1+1, item[i1]); } } fclose(fp); } char *GetCSVItem(char *wp, char *buff, int size) { int i1; buff[0] = '\0'; while(*wp == ' ' || *wp == '\t') wp++; if(*wp == '\0'){ return(NULL); } for(i1 = 0; i1 < MAX_ITEM_SIZE; i1++, wp++){ if(i1 >= size) return(NULL); buff[i1] = *wp; if(*wp == '\0'){ buff[i1] = '\0'; return(wp); } if(*wp == ','){ wp++; buff[i1] = '\0'; break; } } return(wp); } <csvファイル> 1,2,3 11,12,13 21,22,23

  • ネットで落ちていた「Excelで作ったデータ(CSVファイル)の読み込

    ネットで落ちていた「Excelで作ったデータ(CSVファイル)の読み込みプログラム」をそのままコンパイルして実行しようと思ったのですが、 sample.c: In function 'main': sample2.c:9: warning: return type of 'main' is not 'int' と、表示されてしまいます。 プログラミング初心者なので、どこが間違っているのかわかりません。 回答またはアドバイスの程、よろしくお願いいたします。 ネットで落ちていたプログラムを以下に記載します。 sample2.c #include <stdio.h> #define MAX_ITEM_SIZE 100 #define MAX_LINE_SIZE 1024 char *GetCSVItem(char *wp, char *buff, int size); void main(int argc, char *argv[]) { FILE *fp; char buff[MAX_LINE_SIZE], *wp, item[3][MAX_ITEM_SIZE]; int i1, len; if(argc != 2){ printf("コマンドの入力形式が間違っています.\n"); return; } fp = fopen(argv[1], "r"); if(fp == NULL){ printf("ファイルがオープンできません[%s].\n", argv[1]); return; } for(;;){ if(fgets(buff, MAX_LINE_SIZE, fp) == NULL) break; len = strlen(buff); if(len == 0 || buff[len-1] != '\n'){ if(feof(fp) == 0){ printf("データが不正です[%s].\n", buff); return; } } buff[len-1] = '\0'; wp = buff; if((wp = GetCSVItem(wp, item[0], MAX_ITEM_SIZE)) == NULL){ printf("エラー(1)\n"); break; } if((wp = GetCSVItem(wp, item[1], MAX_ITEM_SIZE)) == NULL){ printf("エラー(2)\n"); break; } if((wp = GetCSVItem(wp, item[2], MAX_ITEM_SIZE)) == NULL){ printf("エラー(3)\n"); break; } if(*wp != '\0'){ printf("エラー(4)\n"); break; } for(i1 = 0; i1 < 3; i1++){ printf("%d:%s\n", i1+1, item[i1]); } } fclose(fp); } char *GetCSVItem(char *wp, char *buff, int size) { int i1; buff[0] = '\0'; while(*wp == ' ' || *wp == '\t') wp++; if(*wp == '\0'){ return(NULL); } for(i1 = 0; i1 < MAX_ITEM_SIZE; i1++, wp++){ if(i1 >= size) return(NULL); buff[i1] = *wp; if(*wp == '\0'){ buff[i1] = '\0'; return(wp); } if(*wp == ','){ wp++; buff[i1] = '\0'; break; } } return(wp); }

  • csvファイルの読み込み

    fscanf関数を用いて、csvファイルの内容を構造体のそれぞれのメンバに読み込んで表示させようとしているのですが、4列目以降が上手く読み込めません。初歩的な質問で申し訳ありませんがどなたか教えてください。 ****************************ソース************************************************ #include <stdio.h> #include <string.h> #include <stdlib.h> #define SIZE 64 #define FILE_NAME "view_001_McdlData.csv" #define FILE_SIZE 819200 struct Data{ int DataNo; int FrameNo; int SampleNo; char Digital; double voltage; double trigger; double C; double D; }; int main(int argc, char *argv[]) { FILE* fp,*fo, *fi; // ファイルポインタ用 int n, i, file_size; double time,vel[FILE_SIZE]; struct Data *dat; char buff[SIZE]; if ((fp = fopen(FILE_NAME,"r")) == NULL) { printf( "file open error\n" ); exit(EXIT_FAILURE); } fseek(fp, 0, SEEK_END); file_size = ftell(fp); dat = (struct Data*)malloc(file_size); printf("malloc address= %p, file size= %d\n", dat, file_size); fseek(fp, 0, SEEK_SET); i = 0; //データの読み込み while((fscanf(fp, "%d,%d,%d,%s,%lf,%lf,%lf,%lf",&dat[i].DataNo,&dat[i].FrameNo,&dat[i].SampleNo,&dat[i].Digital,&dat[i].voltage,&dat[i].trigger,&dat[i].C,&dat[i].D)) !=EOF ){ printf("%d %d %d %s %lf %lf %lf %lf\n",dat[i].DataNo,dat[i].FrameNo,dat[i].SampleNo,dat[i].Digital,dat[i].voltage,dat[i].trigger,dat[i].C,dat[i].D); i++; } fclose(fp); return 0; } ***********************************csvファイルの内容************************************ 0,1,0,0x3F,2.270000,0.000000,-1.000000,-1.000000 1,1,1,0x3F,2.260000,0.010000,-1.000000,-1.000000 2,1,2,0x3F,2.260000,0.010000,-1.000000,-1.000000 3,1,3,0x3F,2.260000,0.010000,-1.000000,-1.000000 4,1,4,0x3F,2.260000,0.010000,-1.000000,-1.000000 5,1,5,0x3F,2.260000,0.000000,-1.000000,-1.000000 ***************************************************************************************************

  • テキストファイルの内容を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です。

  • ポインタ配列の動的確保

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #include<stdio.h> #include<stdlib.h> #define kensu 3 main() { char abc[kensu+1]={'A','B','C','\0'}; char *ptr[kensu]; int i; printf("3つの整数を入力して下さい。\n"); for(i=0;i<kensu;i++){ ptr[i]=(char*)malloc(sizeof(char)*10); if(ptr[i]==NULL){ printf("メモリの取得に失敗しました"); exit(1); } printf("整数%c:",abc[i]); fgets(ptr[i],10,stdin); if(ptr[i][strlen(ptr[i])-1]=='\n') ptr[i][strlen(ptr[i])-1]='\0'; } for(i=0;i<kensu;i++) free(ptr[i]); } ちゃんと動いているようです。 しかし、ポインタ配列の動的確保をネットで調べてみると、ポインタのポインタ(?)を使って、下記のように2度mallocしています。 #include <stdio.h> #include <stdlib.h> #define N 3 int main(void) { char** arr; int i,j; arr = (char**)malloc(N * sizeof(char*)); /* ポインタ配列を確保 */ /* 配列の要素それぞれにつき、メモリ領域を確保 */ for(i=0;i<N;i++) arr[i] = (char*)malloc(N * sizeof(char));   ・・・ ポインタの配列を宣言して、配列の各要素に動的確保するのと ポインタのポインタを宣言し、ポインタ配列を動的確保して、再度配列の要素に動的確保するのとでは、何か違いがあるのでしょうか? ポインタのポインタを宣言し、ポインタ配列を確保する必要性が良く分かっていないのです。 ネット等で調べて見たのですが、理解力がないのかよく分かりませんでした。 どうか教えてください。

  • CSVファイルの読み込み

    以下のようなCSVファイルを読み込みたいと思っています。 0.575092,0.030525 0.565324,0.018315 0.555556,0.013431 0.553114,0.013431 0.54823,0.015873 0.538462,0.013431 0.531136,0.006105 0.52381,-0.003663 0.516484,-0.010989 0.501832,-0.015873 0.489622,-0.018315 0.477412,-0.020757 0.46276,-0.020757 ・ ・ ・ 50000*2のデータで、以下のようなプログラムを使用しました。 #include <stdio.h> #include <stdlib.h> #include <string.h> /* 確保するデータ保存領域の大きさ(N行×M列) */ #define N 50000 #define M 2 /* データの区切り文字 */ #define SEP_DATA ',' int csv_read(char filename[], double csv[N][M]) { /* ファイルオープン */ FILE *fp; if( (fp = fopen(filename, "r")) == NULL ) { printf(" file open error!!\n"); return -1; } /* 1行毎に読み出し */ char line[256], *ptr; int i, j, k; i=0; while (fgets(line, 256, fp) != NULL) { printf("*%s", line); ptr = line; j=0; do{ /* line[j]から次のタブ文字までを数値に変換 */ csv[i][j] = atof(ptr); /* 次のタブ文字の位置を探す */ ptr = strchr(ptr, SEP_DATA); /* タブ文字の次の文字を示す */ if (ptr!=NULL) { ptr++; } j++; }while(ptr!=NULL && j<M); i++; } /* ファイルクローズ */ fclose(fp); return 0; } int main(int argv, char *argc[]) { char filename[256]; if( argv > 1){ strcpy(filename, argc[1]); } else { printf("Please Input Filename:"); scanf("%s", filename); } /* データ保存用の領域を確保 */ double (*csvdata)[M]; csvdata = (double(*)[M])malloc(sizeof(csvdata) * N); if ( csvdata == NULL ){ return -1; } int i,j; /* 配列の初期化 */ for( i=0; i<N; i++) { for( j=0; j<M; j++) { csvdata[i][j] = 0.0; } } /* CSVデータの読み込み */ if( csv_read(filename, csvdata) < 0 ) { return -1; } /* 配列の出力 */ for( i=0; i<N; i++) { printf("%lf", csvdata[i][0]); for( j=1; j<M; j++) { printf("\t%lf", csvdata[i][j]); } printf("\n"); } free(csvdata); csvdata = NULL; return 0; } しかし、コンパイルは通るのですが実行時にエラーが出てしまいます。 データの大きさに問題があると思うのですが、原因がわかりません。おかしな所のご指摘を頂きたいです。よろしくお願いします。

  • 文字列の動的確保とポインタ配列について

    C言語についての質問です。 現在、キーボードから文字列を読み込みファイルに保存するプログラムを作成しています。 プログラムの条件は、以下の通りです。 1: キーボードから英数字(最長でMAX_LEN(1000)-1文字)を入力して文字列(文字配列)dataに格納後、画面に表示する。 2: 入力された文字列と同じ長さの文字列を格納する領域を動的に確保し、文字列dataをその領域に コピーする。なお、必要な文字配列の長さは文字列の長さ+1バイトである。 3: 文字列endが入力されるか、入力された文字列がNUM_STRING(10)個になるまで1~2の処理を繰り返す 4: 各文字列へのポインタを格納する(char *)型ポインタの配列str_p(サイズ:NUM_STRING)を定義して利用する。 5:1~2の処理が終了した後で、メモリに格納されたすべての文字列をファイルに出力する。ファイル名はoutput.txtとし、最初の行に文字列の個数を、次の行以降に入力された順番と「逆の順番」で文字 列を出力すること。 実行例 input ->st22 st22 input->st1 st1 end ファイルの中身 2 st1 st22 現在完成しているプログラムは以下の通りです。 #include<stdio.h> #include<string.h> #include <stdilb.h> #define NUM_STRING 10 #define MAX_LEN 1000 int main (void) { int n, i; char data[MAX_LEN] = {}; char *str_p[NUM_STRING]; FILE *fp; do { printf("input->"); scanf("%s", data); if (strcmp(data, "end") == 0) { break; } else { printf("%s\n", data); n++ 2の処理 } while(n <= NUM_STRING); if ((fp = fopen("output.txt", "w")) == NULL) { fprintf(stdout, "File open error\n"); } fprintf(fp, "%d\n", n); for (i = n-1; i>0; i--) fprintf(fp, "5s\n", str_p[i]); fclose (fp); return 0; } 特に動的確保のところがよく分かりません。 回答よろしくお願いします。       

  • ファイル読み込みが上手くできません

    C言語初心者です。 現在、ファイルの情報を構造体に読込んで実行するプログラムを作成しております。 読込むファイルは700MBほど(行数は39900000行)となっており、1行ずつfscanfで読込んでいます。 400000行ごとに構造体に読込んで、処理を実行し、構造体に読込んだ全ての処理が完了したら、再度400000行読込んで・・・を繰り返すものになっております。 400000行ごとにしているためforループで100回まわすようにしているのですが、最後の1回(100回目のループ)で、99回目と同じ場所を読んできてしまいます。 つまり、最後の1回だけはファイルポインタが進んでいない状況になります。 コードは下記になります。 #define MAX_SIZE 400000 uint64_t i = 0; uint64_t fc = 0; int main(int argc, char *argv[]){ char w[] = "$write"; char r[] = "$read"; // ファイルを構造体へ格納 char filename[] = "TEST_READ_WRITE.txt"; struct TEST_DATA{ char cmd[10]; int addr; int bsize; }; FILE *fp; if ((fp = fopen(filename, "r")) == NULL){ printf("%s open error !\n", filename); exit(1); } for (int lp = 0; lp < 100; lp++){ struct TEST_DATA TD[MAX_SIZE]; // 構造体配列の宣言 for (fc = 0; fc < MAX_SIZE; fc++) { if (feof(fp)){ break; } else{ fscanf(fp, "%s %d %d\n", TD[fc].cmd, &TD[fc].addr, &TD[fc].bsize); } } while (i < MAX_SIZE - 1){ //ファイルから取得したデータによって処理を実行 if (strcmp(TD[i].cmd, w) == 0){ //書込み処理 } if (strcmp(TD[i].cmd, r) == 0){ //読み込み処理 } } printf("Finish!! \n"); } fclose(fp); return 0; } 読込むファイルはテキストデータで、 $write 25651496 152 $write 135878112 8 $read 1244848 16 のような感じのものが39900000行並んでいるものになります(数字はランダムです)。 最後の1回のみ上手くファイルポインタが進まない原因が分からずに困っています。 お気づきの方がいらっしゃいましたら、アドバイスをよろしくお願いします。

  • なぜ動かないのかわからないです。

    以下のことをしようと思いました。 (1)テキストファイルを読み込む (2)文字列を半角全角を区別しないで済むワイド文字列に変換する (3)デバッグとして、各配列に格納された文字列、文字数、を表示させる この(1)~(3)を行うために以下のようなプログラムを組んでみました。 // ファイルを読み込む #include <stdio.h> #include <string.h> #include <stdlib.h> #include <locale.h> #define LineMax 30000 int main(void){   char FileName[] = "ReadFile.txt";   wchar_t *FileContents[LineMax];  // ワイド文字列格納用配列   char buff[512];  // ファイル読み込み一時領域   int i, buffstrLen;   int FileLineNo = 0;   int FileContentsCharCount[LineMax];   FILE *fp;   // Cロケールカら地域ロケールに変換   setlocale(LC_ALL, "Japanese");   // ファイルを読み込む   fp = fopen(FileName, "r");   if(fp == NULL){     printf("\"%s\"ファイルの読み込みに失敗しました。\n", FileName);     exit(1);   }      // 一行ずつファイルを変数に格納していく   // 無限ループ(ファイルの最後まで)   while(1){     // ファイルから一行読み込み     if(fgets(buff, 512, fp) == NULL){       break;     }     // 一行の長さを計算する(バイト数)     buffstrLen = strlen(buff);     // 領域を確保     FileContents[FileLineNo] = (unsigned short *)malloc(buffstrLen);     if(FileContents[FileLineNo] = NULL){       puts("領域の確保に失敗しました。");       exit(1);     }     // ■間違い?■ワイド文字にした上で、FileContentsポインタ配列に格納する     FileContentsCharCount[FileLineNo] = mbstowcs(FileContents[FileLineNo], buff, buffstrLen);     FileLineNo++;   }   fclose(fp);   /***** ファイル読み込み完了 *****/   FileLineNo--;   printf("ファイルには%d行ありました\n", FileLineNo);   for(i=0; i<FileLineNo; i++){     // i 行目の文字数     printf("DEBUG:FileContents[%03d]の文字数%d文字\n", i, FileContentsCharCount[i]);     // i 行目の文字内容     printf("DEBUG:FileContents[%03d]の内容:%s\n", i, FileContents[i]);   }   return 0; } ■間違い?■で示した部分でFileContents[FileLineNo]の中に、buff配列に一時的に格納した文字列が入っていないように思いました。 文字数は、バイト数ではなく、全角半角区別なく単純な文字数として表示されるのに、読み込み内容が全く表示されないのです(すべて(null)) 無駄な領域をなくすために、毎回バイト数を計算し、その都度mallocで領域を取得して、そこの領域にコピーしているはずなのに… 私の現在の知識量では、解決する策が全く思いつかなかったので、どなたか詳しい方助けてください。 よろしくお願いします。

  • 画像を読み込む配列の確保。

    C言語について質問です。 画像を読み込む時、その画像の幅、高さを入力し、そのサイズに見合った配列を確保します。その後ファイル名を入力し、配列に読み込むプログラムを作成しました。 メインの部分のみ記述します。 int xsize, ysize, i; unsigned char **src; char filename[30]; FILE *fp; printf("ファイル名を入力してください:"); scanf("%s", filename); printf("画像の幅:");scanf("%d", &xsize); printf("画像の高さ:");scanf("%d", &ysize); src = (unsigned char **)malloc(sizeof(unsigned char *) * ysize); for(i=0; i<ysize; i++) src[i] = (unsigned char *)malloc(sizeof(unsigned char) * xsize); fp = fopen(filename, "rb"); fread(src[0], sizeof(unsigned char), xsize * ysize, fp); このように記述し、エラーもなく実行できたのですが、srcをこのまま出力すると変?な画像となって出力されてしまいました。 上のように記述した場合、矛盾する場所はあるでしょうか? そして、この方法以外に配列を確保する方法はあるでしょうか?

専門家に質問してみよう