2016-04-09 10 views
0

未知数の生徒レコードがバイナリで書かれたファイルから読み込み、GPAで生徒をソートしてstdoutに送信する必要があります。ポインタへのポインタにrealloc()を使用するとポインタ値が変化する

当社のソート機能は、私が学生(おそらく最良の解決策へのポインタへのポインタを使用することを選択した理由です

void insertion_sort(Student **, int); 

は?私は私の好きな学生へのポインタを送っただけかもしれないと思うようになりましたこの(&p_to_Student, n)?)

コードは、pが最初の学生名(最初の学生名)を指している最初の要素を印刷すると、私は気が散ってしまい、他の生徒は問題ありません。

私はpの値をチェックし、それがrealloc()後に変化しないが呼び出され、それはまた、pの最初の要素のアドレス(右?)だからさ。

また、Valgrindと一緒にチェックして、メモリリークに関する一連のエラーを返します。

realloc()コールがないときにコードが正常に実行されます。また、ファイルを読み終えた後にpを初期化するときもコードは正常に実行されます。だから、realloc()を正しく使用していないことと関係しているはずです。

ボーナスの質問:これは、ファイルから不明なデータエントリを読み取るための適切な方法ですか?

#include <stdio.h> 
#include <stdlib.h> 

struct student { 
    char name[30]; 
    char surname[30]; 
    double GPA; 
}; 

typedef struct student Student; 

void insertion_sort(Student **arr, int n) 
{ 
    int i,j; 

    for (i=1; i<n; i++) 
    { 
     Student *tmp = arr[i]; 

     for (j=i; j>0 && (tmp->GPA > arr[j-1]->GPA); j--) 
      arr[j] = arr[j-1]; 

     arr[j] = tmp; 
    } 
} 


int main(int argc, char **argv) 
{ 
    FILE *in; 
    Student s, *arr, **p; 
    size_t ret; 
    int i = 1, n=0, c=2; 

    in = fopen(argv[1], "rb"); 
    if (in == NULL) 
     return printf("Can't open file!\n"), 1; 

    arr = (Student*) malloc(c*sizeof(Student*)); 
    p = (Student**) malloc(c*sizeof(Student*)); 

    do 
    { 
     ret = fread(&s, sizeof(Student), 1, in); 

     if (ret) 
     { 
      if (n == c) 
      { 
       arr = (Student*) realloc(arr, (c*=2)*sizeof(Student)); 
       p = (Student**) realloc(p, c*sizeof(Student*)); 
      } 
      // when I print the value of pointer p 
      // the values is changed when realloc() is called 
      printf("p = %p\n", p); 

      arr[n] = s; 
      p[n] = arr+n; 
      n++; 
     } 

    } while (ret); 

    fclose(in); 

    // If I do this instead the program runs correctly   
    //p = (Student**) malloc(c*sizeof(Student)); 
    //for (int i=0; i<n; i++) 
    //{ 
     //p[i] = arr+i; 
    //} 

    insertion_sort(p, n); 

    for (i=0; i<n; i++) 
    { 
     printf("%2d. %-20s %-20s %7.2lf\n", i+1, p[i]->name, 
      p[i]->surname, p[i]->GPA); 
    } 

    free(arr); 
    free(p); 

    return 0; 
} 
+0

検索バーにreallocと入力するだけで、動作方法に複数のヒットが得られます。あなた自身で答えを見つけようとしなかったことは明らかです。 – Pemdas

+2

'realloc'はポインタを変更することがあります。つまり、そのポインタへのポインタはすべて無効になる可能性があります。あなたの場合、 'p'は' arr'へのポインタを保持します。あなたのソートのためだけに 'p'が必要なので、あなたがコメントしたアプローチ - ソートする前に' p'を割り振る方が良いです。'realloc'はあなたの配列がどれほど大きいかを事前に知らないと便利です。 –

+0

@Pemdas私は信じています。もし私が逃した 'realloc()'の動​​作のどの部分を指してください。 –

答えて

0

reallocポインタを変更することがあります。つまり、そのポインタへのポインタはすべて無効になる可能性があります。あなたの場合、parrへのポインタを保持します。

pの値は変更されていませんが、arrの値が変更されたときに古い値のpは有効ではなくなりました。

sizeof(stud) == 16; 
allocate arr: arr == 0x00100000; 

1st value: arr[0] = stud1;  p[0] = &arr[0]; // 0x00100000 
2nd value: arr[1] = stud2;  p[1] = &arr[1]; // 0x00100010 

reallocate arr: arr == 0x00200000; 
old address of arr is no longer valid! 

3rd value: arr[0] = stud1;  p[2] = &arr[2]; // 0x00200020 

今すぐあなたのポインタ配列は、次のようになります:あなただけのソートにpを必要とするので

p[0] == 0x00100000  // no longer valid! 
p[0] == 0x00100010  // no longer valid! 
p[0] == 0x00200020  // okay 

、アプローチを(すべてのポインタとサイズの値が構成されています)説明するために

あなたは–を並べ替える前に一度にpを割り当てるようにコメントしました–が良いです。

reallocは、配列の大きさをあらかじめあらかじめ把握していない場合にのみ有効です。したがって、アレイを構築している間は使用する必要があります。配列の作成が完了したら、arrが同じままになることを確かめるには、ポインタの配列pを作成する必要があります。

+0

'p'は内容が同じですが、' arr'は新しいメモリのチャンクなので有効ではなく、 'p'がその事実を反映しないため初期化されるため? 'realloc'はそれがするべきことをやっています。それはなぜ私が部分的な結果を得るのかを説明します( 'arr'の最新アドレスは有効です)。 –

+0

正確に。これは、あなたが知っておくべき「realloc」の問題です。しかし、ベクトルがまだ成長している入力フェーズと、割り当てられたメモリのサイズが固定されている作業フェーズを分離するのは通常簡単です。 –

+0

素晴らしい、ありがとう! –

関連する問題