链表C的分段错误

时间:2016-07-06 23:29:19

标签: c data-structures linked-list

我正在为一个类创建链接列表,但在搜索和打印时我一直遇到分段错误。我认为它与数据结构没有正确地进行malloced有关,但我尝试了很多东西,我得到了同样的错误。任何帮助都会很棒

    struct LList_data {
        int x;
        int y;
    }

    struct LList {
        struct LList_data * data;
        // data=(struct LList_data *)malloc(sizeof(struct LList_data));
        struct LList * next;
    }

struct LList * LList_create()
{
        struct LList * list;
        list = (struct LList *)malloc(sizeof(struct LList));
        list->next = NULL;
        return list;
}
    void LList_push_front(struct LList * list, struct LList_data newdata)
    {
        struct LList * node;
        struct LList_data * data;
        node = (struct LList *)malloc(sizeof(struct LList));
        data = (struct LList_data *)malloc(sizeof(struct LList_data));

        node->data = data;

        node->data->x = newdata.x;
        node->data->y = newdata.y;

        node->next=list->next;
        list->next=node;
        return;
    }

    int LList_find(struct LList * list, int x, struct LList_data * data)
    {
            struct LList * node;

    //      if(list == NULL)
    //      printf("list empty");
    //      if(!list->next==NULL)
    //      printf("list next empty");

            for(node=list->next; node!= NULL; node=node->next){
              if(x == node->data->x){
                node->data=data;
                return 1;
                }
            }

            return 0;
    }

    int LList_update(struct LList * list, struct LList_data newData)
    {
            struct LList * node;

            node = list->next;
            while(node)
            {
              if(node->data->x == newData.x)
              {
              node->data = &newData;
              return 1;
              }
              node=node->next;
            }
            return 0;
    }

    int LList_remove(struct LList * list, int x, struct LList_data * data)
    {
            struct LList * node;
            struct LList * prev;
            node = list->next;

            while(node)
            {
              prev = node;
              node = node->next;
            }
            if(node == NULL)
              return 0;

            prev->next = node->next;
            return 1;
    }

    void LList_destroy(struct LList * list)
    {
            struct LList * temp = list->next;
            struct LList * next;

            while(temp)
            {
              next = temp->next;
              free(temp);
              temp = next;
            }
            free(list);
    }

    void LList_print(struct LList * list)
    {
            struct LList * temp;
            temp=list;
            if(temp!=NULL){
            while(temp!=NULL)
              {
              printf("%d,%d",temp->data->x, temp->data->y);
              temp=temp->next;
              }
            temp->next = (struct LList *)malloc(sizeof(struct LList));
            temp->next = NULL;
            }
    }

以下是使用列表的内容

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

void menu();
void a(struct LList * list);
void c(struct LList * list);
void f(struct LList * list);
void r(struct LList * list);
void p(struct LList * list);

int main(){
        menu();
        return 0;
}


void menu()
{
        char choice;
        struct LList * list;

        list = LList_create();

        scanf(" %c", &choice);

        switch(choice){
          case 'a':
          case 'A':
                a(list);
                break;
          case 'C':
          case 'c':
                c(list);
                return;
                break;
          case 'f':
          case 'F':
                f(list);
                return;
                break;
          case 'r':
          case 'R':
                r(list);
                return;
                break;
          case 'p':
          case 'P':
                p(list);
                return;
                break;
          default:
                fprintf(stderr, "Invalid choice \n");
                menu();
                return;
        }
}

void a(struct LList * list)
{
        int x;
        struct LList_data data;

        scanf(" %d", &x);
        data.x = x;
        data.y = 0;

        LList_push_front(list,data);

        printf("%d,%d \n", data.x,data.y);

        menu();
        return;
}
void c(struct LList * list)
{
        LList_destroy(list);
        list =  LList_create();

        menu();
        return;

}

void f(struct LList * list)
{
        int x;

        struct LList_data * data;
        data=NULL;

        scanf(" %d", &x);

        LList_find(list, x, data);

        data->y += 1;

        printf("%d,%d", data->x,data->y);

        menu();
        return;
}

