• ベストアンサー

配列のメモリの確保

先日メモリについてご質問させていただいたものですが、 今ファイルから読み込んだ文字列を配列に格納する作業を行なっています。 今は char buf[1000]; FILE fp; if((fp=fopen("○○.txt","r")) ==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) != NULL){ としてファイルを一行ずつ読み込んでその後単語ごとに配列に組み込みます このときファイルの文字列を格納する配列はbuf[1000]ですが このメモリでは足りないかもしれませんし多すぎるかもしれません。 足りない場合はエラーになるし多すぎる場合はメモリの無駄ですよね。 このような場合はメモリを取り直すべきなのでしょうか?その場合 どのような方法がありますか?調べてもint型の領域確保とかそういうのはあるんですがファイルから読み込んだ文字列の領域確保とかは見つからなかったので教えて下さい。

  • zaqwe
  • お礼率15% (19/123)

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

  • ベストアンサー
  • trapezium
  • ベストアンサー率62% (276/442)
回答No.3

いくつも方法はありますが、 簡単に処理するのであれば、fgets()したあと len = strlen(buf); if (len > 0 && buf[len - 1] != '\n') でエラーメッセージを表示して終了してしまうことです。 一行の長さ無制限としたいのであれば、単語の格納処理で'\n'が見つからなければ、その時点のbufへのポインタをptrとしたとき off = 0; while (fgets(buf + off, sizeof(buf) - off, fp) != NULL) { ...processing... off = strlen(ptr); if (off > 0 && ptr[off - 1] != '\n') strncpy(buf, ptr, --off); } などとしてbufに読み足す方法があります。この場合実際はfread()使う方が効率的だとも思います。

zaqwe
質問者

お礼

ありがとうございました。

その他の回答 (2)

  • kot_o
  • ベストアンサー率16% (6/36)
回答No.2

通りすがりです。 256で十分ではないでしょうか。 文字列は、一行までしか記述出来なかったっというような話を聞いたことがあり、私は、ファイルロードの際は大抵、一行256文字で読み込んでいます。 厳密に調べた事はありませんし、ファイルの仕様によって違うかもしれません。 ですので、参考意見としてください。 ちなみに、様々なテキスト形式のファイルを読んだことがありましたが、256文字で問題はありませんでした。

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.1

fgets()は改行文字が見つからなくてもエラーにはなりません。 「改行文字、EOF、バッファサイズ-1」の中で最も短く読むだけです。 また、標準では「一行全て読む」関数はありませんから、「必ず一行全部取れていないと都合が悪い」のであれば充分な大きさのバッファを確保しておくのが前提になります。 さもなければmallocとreallocを駆使して #define BLOCKSIZE 1024 int bufsize = BLOCKSIZE; char *buf = malloc(bufsize * sizeof(char)); char *read_ptr; FILE *fp; ... // この外でfpのEOF判定をしておく fgets(buf, bufsize, fp); while(strchr(buf, '\n') == NULL){ // 改行が見つかるまで繰り返す buf = realloc(buf, bufsize + BLOCKSIZE); read_ptr = buf + bufsize; bufsize += BLOCKSIZE; if(fgets(read_ptr, BLOCKSIZE, fp) == NULL) break; // 終端に来たら抜ける } ... // 最後の解放を忘れずに free(buf); こんな感じですか。エラー処理を方々端折ってますが。 これはBLOCKSIZE(1024)単位で一行に満たなかった場合にバッファを拡張しています。 なお縮小の方は考えていません、というかfgets()で行単位処理を行う時のバッファサイズは「予期される一行の最大文字数」に合わせておくのが鉄則です。

関連するQ&A

  • fgetsで2行目から文字化け

    fgetsでファイルを一行ずつ読み込みたいのですが、二行目以降が文字化けしてしまいます。 ******* ソース ******* #include <windows.h> #include <stdio.h> FILE *fp; if ((fp = fopen("textlist.txt", "r")) == NULL){ MessageBox(NULL, TEXT("ファイルを開けません"), NULL, NULL); exit (1); } while (1) { TCHAR buf[128] = {0}; if (fgets(buf, sizeof(buf), fp) == NULL) break; MessageBox(NULL,buf,NULL,NULL); } fclose(fp); ***** textlist.txt ***** あいうえお かきくけこ さしすせそ メッセージボックスの一回目は正しく"あいうえお"と表示されますが、二回目・三回目は文字化けしています。 最終的に一行ずつ分けて配列に入れたいので、fgetsで出来たらと思っています。 よろしくお願いします。

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

    ファイルから文字を読み込んで それを配列に入れて辞書順にソートさせようとしています。 それで、ソート以前の問題なのですが、ファイルから文字列を読み込んで配列にいれようとするのですが、 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

  • strtok

    strtokにて分解した文字を各変数に格納する場合 char *p; FILE *fp; char buf[1000]; if((fp = fopen("○","r"))==NULL){ return 0; } if(!fgets(buf,1000,fp)) return 0; strcpy(p, buf); number = strtok(p,","); class_type = strtok(NULL,","); name = strtok(NULL,","); subject = strtok(NULL,","); と一行の文字列を各変数に格納しています。 ファイルの一行は以下のような形式になっています。 1,A,山田,数学//番号,クラスタイプ,名前,得意教科 これで各値は変数に格納できています。 しかし このファイルはCSVファイルなのですが、空の欄があると 1,A,,数学というデータがbuf内に入っています。 この場合 number→1 class_type→A name→数学 と空欄の箇所が飛ばされてしまっています。 改善する方法がわからないのですが strtokを使わない方がいいのでしょうか?

  • メモリ

    メモリについてご質問します。 例えば char *p; p = (char *)malloc(100); とすればpに100バイトのメモリが割り当てられる・・ pに文字列を代入する場合100バイトまで格納可能である。 次にファイルからの一行のある部分の文字列を入れる場合 char *s; while(fgets(buf,1000,fp) !=NULL){ s = GetWord(・・)//何らかの文字列が返ってくる関数です とする場合このときのsについてもメモリを取得しなければなりません。 その際 s = (char *)malloc(100); while(/*省略*/){ とwhileの外でとるのか、それとも while(/*省略*/){ s = (char *)malloc(100); と中でとるべきなのかどっちでしょう? というのもwhile文の中でメモリを作成すると 1回ごとに新たなメモリをとっているのか 更新されていっているのかがわかりません。

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

    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; } 特に動的確保のところがよく分かりません。 回答よろしくお願いします。       

  • 配列を返す

    ファイルから読み込んだ一行の文字列を読み込みカンマごとに区切って 返すというプログラムを関数化することで効率を図りたいと思います。 int main() { char buf[1000]; char *str; char *bufG; //ファイルを読み込む  while(fgets(buf,1000,fp) != NULL){//一行ずつ読む str = buf;//先頭アドレスを指す     bufG = //文字列を返す関数  ・  ・  ・ } } //文字列を返す関数 {    for(i = 0; *str != ',' && *str != '\0'; i++){ if(*str == '\n'){ bufG[i] = '\0'; } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; return bufG; } 前の質問で自動変数でこの関数を抜けたら廃棄になるというのは わかったんですが(そういう警告がでました) ここからどのようにすれば求めるプログラムになりますか? 引数とかちょとわからないので関数定義を書きませんでした。 (1)ファイルをよみこむ (2)一行ずつ読み込み文字列をbufにいれる (3)ポインタstrをbufの先頭アドレスにする (4)get_word関数にてポインタをずらしていき カンマがあればそこまでの文字列を返す (5)main関数に戻り変数に代入する (6)終端文字があるまで(4)ー(5)を繰り返す。 (7)さらに行数分繰り返す これらの一連の流れをやりたいのですが わかりません。

  • ファイルを読み込むプログラムについて

    下のプログラムで分からない所がありますので、教えて頂ければと思います。宜しくお願い致します。 text = fgets(buf,256,fp);はfpのファイルから一行を読み込んでbufに格納するという処理ということは分かります。でも、while文内なので次にこの処理をする時に今度は、2行目(下の段)を読み込むはずですが、プログラム中のどこに2行目に移動させる処理があるのか分かりません。 予想ですが、text = fgets(buf,256,fp);の中にそのような意味の処理が含まれているのでしょうか? どなたかご教授お願い致します。 #include <stdio.h> int main(void) { FILE *fp; char buf[256]; char *text; char flname[256]; printf("ファイル名:"); gets(flname); fp = fopen(flname,"r"); do{ text = fgets(buf,256,fp); if(text != NULL){ printf("%s",text); } }while(text != NULL); fclose(fp); return(0); }

  • ファイルを読み込んで条件式を満たさない

    ファイルを読み込んで一部の文字列が来たら別のファイルの文字列を書き込んでもらうプログラムを作ろうとしたのですが、何故かifを使って条件分岐を試みたところ分岐してくれません。 どのようにしたら分岐しますか? 出来ればソースもお願いします。 ---ソースの内容--- #include <stdio.h> #include <string.h> void main(void){ FILE *fp,*fp2; char buf[100],buf2[100]; fp=fopen("yasa.txt","r+"); while( fgets( buf, 100, fp ) != NULL ){ if(strcmp(buf,"じゃがいも")==0){ fp2=fopen("kuda.txt","r+"); while( fgets( buf2, 100, fp2 ) != NULL ){ printf("%s",buf2); } fclose(fp2); } else{ printf("%s",buf); } } fclose(fp); } ---ソースここまで--- ---yasa.txtの内容--- きゃべつ にんじん じゃがいも だいこん セロリ ---yasa.txtここまで--- ---kuda.txtの内容--- もも オレンジ みかん ぶどう ---kuda.txtここまで---

  • fread関数および動的なメモリ確保について

    こんにちは。 ファイルオープンし、fread関数にて1バイトずつ1024個をPktBuf配列へ格納し、sendto(winsock関数でUDPソケットの関数です)で1024Byteずつ送信しています。 #define DATA 1024 FILE *fp; char PktBuf[1024] fp = fopen(SEND_FILE_NAME,"rb+"); while((n = fread(PktBuf,1,DATA,fp)) != 0) {   sendto } fread(PktBuf,1,DATA,fp)の第2引数で、1と指定しているのですが・・・HPを参考にしているとsizeof(int)やsizeof(char)などが明記されている場合があるのですが、これは移植性を気にする場合に必要なことなのでしょうか? もし、第2引数のところを1から2へ変更した場合、2Byte×1024個=2048Byteとなり、配列[1024]に格納できないことを意味するのでしょうか? 最後に、fread関数およびmallocまたはcalloc関数を用いた、動的なメモリ確保について勉強しているのですが、記述方法がわからない状態です・・・現在の記述方法で問題はないのですが、動的なメモリ確保をすることが定説?と書かれていましたので、そちらも知りたいと思っています。 よろしくお願いします。

  • C言語でファイルからの文字列抽出について

    C言語でファイルからの文字列抽出について INPUTファイルからキーワードを探し、キーワードがあった行をOUTPUTファイルに出力したいのですが、どうしたら良いかわかりません。 //一行ずつ読み込む while(fgets(buf,sizeof(buf),fp)!=NULL){ //文字列からキーワードを探す //キーワードがある一行をOUTPUTファイルに出力 } こんな感じになると思うのですが、どういうコードを書いたら良いかわかりません。 分かる方いらっしゃいましたらご回答宜しくお願いします。

専門家に質問してみよう