web-dev-qa-db-ja.com

Cで文字ごとにファイルを読み取る

みなさん、CでBFインタープリターを書いていますが、ファイルの読み取りで問題が発生しました。以前は最初の文字列を読み取るためにscanfを使用していましたが、BFコードにスペースやコメントを含めることはできませんでした。

今ここに私が持っているものがあります。

char *readFile(char *fileName)
{
  FILE *file;
  char *code = malloc(1000 * sizeof(char));
  file = fopen(fileName, "r");
  do 
  {
    *code++ = (char)fgetc(file);

  } while(*code != EOF);
  return code;
}

ファイル内の次の文字をコードポインターに割り当てる方法で問題が発生することは知っていますが、それが何であるかはわかりません。
この演習のポイントであるポインターの知識が不足しています。インタープリターはすべて正常に動作し、すべてポインターを使用していますが、ファイルの読み取りに問題があります。

(後でファイルに「+-> <[]。」を読み込むだけを実装しますが、誰かがそれを行う良い方法を持っているなら、私に知らせてくれれば素晴らしいでしょう!)

前もって感謝します

27
Devan Buggay

コードには多くの問題があります:

_char *readFile(char *fileName)
{
    FILE *file;
    char *code = malloc(1000 * sizeof(char));
    file = fopen(fileName, "r");
    do 
    {
      *code++ = (char)fgetc(file);

    } while(*code != EOF);
    return code;
}
_
  1. ファイルが1,000バイトを超える場合はどうなりますか?
  2. 文字を読み取るたびにcodeを増やし、呼び出し元にcodeを返します(ただし、メモリブロックの最初のバイトを指すようになった場合でも) malloc)。
  3. fgetc(file)の結果をcharにキャストしています。結果をEOFにキャストする前に、charを確認する必要があります。

後で解放できるように、mallocによって返された元のポインターを維持することが重要です。ファイルサイズを無視しても、次の方法でこれを実現できます。

_char *readFile(char *fileName)
{
    FILE *file = fopen(fileName, "r");
    char *code;
    size_t n = 0;
    int c;

    if (file == NULL)
        return NULL; //could not open file

    code = malloc(1000);

    while ((c = fgetc(file)) != EOF)
    {
        code[n++] = (char) c;
    }

    // don't forget to terminate with the null character
    code[n] = '\0';        

    return code;
}
_

ファイルのサイズを示すさまざまなシステムコールがあります。一般的なものは stat です。

35
dreamlax

@dreamlaxから上記のコードを展開する

char *readFile(char *fileName) {
    FILE *file = fopen(fileName, "r");
    char *code;
    size_t n = 0;
    int c;

    if (file == NULL) return NULL; //could not open file
    fseek(file, 0, SEEK_END);
    long f_size = ftell(file);
    fseek(file, 0, SEEK_SET);
    code = malloc(f_size);

    while ((c = fgetc(file)) != EOF) {
        code[n++] = (char)c;
    }

    code[n] = '\0';        

    return code;
}

これにより、ファイルの長さがわかり、1文字ずつ読み取ることができます。

8
Justin

有効なブレーンファックキャラクター以外のすべてを無視する1つの簡単な方法を次に示します。

#define BF_VALID "+-><[].,"

if (strchr(BF_VALID, c))
    code[n++] = c;
2
caf

ファイルは、関数の呼び出しごとに開かれ、閉じられません

2
Mandrake

最も重要な問題は、ものを読み込むときにcodeをインクリメントし、codeの最終値を返すことです。つまり、文字列のend。おそらく、ループの前にcodeのコピーを作成し、代わりにそれを返したいでしょう。

また、C文字列はnullで終了する必要があります。読み込む最終文字の直後に_'\0'_を配置することを確認する必要があります。

注:fgets()を使用して、1回のヒットで行全体を取得できます。

2

2つのいずれかがトリックを行う必要があります-

char *readFile(char *fileName)
{
  FILE *file;
  char *code = malloc(1000 * sizeof(char));
  char *p = code;
  file = fopen(fileName, "r");
  do 
  {
    *p++ = (char)fgetc(file);
  } while(*p != EOF);
  *p = '\0';
  return code;
}

char *readFile(char *fileName)
{
  FILE *file;
  int i = 0;
  char *code = malloc(1000 * sizeof(char));
  file = fopen(fileName, "r");
  do 
  {
    code[i++] = (char)fgetc(file);
  } while(code[i-1] != EOF);
  code[i] = '\0'
  return code;
}

他のポスターが指摘したように、ファイルサイズが1000文字を超えないようにする必要があります。また、メモリの使用が終わったら、メモリを解放することを忘れないでください。

1
Prav

ここでの問題は2つあります。a)読み込まれた値をチェックする前にポインタをインクリメントし、b)fgetc()がcharではなくintを返すという事実を無視します。

最初の問題は簡単に修正できます。

char *orig = code; // the beginning of the array
// ...
do {
  *code = fgetc(file);
} while(*code++ != EOF);
*code = '\0'; // nul-terminate the string
return orig; // don't return a pointer to the end

2番目の問題はさらに微妙です-fgetcは、EOF値が可能なchsr値と区別できるintを返します。これを修正するには、EOF =チェックし、おそらくdo/whileの代わりに通常のwhileループ。

1
Chris Lutz