0

ファイルの行を逆にすることを目的とした、書き込もうとしているCプログラムがあります。私はまだCが苦手なので(Javaのバックグラウンドを持っていますが)、ポインタなどを間違える可能性が非常に高いですが、毎回マニュアルを参考にしてみました。これはやや課題です。

プログラムのポイントは、ファイルの内容を最大でMAX_LINESまで反転し、各行がMAX_CHARSを超えないようにすることです。私が試したかった方法は次のとおりです。fgetsを使用してファイルから80文字またはEOLまで読み取り、その文字列を保存し、側面のカウンターを使用してEOFまたはMAX_LINESに達するまでプロセスを繰り返します。その後、second_array [counter]から0に変更して、同じ文字列を別の配列に配置するだけです。ただし、実際に文字列を最初の配列に入れる際に問題が発生します。これが私がこれまでに持っているものです:

1 #include <stdio.h>
2 #include <string.h>
3
4 #define MAX_LINES 100
5 #define MAX_CHAR 80
6
7 int main(int argc, char *argv[])
8 {
9         if(argc != 2)
10                 goto out;
11         FILE *fp;
12         char *str[MAX_CHAR];
13         char buffer[MAX_CHAR];
14         char *revstr[MAX_CHAR];
15         int curr_line = 0, i = 0, j =0;
16
17         fp = fopen(argv[1],"r");
18
19         out:
20         if (fp == NULL && argc != 2){
21                 printf("File cannot be found or read failed.\n");
22                 return -1;
23         }
24
25         /* printf("This part of the program reverses the input text file, up to a  maximum of 100 lines and 80 characters per line.\n The reversed file, from the last (or    100th) line to the first, is the following:\n\n"); */
26
27         /* fgets reads one line at a time, until 80 chars, EOL or EOF */
28         while(curr_line < MAX_LINES && ((fgets(buffer, MAX_CHAR, fp)) != NULL)){
29
30                 str[i] = buffer;
31                 ++j;
32                 ++i;
33         }
34
35         for(i = 0; i < 4; ++i) 
36                 printf("%s \n", str[i]);
37
38
39         printf("END OF PROGRAM RUN.");
40         return 0;
41 }

同じディレクトリに、次の行を含む「txt」ファイルがあります。

is this a test
this is a test
this is not a test

ただし、プログラムをコンパイルして実行すると(./a.out txt)、次の出力が得られます。

this is not a test

this is not a test

this is not a test

END OF PROGRAM RUN.

明らかに、これは同じ場所を上書きしていることを意味しますが、これを修正する方法がわかりません(前述のように、ポインターはまだ私にはかなり異質です)。誰かがここで何が起こっているのかを明確にできますか?代わりに2Dアレイを使用する必要がありますか?どんな助けでも大歓迎です。

4

2 に答える 2

3

の誤用buffer

buffer問題は、ポインターを に保存し続けても、最後に読み取った行しか含まれてstr[i]いないことです。buffer

おそらく次を使用して、行のコピーを読み取る必要がありますstrdup()

str[i++] = strdup(buffer);

心配すべきエラー チェックがありますが、概念的には、それを処理する簡単な方法の 1 つです。

その理由を明確にしていただけますか?であるという宣言はfgets()char *fgets()現在ファイルから読み取られている行へのポインターを一時的に返すという印象を受けました!

実際にfgets()は、次の 2 つの値のいずれかを返します。

  • EOF またはその他の I/O エラーで NULL、または
  • buffer、関数に渡された文字列へのポインター。

特に、新しいストレージが自動的に作成されるわけではありません。readline()それが必要な場合は、おそらくPOSIXから見る必要があります。

したがって、毎回fgets()同じ配列を使用するように呼び出して、連続する各行の読み取りが前の行を上書きするようにします。bufferそのため、何らかの方法で各行をコピーする必要があり、それstrdup()を行う簡単な方法として私が提案した理由です。


strdup()

この関数strdup()は POSIX の一部ですが、標準 C ではありません。ただし、簡単に実装できます。

char *strdup(const char *str)
{
    size_t len = strlen(str) + 1;
    char  *dup = malloc(len);
    if (dup != 0)
        memmove(dup, str, len);
    return(dup);
}

エラー報告

gotoこのコードで簡単に実行できますが、可能な場合は避ける必要があります。二重目的のエラー メッセージは、実際には、引数を省略したり、あまりにも多くの引数を指定したりするユーザーを混乱させてしまいます。2 つの個別のエラー メッセージを提供します。1 つはプログラムの引数の数が正しくない場合、もう 1 つはファイルを開けない場合です。

if (argc != 2)
{
    fprintf(stderr, "Usage: %s file\n", argv[0]);
    exit(1);
}
fp = fopen(argv[1], "r");
if (fp == 0)
{
    fprintf(stderr, "%s: failed to open file %s (%d: %s)\n",
            argv[0], argv[1], errno, strerror(errno));
    exit(1);
}

stderrエラーはではなくで報告されるべきであることに注意してくださいstdout。それがエラー出力チャネルの目的です。

于 2013-01-22T05:54:47.660 に答える
1

あなたのコードでは、str配列の各インデックスを同じ配列バッファを指すようにしています。これが、str 配列のすべてのインデックスに対して同じ値 (バッファ内の値) を取得している理由です。このような配列を使用してコードを使用できます

#define MAX_LINES 100
#define MAX_CHAR 80

int main(int argc, char *argv[])
{
        if(argc != 2)
                 goto out;
         FILE *fp;
         char str[MAX_LINES][MAX_CHAR];
         char buffer[MAX_CHAR];
         char *revstr[MAX_CHAR];
         int curr_line = 0, i = 0, j =0;

         fp = fopen(argv[1],"r");

         out:
         if (fp == NULL && argc != 2){
                 printf("File cannot be found or read failed.\n");
                 return -1;
         }

         /* printf("This part of the program reverses the input text file, up to a  maximum of 100 lines and 80 characters per line.\n The reversed file, from the last (or    100th) line to the first, is the following:\n\n"); */

         /* fgets reads one line at a time, until 80 chars, EOL or EOF */
         while(curr_line < MAX_LINES && ((fgets(buffer, MAX_CHAR, fp)) != NULL)){

                 //str[i] = buffer;
                 memcpy(str[i], buffer, strlen(buffer));
                 curr_line++;
                 ++j;
                 ++i;
         }

         for(i = 0; i < 4; ++i) 
                 printf("%s \n", str[i]);


         printf("END OF PROGRAM RUN.");
         return 0;
 }

また、変数currn_lineを変更していません

于 2013-01-22T06:24:47.667 に答える