简体   繁体   English

在C中排序的链表

[英]sorted linked list in C

following some forums and tutorials I wrote a code for sorted linked list. 在一些论坛和教程之后,我编写了用于排序链表的代码。 The code is causing core dump. 该代码导致核心转储。 I believe error is after line 50 where I'm trying to insert node at the end. 我相信错误是在第50行之后,我尝试在最后插入节点。 Can you please help me with the bug? 您能帮我解决这个错误吗? I'm not sure what I'm doing wrong. 我不确定自己在做什么错。 Thanks. 谢谢。

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

struct node
{
    char val;
    struct node* next;
};

struct node *start = (struct node*) NULL;

// definition of creating only first node
struct node* create(char* data)
{
    struct node* temp;
    temp = (struct node*)malloc(sizeof(struct node));
        if (start == NULL)
        {
            temp->val = data;
            temp->next = NULL;
            start = temp;
        }
    printf("List created\n");
}

struct node* insert(char* data)
{
    int i, pos;
    struct node* tempnode, *ptr;
    ptr = start;

    while(ptr != NULL)
    {
        if (data <= ptr->val)
        {
            printf("!!!Inserting before!!!\n");
            tempnode = (struct node*)malloc(sizeof(struct node));
            tempnode->val = ptr->val;
            tempnode->next=ptr->next;
            ptr->val = data;
            ptr->next=tempnode;
            break;
        }
        else if (data > ptr->val)
        {
            printf("!!!Going next!!!\n");
            ptr = ptr->next;
        }
        if (ptr == NULL) //insert behind the node
        {
            tempnode = (struct node*)malloc(sizeof(struct node));
            tempnode->val = data;
            tempnode->next = NULL;
            ptr->next = tempnode;
            printf("!!!Placed at the end!!!\n");
            break;
        }
    }
}

void display()
{
    struct node* ptr; // ptr is pointer
    ptr = start;
    while (ptr != NULL)
    {
        printf("%s->", ptr->val);
        ptr = ptr->next;
    }
    printf("End of list\n");
}

int main()
{
    char* data;
    int i = 0;

    create(0);
    FILE* file = fopen("words.txt", "r");

    while (i < 10)
    {
        fscanf(file, "%s", &data);
        printf ("data is %s\n", &data);
        insert(data);
        i++;
    }
    display();

}

Here, at the bottom of your insert function, you have guaranteed that ptr is NULL, but yet you do ptr->next = ... . 在这里,在insert函数的底部,您已保证ptr为NULL,但您仍然要进行ptr->next = ... This is equivalent to (*ptr).next = ... which dereferences a NULL pointer! 这等效于(*ptr).next = ... ,它取消引用NULL指针!

if (ptr == NULL) //insert behind the node
    {
        tempnode = (struct node*)malloc(sizeof(struct node));
        tempnode->val = data;
        tempnode->next = NULL;
        ptr->next = tempnode;
        printf("!!!Placed at the end!!!\n");
        break;
    }

Local variables are never initialized, their values are indeterminate (and will seem to be random). 局部变量永远不会被初始化,它们的值是不确定的(并且似乎是随机的)。 Using uninitialized local variables leads to undefined behavior . 使用未初始化的局部变量会导致未定义的行为

Now look at the data variable in the main function: It's uninitialized, and therefore can't be used until you actually make it point somewhere. 现在看一下main函数中的data变量:它是未初始化的,因此在您将其实际指向某个位置之前无法使用。 Since you don't do that you have undefined behavior. 由于您不这样做,所以您有未定义的行为。 You also use it wrongly in the fscanf call, as you pass the address of the pointer to fscanf . 你还在错误地使用它fscanf调用,如您通过指针的地址fscanf While the arguments should be pointers, data already is a pointer. 尽管参数应该是指针,但data已经是指针。 You just need to allocate memory for it. 您只需要为其分配内存。 This is simplest done by making it an array instead of a pointer: 这是通过使它成为数组而不是指针来完成的最简单的操作:

char data[128];

There are also some other problems, like you using the comparison operators like <= to compare strings. 还有其他一些问题,例如您使用<=类的比较运算符来比较字符串。 This will only compare the pointers. 这只会比较指针。 Use strcmp to compare strings. 使用strcmp比较字符串。 Another problem is that even when you fix the above, it will not work as you expect, and that is because you use the same string pointer for all nodes. 另一个问题是,即使修复了上述问题,它也无法按预期工作,这是因为对所有节点都使用了相同的字符串指针。 You need to duplicate the strings when you add nodes. 添加节点时,您需要复制字符串。 This can be done with the strdup function: 这可以通过strdup函数完成:

ptr->val = strdup(data);

Of course, since this allocates memory for the string using malloc , you have to free this memory manually. 当然,由于此操作使用malloc为字符串分配内存,因此您必须手动free此内存。

My first observation is that you have not allocated memory to char* data in main. 我的第一个观察结果是您尚未将内存分配给main中的char* data This way you are corrupting the memory when doing fscanf(file, "%s", data); 这样,您在执行fscanf(file, "%s", data);时会损坏内存fscanf(file, "%s", data); . Also you would like to dynamically allocate/deallocate this memory not like char data[128] , since you want each node to have different data. 另外,由于您希望每个节点具有不同的数据,因此您不希望像char data[128]那样动态分配/取消分配该内存。

