1

私は次のようにstruct定義しています

typedef struct
{
    char* name;
    char* ID;
    int marks;

    char* details;

} Student;

そして別の

typedef struct
{
    int n;
    Student* stud_array;
} Batch;

ファイルには特定の形式の学生のさまざまなバッチのエントリがあり、私はそのファイルから読み取ってBatchArrayタイプのデータを入力していますBatch*

各フィールドが入力された後、私は使用しています

puts(BatchArray[no_of_batches-1].stud_array[i].name);
puts(BatchArray[no_of_batches-1].stud_array[i].ID);
printf("%d\n",BatchArray[no_of_batches-1].stud_array[i].marks);

結果を確認します。そしてそれは私に正しい出力を与えます。

ただし、すべてが完了した後、繰り返し処理する場合は、各構造体BatchArrayのフィールドのみが値を保持します。とmarksはランダムなガベージ値であることが示されています。nameID

反復コードは標準です。それにもかかわらず、ここにあります。

   for(i = 0; i < no_of_batches; i++)   {
        currBSize = BatchArray[i].n;
        printf("Batch %d\n", (i+1));
        printf("Batch size %d\n", currBSize);
        for(j = 0; j < currBSize; j++)  {
            puts(BatchArray[i].stud_array[j].name);
        }
    }

私が取り組んでいる問題は、各バッチの平均点を見つける必要があるので、それは問題ではありません。しかし、他のフィールドがガベージ値にリセットされる理由を知りたいのですが。

誰かがこれを手伝ってくれる?

編集:これが私がフィールドに入力する方法です。

このファイルは、次のようなエントリで構成されています

3名前1ID1マーク1名前2ID2マーク2名前3ID3マーク32名前4ID4マーク4名前5ID5マーク5

これがコードです。

no_of_batches = 0;
            infileptr = fopen (infilename, "r");

            BatchArray = (Batch *) malloc(sizeof(no_of_batches));

            int MAX_BUFF = 100;
            char currLine[MAX_BUFF];    

            while (fgets(currLine, MAX_BUFF, infileptr) != NULL)    {

                no_of_batches++;
                BatchArray = (Batch *) realloc(BatchArray, no_of_batches*sizeof(Batch));
                currBatchSize = atoi(currLine);
                BatchArray[no_of_batches-1].n = currBatchSize;
                printf("currBatchSize : %d\n",BatchArray[no_of_batches-1].n);
                BatchArray[no_of_batches-1].stud_array = (Student *) malloc(currBatchSize*sizeof(Student));
                for(i = 0; i < currBatchSize; i++)  {
                    fgets(currLine, MAX_BUFF, infileptr);
                    currLine[strlen(currLine)-1] = '\0';

                    BatchArray[no_of_batches-1].stud_array[i].details = currLine;

                    //getting the Name from currLine
                    j = 0;
                    len = strlen(currLine);
                    char buildName[len];
                    while(currLine[j] != ' ')   {
                        buildName[j] = currLine[j];
                        j++;
                    }

                    buildName[j] = '\0';
                    BatchArray[no_of_batches-1].stud_array[i].name = buildName;

                    j++;
                    //getting the ID from currLine
                    k = 0;
                    char buildID[len];
                    while(currLine[j] != ' ')   {
                        buildID[k] = currLine[j];
                        j++;
                        k++;
                    }

                    buildID[k] = '\0';
                    BatchArray[no_of_batches-1].stud_array[i].ID = buildID;

                    puts(BatchArray[no_of_batches-1].stud_array[i].name);
                    puts(BatchArray[no_of_batches-1].stud_array[i].ID);

                    //getting the marks from currLine
                    k = 0;
                    j++;
                    char buildMarks[len];
                    while(currLine[j] != '\0')  {
                        buildMarks[k] = currLine[j];
                        j++;
                        k++;
                    }

                    buildMarks[k] = '\0';
                    BatchArray[no_of_batches-1].stud_array[i].marks = atoi(buildMarks);
                    printf("%d\n",BatchArray[no_of_batches-1].stud_array[i].marks);
                }
                puts("");
            }
4

3 に答える 3

1

フィールドnameIDは 型char*です。つまり、それらはポインターです。ロードと反復の間にそれらが指すメモリが上書きされた場合、それらはガベージを指します。この場合、スタックに割り当てられたローカル変数である配列nameの開始アドレスにフィールドを 割り当てているように見えます。buildName

2 つの選択肢があります。

  • フィールド タイプを文字の配列に変更します。欠点は、最大長を指定し、バッファ オーバーフローをチェックする必要があることです。
  • 動的メモリを使用します。strdupまたはを使用して動的メモリを使用できますmalloc。この場合、freeメモリが不要になったときに ( を呼び出して) 割り当てを解除し、メモリ リークを回避する必要があります。
于 2012-08-02T08:39:21.063 に答える
1

それ以外の

    BatchArray[no_of_batches-1].stud_array[i].name = buildName;

書きます

    BatchArray[no_of_batches-1].stud_array[i].name = strdup(buildName);

最初のケースの問題は、 が をname指していることbuildNameです。これは、スタック上の配列であり、スタックの内容が変更されるたびに上書きされます。

2 番目のケースでは、新しく割り当てられたヒープ メモリに配列をコピーし (mallocまたはのようにrealloc)、コピーするまで変更されませfreeん。

于 2012-08-02T08:53:04.413 に答える
1

私の推測では、nameandIDフィールドにメモリを割り当てていません。名前フィールドと ID フィールドはどちらも char ポインターであるため、データを入力する前にそれぞれに個別にメモリを割り当てる必要があります。

フィールドに入力しているコードを投稿すると、SOの人々はより正確な理由を与えることができます.

編集:

異なる学生の値を入力するために、同じローカル変数 buildName と buildID を使用しています。ローカル変数を構造体フィールドに割り当てると、それらに格納されるのはそれらの変数のアドレスであり、それらのアドレスの値は、ループを反復するにつれて変化し続けます。もう 1 つの問題は、関数から戻るとローカル変数がスコープ外になることです。そのため、名前と ID フィールドにメモリを割り当てるために malloc を使用するか、strdup を使用することをお勧めします (strdup の使用については、以下の ectamur の回答を参照できます)。

于 2012-08-02T08:31:39.647 に答える