Значения в массиве структур, превращающихся в значения мусора - PullRequest
1 голос
/ 02 октября 2011

У меня проблема, которая меня действительно смущает ... Ниже я вызываю функцию инициализации:

void Initialize (List *L) {
    char* initialize = "initialize";
    int i;

    for (i=0; i<MAXLISTSIZE; i++) {
       strncpy(L->items[i].name,initialize,MAXNAMESIZE);
       L->items[i].name[MAXNAMESIZE - 1] = '\0';
       L->items[i].grade = 0;
       printf("L->items[i].name = %s\n", L->items[i].name);
       printf("L->items[i].grade = %d\n", L->items[i].grade);
    }    
    L->count = 0;
}

И, похоже, работает, я печатаю значения в цикле, и это нормально. Если я также печатаю внутри идентичного цикла в main для двойной проверки, это также работает, но если я просто печатаю значения в main после функции initialize (без операторов print в Initialize), я получаю полный мусор.

Кажется, память, в которой я храню свои значения, не остается согласованной, и я не могу понять, почему.

Нужно ли распределять память по структурам? Поскольку мне не нужен переменный объем памяти, я подумал, что в этом нет необходимости ... Я не уверен, как это сделать.

Мои структуры:

typedef Student Item;
#define MAXLISTSIZE 4
typedef struct {
Item items[MAXLISTSIZE];
int count;
} List;

#define MAXNAMESIZE 20
typedef struct {
char name[MAXNAMESIZE];
int grade;   
} Student;

Я просто вызываю Initialize from main:

int main () {
    List *newList;

    /*call initialize function*/
    newList = callInitialize();

return 0;
}

callInitialize:

List *callInitialize () {
List *L;

List studentList;
L = &studentList;

Initialize(L); 

return L;
}

Ответы [ 2 ]

5 голосов
/ 02 октября 2011

Теперь, когда вы разместили функцию, которая вызывает реальную проблему, мы видим, что не так: вы возвращаете адрес локальной переменной, которая выходит за рамки! Это недействительно.

List * foo()
{
  List x;     // <--- x comes to life
  return &x;  // <--- x dies here...
}

int main()
{
  List * p = foo();  // ... but its address is used here!
  p->name ...        // dereferencing an invalid address!!
}

Ваша ситуация требует динамического (или «ручного») выделения, что означает выделение памяти, время жизни которой контролируется только вами , а не локальной областью.

List * initList()
{
  return malloc(sizeof(List)); // this memory is permanent
}

Любое ручное распределение должно сопровождаться процедурой очистки:

void freeList(List * p)
{
  free(p);
}
4 голосов
/ 02 октября 2011

Теперь, когда вы разместили оставшуюся часть кода, проблема очевидна:

List *callInitialize () {
    List *L;

    List studentList;
    L = &studentList;

    Initialize(L); 

    return L;
}

В этой функции вы создаете локальную переменную studentList, которую вы передаете Initialize для ее установки.

К сожалению, область действия переменной studentList заканчивается при выходе из функции callInitialize. Вот почему он может содержать мусор, если вы попытаетесь использовать его позже.

Несмотря на ваш комментарий о том, что malloc не нужен, поскольку структура небольшая, вам нужно это нужно, если вы хотите, чтобы область данных существовала вне функции, в которой они созданы.

Вероятно, решение "минимального изменения" будет:

List *callInitialize (void) {
    List *L = malloc (sizeof (List));
    if (L != NULL)
        Initialize(&L); 
    return L;
}

и затем запомните, что в какой-то момент вызывающая сторона должна освободить его, если только не произойдет сбой malloc, и поэтому эта функция вернет NULL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...