3

fgets と strtok() を使用してファイルを 1 行ずつ読み込み、各行の情報のリンク リストを作成しようとしています。

現在、情報を配列に入れているだけで、情報を正しく読み取る方法を見つけようとしていますが、正しく機能していません。

while(fgets) 部分では、すべてを配列に適切にロードし、出力しているようです。ただし、そのループが実行された後、配列全体を出力しようとすると、非常に奇妙な結果が得られます..これはほとんどが最後の行の一部のみであり、ほとんどの場合、完全な単語などではありません。

たとえば、私が読んでいる場合:

Simpson, Homer, Male, 1976
Simpson, Marge, Female, 1978
Simpson, Bart, Male, 2002 
Simpson, Lisa, Female, 2004 
Simpson, Maggie, Female, 2011 

最後に得られるプリントアウトは次のようなものです。

le
Simpson
 Maggie


Simpson
 Maggie
e
ale
Simpson
 Maggie
e
e
Simpson
 Maggie
 Female
 2011

どこが間違っているのか教えてください、ありがとう!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSTRINGSIZE 10
#define LINESIZE 128

struct person{
    char firstName[MAXSTRINGSIZE];
    char lastName[MAXSTRINGSIZE];
    char gender[MAXSTRINGSIZE];
    int birthYear;
    struct person *next;
} *first, *current;


int main (void){
    static const char filename[] = "Assignment1file.txt";
    FILE *myfile = fopen ( "Assignment1file.txt", "r" );

    int i=0;
    int j=0;
    int k=0;
    int l=0;
    char *result[10][4];
    char line[LINESIZE];
    char *value;

    for(i=0; i<9; i++){
        for(j=0;j<4;j++){
            result[i][j] = NULL;
        }
    }
    i=0;

    // loop through each entry in Assignment1file
    while(fgets(line, sizeof(line), myfile)){

        //load last name
        value = strtok(line, ",");
        result[i][0] = value;
        printf("%i 0 %s", i, value);


        //load first time
        value = strtok(NULL, ",");
        result[i][1] = value;
        printf("%i 1 %s", i, value);

        // load gender
        value = strtok(NULL, ",");
        result[i][2] = value;
        printf("%i 2 %s", i, value);

        // load birth year
        value = strtok(NULL, "\n");
        result[i][3] = value;
        printf("%i 3 %s", i, value);
        printf("\n");

        for(j=0;j<4;j++){
            printf("%s\n", result[i][j]);
        }


        //go to next line
        i++;
    }   

    // read out the array
    for(k=0; k<5; k++){
        for(j=0;j<4;j++){
            printf("%s\n", result[k][j]);
        }
    }

    fclose(myfile);
    return 0;
}
4

4 に答える 4

5

このコードにはいくつかの問題があります。期待どおりの動作をするようにコードをすばやく修正しました。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSTRINGSIZE 10
#define LINESIZE 128

struct person{
    char firstName[MAXSTRINGSIZE];
    char lastName[MAXSTRINGSIZE];
    char gender[MAXSTRINGSIZE];
    int birthYear;
    struct person *next;
} *first, *current;


int main (void){
    FILE *myfile = fopen ( "Assignment1file.txt", "r" );
    int i=0;
    int j=0;
    int k=0;
    int l=0;
    char *result[10][4];
    char line[LINESIZE];
    char *value;

    for(i=0; i<=9; i++){
        for(j=0;j<=4;j++){
            result[i][j] = NULL;
        }
    }
    i=0;

    // loop through each entry in Assignment1file
    while(fgets(line, sizeof(line), myfile)){
        //load last name
        value = strtok(line, ", ");
        result[i][0] = strdup(value);
    printf("last: %s\n", value);


        //load first time
        value = strtok(NULL, ", ");
        result[i][1] = strdup(value);
    printf("first: %s\n", value);

        // load gender
        value = strtok(NULL, ", ");
        result[i][2] = strdup(value);
    printf("gender: %s\n", value);

        // load birth year
        value = strtok(NULL, " \n");
        result[i][3] = strdup(value);
    printf("birth year: %s\n", value);

        //go to next line
        i++;
    }   

    // read out the array
    for(k=0; k<5; k++){
        for(j=0;j<4;j++){
            printf("%s\n", result[k][j]);
        }
    }

    fclose(myfile);
    return 0;
}

人々は、この変更の詳細についてすでにコメントしています。

于 2012-09-19T16:58:36.900 に答える
2

strtok元の文字列を変更します。したがって、保存した以前のポインターは、反復ごとに存在しなくなります。

簡単な解決策は、値を割り当ててコピーするためのstrdupを使用することです。

valueどこでも割り当てを変更するだけです:

result[i][0] = value;

に:

result[i][2] = strdup(value);
于 2012-09-19T16:55:05.797 に答える
2

strtok()内部でポインターを返すline[]ため、次の行を読み取ると、保存したすべてのポインターがファイルの最後の行が保存されている場所を指しています。

次のように、文字列の各ビットにメモリを割り当てることができます。

//load last name
value = strtok(line, ",");
result[i][0] = malloc(strlen(value) + 1);
strcpy(result[i][0], value);

余談ですが、最初にすべてを に設定するためにループは必要ありませんNULL。代わりにこれを行うことができます。

char *result[10][4] = {0};
于 2012-09-19T16:56:17.213 に答える
1

トークンが必要な場合は、トークンを別のストレージにコピーする必要があります。

strtok()行を読み込むバッファーを変更し、区切り文字を NUL 文字に置き換え、バッファー内の特定の位置 (現在のトークンの開始点) へのポインターを返します。

次の行を読み取ると、バッファーは新しいデータで満たされます。したがって、以前のデータがなくなっているため、保存したすべてのポインターは役に立ちません。

ドキュメントからの引用:

トークンの開始と終了を決定するために、関数は最初に区切り文字に含まれていない最初の文字( token の開始となる)の開始位置からスキャンします。次に、このトークンの先頭から、区切り記号に含まれる最初の文字をスキャンします。これがトークンの末尾になります

このトークンの末尾は、関数によって自動的にヌル文字に置き換えられ、トークンの先頭が関数によって返されます。

そして(私のものを強調してください):

str
切り詰める C 文字列。この文字列の内容は変更され、小さな文字列 (トークン) に分割されます。
または、null ポインターを指定することもできます。この場合、関数は、関数への以前の呼び出しが正常に終了した場所のスキャンを続行します。

delimiters: 区切り
文字を含む C 文字列。
これらは、呼び出しごとに異なる場合があります。

于 2012-09-19T16:51:54.580 に答える