void r(struct LList * list)
{
        int x;
        struct LList_data * data;
        scanf(" %d", &x);

        data=NULL;

        LList_find(list, x, data);

        printf("%d,%d", data->x,data->y);

        LList_remove(list, x, data);

        menu();
       return;
}
void p(struct LList * list)
{
        LList_print(list);

        menu();
        return;
}

1 个答案:

答案 0 :(得分:0)

一些事情......

从子函数(例如menu)递归调用p并不是一件好事。在menu

中循环main要好得多

打印功能正在添加新元素?!

find函数刚刚返回0/1,但从未返回指向“found”元素的指针。

我已经注释并修复了[大部分]错误。当我这样做时(如果可能),我将原始代码保留在#if 0中,并将更正的代码保留在相应的#else部分中。注释更详细地说明了一些问题。我希望比较原始代码和修改代码是有益的。

我必须更改一些链接列表函数参数/返回值,以便它们有意义。

无论如何,这是代码,为了简单起见我合并为一个文件[请原谅无偿的样式清理]:

//#include "llist.h"
#include <stdio.h>
#include <stdlib.h>

struct LList_data {
    int x;
    int y;
};

struct LList {
    struct LList_data *data;
    // data=(struct LList_data *)malloc(sizeof(struct LList_data));
    struct LList *next;
};

struct LList *
LList_create()
{
    struct LList *list;

    list = (struct LList *) malloc(sizeof(struct LList));
    list->next = NULL;

    return list;
}

void
LList_push_front(struct LList *list, struct LList_data newdata)
{
    struct LList *node;
    struct LList_data *data;

#if 0
    node = (struct LList *) malloc(sizeof(struct LList));
    data = (struct LList_data *) malloc(sizeof(struct LList_data));
#else
    node = malloc(sizeof(*node));
    data = malloc(sizeof(*data));
#endif

    node->data = data;

    node->data->x = newdata.x;
    node->data->y = newdata.y;

    node->next = list->next;
    list->next = node;

    return;
}

#if 0
int
LList_find(struct LList *list, int x, struct LList_data *data)
{
    struct LList *node;

    // if(list == NULL)
    // printf("list empty");
    // if(!list->next==NULL)
    // printf("list next empty");

    // NOTE/BUG: this entire function is just to _find_ a node [to be used by
    // other functions], so it should _not_ try to change anything

    for (node = list->next; node != NULL; node = node->next) {
        // NOTE/BUG: this replaces node->data without freeing it first (i.e.
        // this is a memory leak)
        if (x == node->data->x) {
            node->data = data;
            return 1;
        }
    }

    return 0;
}

#else
struct LList_data *
LList_find(struct LList *list, int x)
{
    struct LList *node;
    struct LList_data *data;

    data = NULL;
    for (node = list->next; node != NULL; node = node->next) {
        if (x == node->data->x) {
            data = node->data;
            break;
        }
    }

    return data;
}
#endif

int
LList_update(struct LList *list, struct LList_data newData)
{
    struct LList *node;

    node = list->next;
    while (node) {
        // NOTE/BUG: newData is on the _stack_ and when this function returns
        // newData will go out of scope (i.e. node->data will become invalid)
#if 0
        if (node->data->x == newData.x) {
            node->data = &newData;
            return 1;
        }
#else
        // NOTE/FIX: reuse the existing data cell and populate with new data
        if (node->data->x == newData.x) {
            *node->data = newData;
            return 1;
        }
#endif
        node = node->next;
    }
    return 0;
}

int
LList_remove(struct LList *list, /*-int x,-*/ struct LList_data *data)
{
    struct LList *node;
    struct LList *next;
    struct LList *prev;

    prev = NULL;

    // NOTE: passing "x" really not required since "data" points to the node
    // to be removed

    for (node = list->next;  node != NULL;  node = next) {
        next = node->next;
        if (node->data == data)
            break;
        prev = node;
    }

    if (node != NULL) {
        if (prev != NULL)
            prev->next = next;
        else
            list->next = next;
        free(node->data);
        free(node);
    }
}

