Ошибка сегментации со списком C, когда не используется глобальный список - PullRequest
1 голос
/ 10 июля 2020

Я написал код, создавая односвязный список, а затем преобразовал его в динамический c массив в C.

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

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

Кто-нибудь может сказать мне, почему это не сработает, если я хочу передать список в качестве параметра функции и, таким образом, иметь возможность создавать несколько списков?


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

typedef struct NodeStruct* Node;
typedef struct NodeStruct {
Node next;
int val;
} NodeStruct;
typedef Node List;



Node newNode(int x){
    Node n = (Node)malloc(sizeof(NodeStruct));
    if(n!=NULL){
        n->val = x;
        n->next = NULL;
        return n;
    }
    else{
        printf("ERROR: Could not allocate memory!\n");
    }
    exit(1);
}

void prepend(List l, Node node){
    if (l == NULL) l = node;
    else{
        node->next = l;
        l = node;
    }
}

void printList(List l){
    if(l!=NULL){
        Node n = l;
        while(n->next != NULL){
            printf("%d, ", n->val);
            n = n->next;
        }
        printf("%d\n", n->val);
    }
    else{
        printf("ERROR: List empty!\n");
    }
}



/*=============================*/

int* arrOf(List l){
    if(l==NULL){
        printf("ERROR: List empty\n");
        exit(1);
    }

    int size = 0;
    Node n = l;
    while(n!=NULL){
        size++; 
        n = n->next;
    }
    
    int* arr = (int*)malloc((size+1)*sizeof(int));
    n = l;
    int i = 0;
    arr[i++] = size;
    while(n != NULL){
        arr[i++] = n->val;
        n = n->next;
    }
    printf("Returning Array\n");
    return arr;
}



int main(int argc, char *argv[]){

    List l;
    
    prepend(l, newNode(5));
    prepend(l, newNode(6));
    prepend(l, newNode(7));
    prepend(l, newNode(8));
    prepend(l, newNode(9));
    prepend(l, newNode(4));
   
    printList(l);
    printf("\n===========================================\n");
    
    int* arr = arrOf(l);
    for(int i = 0; i < 10; ++i){
        printf("%d, ", arr[i]);
    }

    return 0;
}

Ответы [ 2 ]

2 голосов
/ 10 июля 2020

Когда вы инициализируете List l в main, вы не назначаете значение по умолчанию. Он хранится в стеке и не инициализируется. Это означает, что значение не определено и не обязательно равно null.

Когда вы создаете List l глобально, переменная сохраняется в сегменте bss и инициализируется значением null.

Измените свое объявление List l на:

List l = NULL;
1 голос
/ 10 июля 2020

Эта функция

void prepend(List l, Node node){
    if (l == NULL) l = node;
    else{
        node->next = l;
        l = node;
    }
}

работает с копией значения указателя l, объявленного в main

List l;

, которое, кроме того, не было инициализировано.

Таким образом, изменение копии в этих операторах внутри функции

if (l == NULL) l = node;
//...
l = node;

не влияет на исходное значение указателя, объявленного в main.

Вы должны написать как минимум как

void prepend(List *l, Node node){
        node->next = *l;
        *l = node;
}

и в основном

List l = NULL;

Функцию можно вызвать как

prepend( &l, newNode(5) );

То есть указатель на головной узел должен быть передан в функцию по ссылке .

Также вам необходимо освободить всю динамически выделяемую память для списка и массива.

...