There are a number of problems with this code. 此代码有很多问题。 Does it compile without warnings? 它会在没有警告的情况下编译吗? Does it compile at all? 它可以编译吗?

  • In main(), you haven't initialized data before using it. 在main()中,您尚未在使用之前初始化data Most compilers will warn you about that. 大多数编译器会警告您。

  • create() and insert() both say they return struct node* but do not return anything. create()和insert()都说它们返回struct node*但不返回任何东西。 The compiler should complain about that. 编译器应该对此抱怨。

  • insert() takes char *data as a parameter, but you assign tmpnode->val = data in that function. insert()将char *data作为参数,但是您要在该函数中分配tmpnode->val = data According to your declaration of struct node , val is a char , not a char * . 根据您对struct node的声明, val是一个char ,而不是char * The compiler should complain about that too. 编译器也应该对此抱怨。

  • In main() , data is a char * , and you are passing the address of the pointer into fscanf() . main()datachar * ,并且您将指针的地址传递给fscanf() And you haven't allocated any memory for data , nor initialized it to anything non-random, so you are passing the address of a bogus pointer into fscanf(). 而且您没有为data分配任何内存,也没有将其初始化为任何非随机的数据,因此您要将伪指针的地址传递给fscanf()。

There's lots more, but that's a good start. 还有很多,但这是一个好的开始。 If you've disabled warnings in your compiler, enable them agian - they're telling you something important. 如果您在编译器中禁用了警告,则将其启用agian-它们会告诉您一些重要的信息。 If you are getting warnings and ignoring them, stop ignoring them - they are telling you something important. 如果您收到警告并忽略它们,请不要忽略它们-它们在告诉您重要的事情。

I pretty much reworked the code from scratch and I'm sure there are probably still many things to fix but it does sort the input. 我几乎从头开始重新编写了代码,并且我敢肯定可能还有很多事情要修复,但是它确实对输入进行了排序。 Only thing which bothers me is that Valgrind throws out plenty of errors for my Freememory function 唯一令我困扰的是Valgrind为我的Freememory函数抛出了很多错误

HEAP SUMMARY:
==8731==     in use at exit: 0 bytes in 0 blocks
==8731==   total heap usage: 9 allocs, 32 frees, 1,016 bytes allocated
==8731== 
==8731== All heap blocks were freed -- no leaks are possible
==8731== 
==8731== For counts of detected and suppressed errors, rerun with: -v
==8731== ERROR SUMMARY: 38 errors from 6 contexts (suppressed: 2 from 2)

Anyway my solution to the problem is here: 无论如何,我的解决方案在这里:

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

// maximum length for a word
#define LENGTH 45

// default dictionary
#define DICTIONARY "words.txt"

typedef struct node
{
    char word[LENGTH + 1];
    struct node* next;
}
Word;

Word *head = NULL; //start
Word *cur = NULL;  //cursor
Word *cur2 = NULL;  //cursor

/****************************************/
/*              PROTOTYPES              */
/****************************************/
Word* create(char *node);
void display();
void freememory();

/****************************************/
/*              FUNCTIONS               */
/****************************************/

Word* create(char *node)
{
    Word *new_node = NULL;
    new_node = (Word*)malloc(sizeof(Word));
    strncpy(new_node->word, node, LENGTH);

    if(head==NULL)
    {
        head=new_node;
        new_node->next=NULL;
    }
    else
    {
        cur = head;
        cur2 = cur->next;
        while (cur != NULL)
        {
            if (strcmp(new_node->word, cur->word) > 0 )
            {

                if (cur->next == NULL)
                {
                    new_node->next = NULL;
                    cur->next = new_node;
                    break;
                }
                else if (strcmp(new_node->word, cur->word) > 0 && strcmp(new_node->word, cur2->word) <= 0)
                {
                    new_node->next = cur->next;
                    cur->next = new_node;
                    break;
                }
            }
            else if (strcmp(new_node->word, cur->word) <= 0 )
            {
                new_node->next = head;
                head = new_node;
                break;
            }
            cur = cur->next;
            cur2 = cur2->next;
        }
    }
    return head;
}

// output the list
void display()
{
    //Word *Wordlist;
    cur = head;
    while (cur != NULL)
    {
        printf("%s->", cur->word);
        cur = cur->next;
    }
    printf("End of the list!\n");
}

// free allocated memory
void freememory()
{
    Word *temp = NULL;
    Word *temp2 = NULL;
    cur = head;
    cur2 = head;
    while(cur != NULL)
    {
        temp = cur;
        cur = cur->next;
        free(cur);
        free(temp);
    }

    while(cur2 != NULL)
    {
        temp2 = cur2;
        cur2 = cur2->next;
        free(cur2);
        free(temp2);
    }

    free(head);
}

/****************************************/
/*               M A I N                */
/****************************************/

int main()
{
    system("clear");
    char data[LENGTH];

    FILE* file = fopen(DICTIONARY, "r");

    // check successful opening of the file
    if(file == NULL) {
        perror("Error opening file");
        return -1;
    }

    //read data (words) from file
    while(fscanf (file, "%s", data) == 1)
    {
        create(data);
    }
    display();
    freememory();
    fclose(file);
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM