segfault при динамическом выделении памяти в C - PullRequest
0 голосов
/ 08 сентября 2011

Я пытался построить приоритетную очередь в C.Прежде всего, я делаю некоторые работы по инициализации, такие как выделение места.Ниже приведена процедура Initialize и PriorityQueue - указатель.

void Initialize(int MaxElement, PriorityQueue H)
{
   if (MaxElement < MinPQSize)
     printf("Priority queue size is too small");

   if (!(H = (PriorityQueue)malloc(sizeof(struct HeapStruct))))
     printf("Out of space!!!");

   if (!(H->Elements = (ElementType *)malloc((MaxElement+1) * sizeof(ElementType))))
     printf("Out of space!!!");

   H->Capacity = MaxElement;
   H->Size = 0;

   H->Elements[0] = MinData;
}

Вот как выглядит тестовый код

 int MaxElement = 15;
 PriorityQueue myHeap;
 Initialize(MaxElement, myHeap);

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

 PriorityQueue Initialize(int MaxElement, PriorityQueue H)
 {
   ...
   return H;
 }
 myHeap = Initialize(MaxElement, myHeap);

Так что же происходит под капотом?Вызывается ли free (), когда функция возвращается без возвращаемого значения?Спасибо заранее!

Ответы [ 2 ]

6 голосов
/ 08 сентября 2011

Нет, хотя H, который вы передаете, является указателем, вы пытаетесь изменить его внутри функции (с вашим первым malloc). Чтобы что-то изменить, нужно передать указатель на это. В данном случае это означает указатель на указатель:

void Initialize (int MaxElem, PriorityQueue *H) {
    if (MaxElem < MinPQSize)
        printf("Priority queue size is too small");

    if (!(*H = (PriorityQueue)malloc(sizeof(struct HeapStruct))))
        printf("Out of space!!!");

    if (!((*H)->Elements = (ElemType *)malloc((MaxElem+1) * sizeof(ElemType))))
        printf("Out of space!!!");

    (*H)->Capacity = MaxElem;
    (*H)->Size = 0;
    (*H)->Elements[0] = MinData;
}

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

Пара других моментов, которые вы можете рассмотреть:

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

Хотя, если честно, мне действительно нравятся версии, которые возвращают значение (без необходимости передавать его заранее, поскольку вы явно создаете new вещь). Примерно так должно поступить:

PriorityQueue Initialize (int MaxElem) {
    PriorityQueue H;

    if (MaxElem < MinPQSize) {
        printf("Priority queue size is too small");
        return NULL;
    }

    if (!(H = malloc(sizeof(*H)))) {
        printf("Out of space!!!");
        return NULL;
    }

    if (!(H->Elements = malloc((MaxElem+1) * sizeof(ElementType)))) {
        printf("Out of space!!!");
        free (H);
        return NULL;
    }

    H->Capacity = MaxElem;
    H->Size = 0;
    H->Elements[0] = MinData;

    return H;
}

PriorityQueue myHeap = Initialize (MaxElement);
1 голос
/ 08 сентября 2011

Вы передаете указатель по значению, позвольте мне проиллюстрировать:

char* c = 0;

void set_c(char* ptr)
{
    ptr = (char*) malloc(sizeof(char) * 10);       
}

// a copy of c is sent in, 
set_c(c);
// c doesn't point to the newly allocated data!

Чтобы установить его правильно, вы должны передать указатель BY указатель, например:

void set_c_correctly(char** ptr)
{
   *ptr = (char*) malloc(sizeof(char) * 10);
}

// a pointer to c is passed in
set_c_correctly(&c);

// now c points to the newly allocated data
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...