void
LList_destroy(struct LList *list)
{
    struct LList *temp = list->next;
    struct LList *next;

#if 0
    // NOTE/BUG: this does _not_ free the data associated with each list
    // element (i.e. a memory leak)
    while (temp) {
        next = temp->next;
        free(temp);
        temp = next;
    }
#else
    while (temp) {
        next = temp->next;

        free(temp->data);
        free(temp);

        temp = next;
    }
#endif

    free(list);
}

void
LList_print(struct LList *list)
{
    struct LList *temp;

    // NOTE/BUG: a list print function has no need to add to or change the
    // list
#if 0
    temp = list;
    if (temp != NULL) {
        while (temp != NULL) {
            printf("%d,%d", temp->data->x, temp->data->y);
            temp = temp->next;
        }
        temp->next = (struct LList *) malloc(sizeof(struct LList));
        temp->next = NULL;
    }
#else
    for (temp = list->next;  temp != NULL;  temp = temp->next)
        printf("%d,%d\n", temp->data->x, temp->data->y);
#endif
}

void menu(void);
void a(struct LList *list);
struct LList *c(struct LList *list);
void f(struct LList *list);
void r(struct LList *list);
void p(struct LList *list);

struct LList *mainlist;

int
main()
{

    mainlist = LList_create();

    while (1) {
        menu();
    }

    return 0;
}

void
menu(void)
{
    struct LList *list;
    char choice;

    list = mainlist;

    printf("a -- a new element\n");
    printf("c -- recreate empty list\n");
    printf("f -- find list element and increment\n");
    printf("r -- remove element from list\n");
    printf("p -- print list\n");
    printf("menu> ");
    fflush(stdout);

    scanf(" %c", &choice);

    switch (choice) {
    case 'a':
    case 'A':
        a(list);
        break;

    case 'C':
    case 'c':
        mainlist = c(list);
        //return;
        break;

    case 'f':
    case 'F':
        f(list);
        //return;
        break;

    case 'r':
    case 'R':
        r(list);
        //return;
        break;

    case 'p':
    case 'P':
        p(list);
        //return;
        break;

    default:
        fprintf(stderr, "Invalid choice \n");
#if 0
        menu();
        return;
#endif
        break;
    }
}

void
a(struct LList *list)
{
    int x;
    struct LList_data data;

    printf(" Enter value to add: ");
    fflush(stdout);
    scanf(" %d", &x);

    data.x = x;
    data.y = 0;

    LList_push_front(list, data);

    printf("%d,%d \n", data.x, data.y);

#if 0
    menu();
    return;
#endif
}

struct LList *
c(struct LList *list)
{

    LList_destroy(list);

    // NOTE/BUG: "list" goes out of scope, so recreating it here has no useful
    // effect without returning the value
    list = LList_create();

#if 0
    menu();
    return;
#endif

    return list;
}

void
f(struct LList *list)
{
    int x;

    struct LList_data *data;

    data = NULL;

    printf(" Enter value to find/increment: ");
    fflush(stdout);
    scanf(" %d", &x);

    data = LList_find(list, x);
    if (data != NULL) {
        data->y += 1;
        printf("%d,%d\n", data->x, data->y);
    }

#if 0
    menu();
    return;
#endif
}

void
r(struct LList *list)
{
    int x;
    struct LList_data *data;

    printf(" Enter value to remove: ");
    fflush(stdout);
    scanf(" %d", &x);

    data = NULL;

    // NOTE/BUG: "data" will always be null because LList_find never set it
    // to anything
#if 0
    LList_find(list, x, data);
    printf("%d,%d\n", data->x, data->y);
#else
    data = LList_find(list, x);
    if (data != NULL) {
        printf("%d,%d\n", data->x, data->y);
        LList_remove(list, data);
    }
#endif

#if 0
    menu();
    return;
#endif
}

void
p(struct LList *list)
{
    LList_print(list);

#if 0
    menu();
    return;
#endif
}