Malloc внутри вызова функции, кажется, освобождается при возврате? - PullRequest
16 голосов
/ 20 сентября 2008

Я думаю, что дошел до самого простого случая:

int main(int argc, char ** argv) {
  int * arr;

  foo(arr);
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

void foo(int * arr) {
  arr = (int*) malloc( sizeof(int)*25 );
  arr[3] = 69;
}

Вывод такой:

> ./a.out 
 car[3]=-1869558540
 a.out(4100) malloc: *** error for object 0x8fe01037: Non-aligned pointer
                         being freed
 *** set a breakpoint in malloc_error_break to debug
>

Если бы кто-нибудь мог пролить свет на то, где мое понимание не работает, это было бы очень признательно.

Ответы [ 5 ]

47 голосов
/ 20 сентября 2008

Вы передаете указатель по значению, а не по ссылке, поэтому, что бы вы ни делали с arr внутри foo, не будет иметь значения вне функции foo. Как писал m_pGladiator, один из способов - объявить ссылку на указатель следующим образом (возможно только в C ++, кстати, C не знает о ссылках):

int main(int argc, char ** argv) {
  int * arr;

  foo(arr);
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

void foo(int * &arr ) {
  arr = (int*) malloc( sizeof(int)*25 );
  arr[3] = 69;
}

Другой (лучше imho) способ - не передавать указатель в качестве аргумента, а возвращать указатель:

int main(int argc, char ** argv) {
  int * arr;

  arr = foo();
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

int * foo(void ) {
  int * arr;
  arr = (int*) malloc( sizeof(int)*25 );
  arr[3] = 69;
  return arr;
}

И вы можете передать указатель на указатель. Это способ передачи C по ссылке. Сложно синтаксис немного, но хорошо - вот как С ...

int main(int argc, char ** argv) {
  int * arr;

  foo(&arr);
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

void foo(int ** arr ) {
  (*arr) = (int*) malloc( sizeof(int)*25 );
  (*arr)[3] = 69;
}
6 голосов
/ 20 сентября 2008

Вы выделили arr в foo, но это значение указателя сохраняется в стеке вызовов. Если вы хотите сделать это, сделайте это так:

void foo( int ** arr) {
    *arr = (int *)malloc( sizeof(int) * 25 );
    (*arr)[3] = 69;
}

А в основном просто передайте указатель на foo (например, foo (& arr))

3 голосов
/ 20 сентября 2008

foo получает локальную копию указателя int, выделяет для него память и пропускает эту память, когда выходит из области видимости.

Один из способов исправить это, чтобы foo вернул указатель:

int * foo() {
  return (int*) malloc( sizeof(int)*25 );
}

int main() {
    int* arr = foo();
}

Другой способ - передать указатель на указатель

void foo(int ** arr) {
   *arr = malloc(...);
}

int main() {
    foo(&arr);
}

В C ++ проще модифицировать foo, чтобы принимать ссылку на указатель. Единственное изменение, которое вам нужно в C ++ - это изменить foo на

void foo(int * & arr)
1 голос
/ 20 сентября 2008

Поскольку вы передаете указатель по значению, указатель arr внутри main не указывает на выделенную память. Это означает две вещи: у вас есть утечка памяти (НЕТ, память не освобождается после завершения функции foo), и когда вы обращаетесь к указателю arr внутри main, вы получаете доступ к некоторому произвольному диапазону памяти, следовательно, вы не используете 3 распечатаны и, следовательно, free () отказывается работать. Вам повезло, что вы не получили ошибку сегментации при доступе к arr [3] внутри main.

0 голосов
/ 20 сентября 2008

Вы не можете изменить значение вашего аргумента (arr), если оно не передано по ссылке (&). Как правило, вы хотите вернуть указатель, поэтому ваш метод должен быть:

обр = Foo ();

Плохо жужу пытаться переназначить аргументы; Я не рекомендую (&) решение.

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