Ошибка сегментации в структуре с указателем на другую структуру - PullRequest
0 голосов
/ 11 ноября 2011

У меня проблемы с моим списком ссылок.У меня struct dListNode используется в качестве узла для списка с указателем на struct data, который используется в качестве хранилища данных.

struct data{
    int payload;
};

struct dListNode{
    struct dListNode *next;
    struct dListNode *prev;
    struct data *val;
}*dHead, *dTail;

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

newDNode = (struct dListNode *)malloc(sizeof(struct dListNode)+sizeof(struct data));
printf("newnode created\n"); // this prints
newDNode->val->payload = rand() % 1000; //error here?
printf("newnode payload: %i\n", newDNode->val->payload); //seg fault before this is printed

Кроме того, я уже запустил эту строку в программе: srand((unsigned)time(NULL))

Ответы [ 4 ]

3 голосов
/ 11 ноября 2011

NewDNode не имеет связанного с ним выделения памяти.Поэтому, когда вы делаете

newDNode = (struct dListNode *)malloc(sizeof(struct dListNode)+sizeof(struct data));

, это просто выделяет память для newDnode, а не newDnode->val.Поскольку newDNode->val содержит только то, что осталось в памяти в этом месте (или, может быть, даже 0 (указатель NULL)), и вы пытаетесь присвоить значение в ячейке памяти, которая не находится ни в стеке, ни в куче, программажалуется, потому что вы пытаетесь получить доступ к неназначенной части памяти.

Вот что вы должны сделать:

newDNode = malloc(sizeof(struct dListNode));
newDnode->val = malloc(sizeof(struct data));
printf("newnode created\n");
newDNode->val->payload = rand() % 1000;
printf("newnode payload: %i\n", newDNode->val->payload);

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

2 голосов
/ 11 ноября 2011

Ваша проблема в том, что вы никогда не инициализировали указатель val:

newDNode->val->payload = rand() % 1000;

newDNode выделено, но ни одно из полей не инициализировано, поэтому разыменование val, скорее всего, вызовет ошибку сегментации.

Так что вам нужно выделить что-то для val, прежде чем вы получите к нему доступ.

newDNode = malloc(sizeof(struct dListNode));   //  Allocate "dListNode"
newDNode->val = malloc(sizeof(struct data));   //  Allocate "data"
newDNode->val->payload = rand() % 1000;

У вас есть небольшое недопонимание того, как работает распределение. Вам нужно выделить каждый указатель отдельно.

РЕДАКТИРОВАТЬ: И альтернативный подход просто не использовать указатель для val во-первых:

//  Declare struct as:
struct dListNode{
    struct dListNode *next;
    struct dListNode *prev;
    struct data val;
}*dHead, *dTail;


//  Build object like this:
newDNode = malloc(sizeof(struct dListNode));
newDNode->val.payload = rand() % 1000;
1 голос
/ 11 ноября 2011

val не указывает на действительную структуру data. Конечно, вам достаточно malloc размера, но это не значит, что val теперь внезапно является действительным указателем. Вы должны инициализировать newDNode только размером dListNode, а затем отдельно инициализировать newDNode->val, чтобы указать на некоторый допустимый кусок памяти, достаточно большой для структуры data.

В примечании к стороне вам не нужно приводить возвращаемое значение malloc. Это вещь C ++; в C void* может быть неявно преобразован в любой другой тип указателя.

Во-вторых, если вы typedef ваши типы структур, вам не нужно писать struct повсеместно при их использовании.

0 голосов
/ 11 ноября 2011

Вы никогда не устанавливаете newDNode->val, чтобы указывать на что-либо.Поэтому, когда вы пытаетесь установить newDNode->val->payload, вы разыменовываете либо нулевой указатель, либо какой-то случайный адрес (я забыл, какой).Ни один из случаев не является тем, что вам нужно.

Мне не очень нравится идея malloc'а для обеих структур в одном и том же утверждении.Но если вы настаиваете на этом, вам нужно будет сделать что-то вроде

newDNode->val = (struct data*)((char*) newDNode + sizeof(struct dListNode));

Лучший способ - изменить структуру так, чтобы val была структурой, а не просто указателем наодин.Затем sizeof(struct dListNode) включает в себя размер struct data, и вы можете получить к нему доступ, например newDListNode->val.payload, без необходимости выделять часть данных по отдельности или выполнять хитрые математические операции с указателями.(Недостатком является то, что вам придется скопировать структуры, чтобы сохранить их в массиве, поменять их местами и т. Д.)

...