C динамическая структура (malloc и free) - PullRequest
2 голосов
/ 29 декабря 2010

Я пытаюсь изучить основы программирования на C, C ++, поэтому я начал с "C".У меня большой опыт программирования на Java и VB.Но «С» - это то, что я хочу выучить.Поэтому у меня возникла проблема: я пытаюсь понять функции "malloc" и "free".

Я использую Borland C ++ 4.5 и Visual C ++ 6.0 в Windows 98. - (Просто среда тестирования, хочуизучите очень простое и раннее программирование Windows).

См. этот код:

struct String
{
 char *value;
 int length;
};
char *initString(const char *value)
{
 char *str = (char*)malloc( strlen(value)+1 );
 strcpy(str, value);
 return str;
}

struct String *InitString(const char *text)
{
 struct String *str = (struct String*)malloc( sizeof(struct String) );

 str->value = initString(text);
 str->length = strlen( str->value );
 return str;
}
void freeString(struct String *str)
{
 free(str->value);
 free(str);
 str = NULL;
}
int main(int argv, char *argc[])
{
 struct String *theString = InitString("Testring string struct");

 printf("String: %s\n", theString->value);
 printf("String Length: %d\n", theString->length);

 freeString(theString);

 printf("\nData: %s", theString->value);

 return 0;
}

Когда эта программа запускается, результат верный.", функция освобождает память и устанавливает для структуры значение NULL внутри функции" freeString () ", что должно освободить" theString "внутри" main () ", когда я передаю указатель на" theString ", но когдафункция возвращает: «theString» не является «NULL».

В Borland 4.5 я все еще могу вызвать «printf» с «theString-> value», и она печатает строку.В Visual C ++ происходит сбой программы при вызове «printf» - НО «theString» все еще не «NULL».Когда я отслеживаю программу в режиме отладки, "struct" освобождается внутри функции "freeString ()", а для структуры устанавливается значение NULL, но когда функция возвращает, "theString" не равно NULL, а "value" равновсе еще можно использовать на Borland, но не на Visual C ++.

Итак, я пытаюсь понять, что здесь происходит?Есть ли какая-то де-ссылка, которую следует сделать?

Заранее спасибо!

Ответы [ 5 ]

4 голосов
/ 29 декабря 2010

Это одна из причин, по которой вам никогда не следует использовать указатель после освобождения памяти, на которую он указывает. Поведение не определено, и это именно то, что вы видите здесь.

3 голосов
/ 29 декабря 2010

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

Вероятно, что произойдет: msvc, по крайней мере, в режиме отладки, обнуляет или записывает специальный байт в свободную память, поэтому указатель значения str-> становится недействительными вылетает при разыменовании, а borland просто освобождает память обратно в пул памяти, но оставляет ее нетронутой.

Ваш str=NULL в функции

void freeString(struct String *str)
{
 free(str->value);
 free(str);
 str = NULL;
}

не имеет никакого реального эффекта.Он просто устанавливает локальное значение str в NULL, вызывающий не затрагивается.

Если вы хотите установить указатель вызывающего в NULL, вы должны передать указатель на этот указатель или вв случае C ++ передайте ссылку на указатель.

void freeString(struct String *&str) //c++
{
 free(str->value);
 free(str);
 str = NULL;
}


void freeString(struct String **str) //c, call it as freeString(&theString);
{
 free((*str)->value);
 free(*str);
 *str = NULL;
}
1 голос
/ 29 декабря 2010

C - это вызов по значению. Что бы установить на NULL, если бы вы позвонили freeString(anotherFunction(theString))?

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

Idiomatic C99 просто пропустит присвоение str = NULL в freeString().

0 голосов
/ 29 декабря 2010

Вы пытаетесь получить доступ к освобожденному полю. И это приводит к неопределенному поведению. Вы можете получить доступ к значению, несмотря на то, что оно выпущено некоторыми компиляторами, потому что это конкретное поле не сбрасывается никаким другим запущенным приложением. Даже в X-Code это работает хорошо, но не в компиляторе Visual Studio.

0 голосов
/ 29 декабря 2010

Фактически, кто должен передавать в аргумент адрес указателя, а не только указатель

void freeString( struct String **str)
{
  ...
  *str=NULL;
}

В противном случае вы устанавливаете в NULL копию указателя str, а не str ...

И в main () не забудьте проверить NULL-указатель, чтобы избежать сбоя:

if (theString!=NULL)
  printf("\nData: %s", theString->value);
...