mallo c () не может выделить память внутри функции в C - PullRequest
2 голосов
/ 26 января 2020

Я хочу динамически распределять память внутри функции. Функция называется func_1 и объявляется следующим образом:

int func_1(int **destination);

Здесь destination - указатель на указатель. Этот указатель содержит адрес указателя, которому я хочу динамически распределять память внутри функции.

Функция func_1 имеет следующий код:

void func_1(int **destination)
{
   *destination = (int*)malloc(sizeof(int) * 10);
   for(int i = 0 ; i < 10 ; i++)
   {
      *destination[i] = i;             //segmentation fault comes HERE
   }    
}

Ниже мой main() function:

int main()
{
   int *pointer;
   func_1(&pointer);
   return 0;
}

Когда я пытаюсь запустить эту программу, я получаю ошибку ошибки сегментации (SIGSEGV). Я использовал GDB, чтобы найти источник этой ошибки, и оказалось, что линия внутри для l oop является виновником этой ошибки.

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

Я хочу знать:

  • Почему я получаю эту ошибку?

  • Как это можно исправить?

Спасибо за помощь!

Ответы [ 2 ]

1 голос
/ 26 января 2020
Оператор

[] (подписка на массив) имеет приоритет 2

* Оператор (разыменование) имеет приоритет 3

В вашем коде *destination[i] означает то же, что и *(destination[i]). Это значение неинициализировано и приводит к ошибке сегментации.

Если вы будете использовать явный приоритет операции (*destination)[i], вы получите ожидаемый результат.

void func_1(int **destination)
{
   *destination = (int*)malloc(sizeof(int) * 10);
   for(int i = 0 ; i < 10 ; i++)
   {
      (*destination)[i] = i;             //no segmentation fault
   }    
}

вы можете прочитать больше о приоритете здесь

Полный код:

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

void func_1(int **destination)
{
   *destination = (int*)malloc(sizeof(int) * 10);
   for(int i = 0 ; i < 10 ; i++)
   {
      (*destination)[i] = i;             
   }
}

int main()
{
   int *pointer;
   func_1(&pointer);
   return 0;
}
0 голосов
/ 26 января 2020

Почему я получаю эту ошибку?

Вы перезаписываете указатель destination вместо присвоения значения, возвращаемого malloc указателю , на который указывает указатель destination.

  • Вместо *destination = (int*)malloc(sizeof(int) * 10) вы должны набрать **destination = malloc(sizeof(int) * 10).
  • Вместо *destination[i] = i вы должны набрать (**destination)[i] = i.

In C оператор индекса массива [] имеет более высокий приоритет, чем оператор косвенного обращения *. Кроме того, первый ассоциативен слева направо , а второй ассоциативно справа налево .

В вашем случае это означает, что вам нужно набрать (**destination)[i] = i; вместо **destination[i] = i, потому что в противном случае [i] будет оцениваться до **, и вы в конечном итоге будете использовать wild-указатель (что приведет к очень вероятной ошибке сегментации в общем и совершенно точно в этом случае, поскольку вы ссылаетесь на нулевой указатель, когда i == 0).


Как это можно исправить?

Исправление «просто заставь это работать» - это то, что я представил выше.

Однако это не решает фундаментальную проблему с вашим кодом, которая заключается в том, что излишне сложно . Использование указателя на указатель очень подвержено ошибкам и его следует избегать. Действительно, в этом случае вообще нет необходимости использовать его.

Следующее делает именно то, что вы хотите, без всякой ненужной сложности:

int* func_1()
{
   int* destination = malloc(sizeof(int) * 10);
   for (int i = 0; i < 10; ++i)
   {
      destination[i] = i;
   }
   return destination;
}
int main()
{
   int* pointer = func_1();
   free(pointer);
   return 0;
}

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

Как я продемонстрировал выше, нет причин передавать указатель на указатель на функцию. Память, выделенная с помощью malloc, остается для вас навсегда, вам просто нужно отследить ее и освободить с помощью вызова free, когда он вам больше не нужен. То, как вы отслеживаете память, не имеет значения - в этом случае достаточно просто вернуть указатель. Изменение pointer внутри func_1 вместо перехвата возвращаемого значения функции не дает никаких дополнительных преимуществ и служит только для того, чтобы сделать код более сложным, чем нужно.


У меня сложилось впечатление, что вы несколько смущен насчет указателей, поэтому я рекомендую вам пересмотреть тему. Вот довольно четкое объяснение относительно указателей, которое также охватывает указатели на указатели (и указатели на указатели на указатели): Как работают указатели в C?


Подробнее:

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