【问题标题】:Problem in executing single-linked-list in c without using dynamic memory allocation在不使用动态内存分配的情况下在 c 中执行单链表的问题
【发布时间】:2020-08-24 11:53:00
【问题描述】:

我正在用“c”编写单链表程序,而不使用动态内存分配。但它正在进入无限循环。整个程序:

#include <stdio.h>

struct SingleLinkedList
{
    int data;
    struct SingleLinkedList* next;
};

typedef struct SingleLinkedList sll;

void insertAtStart(sll** head, int data)
{
    sll newNode = { data, NULL };
    newNode.data = data;
    if (*head == NULL)
    {
        *head = &newNode;
        return;
    }
    newNode.next = *head;
    *head = &newNode;
}

void insertAtEnd(sll** head, int data)
{
    sll newNode = { data, NULL };
    newNode.data = data;
    if (*head == NULL)
    {
        *head = &newNode;
        return;
    }
    sll* node = *head;
    while (node -> next != NULL)
    {
        node = node -> next;
    }
    node -> next = &newNode;
}

void insertAfterNode(sll **head, int data)
{
    int nodeNum, count = 1;
    printf("\nEnter the node number to insert after: ");
    scanf("%d", &nodeNum);
    if (*head == NULL)
    {
        printf("\nThe List is empty!\n");
        return;
    }
    sll *prevNode = *head;
    while (count < nodeNum && prevNode -> next != NULL)
    {
        prevNode = prevNode -> next;
        count++;
    }
    if (count < nodeNum)
    {
        printf("\nThere are only %d nodes in the list\n", count);
        return;
    }

    sll newNode = { data, NULL };
    newNode.next = prevNode -> next;
    prevNode -> next = &newNode;
}

int choiceSelection()
{
    int choice;
    printf("\nSelect an Option:\n");
    printf("1. Insert At Beginning\n");
    printf("2. Insert At Last\n");
    printf("3. Insert After Certain Node\n");
    printf("4. Print all nodes\n");
    printf("5. Exit\n");
    scanf("%d", &choice);
    return choice;
}

int dataEntry()
{
    int data;
    printf("\nEnter the data: ");
    scanf("%d", &data);
    return data;
}

void print(sll* node)
{
    int count = 1;
    while(node != NULL)
    {
        printf("\n----------------%d----------------\n", count);
        printf("Data: %d", node -> data);
        printf("\tAddress: %p", node);
        printf("\tNext: %p\n", node -> next);
        node = node -> next;
        count++;
    }
}

int main()
{
    sll *head = NULL;
    enum option {
        InsertAtStart = 1,
        InsertAtEnd = 2,
        InsertAfterNode = 3,
        Print = 4,
        Exit = 5,
    } choice;

    while (choice != Exit)
    {
        choice = choiceSelection();
        switch (choice)
        {
            case InsertAtStart:
                insertAtStart(&head, dataEntry());
                break;
            case InsertAtEnd:
                insertAtEnd(&head, dataEntry());
                break;
            case InsertAfterNode:
                insertAfterNode(&head, dataEntry());
                break;
            case Print:
                print(head);
                break;
            case Exit:
                break;

            default:
                printf("\nIncorrect Choice..Please choose among 1, 2, 3, 4, 5\n");
                break;
        }
    }
    printf("\nExiting!");
    return 0;
}

输出是:

Select an Option:
1. Insert At Beginning
2. Insert At Last
3. Insert After Certain Node
4. Print all nodes
5. Exit
1

Enter the data: 2

Select an Option:
1. Insert At Beginning
2. Insert At Last
3. Insert After Certain Node
4. Print all nodes
5. Exit
4

----------------1----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------2----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------3----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------4----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------5----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------6----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------7----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------8----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------9----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------10----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------11----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0

----------------12----------------
Data: 0 Address: 0x7ffe2e94c0c0 Next: 0x7ffe2e94c0c0
--------^C

需要手动终止。
谁能告诉我问题出在哪里?或者不使用动态内存分配是不可能的?

【问题讨论】:

  • 您总是应该尽可能地独立开发新功能。这段代码大部分与构建链表的问题无关;硬编码一些值,尝试构建一个包含两个元素的列表,然后看看会发生什么。
  • choice 一开始没有初始化。您的 while 循环正在处理未定义的行为。
  • insertAtStart() 函数试图在列表中嵌入一个指向局部变量的指针;这是灾难的根源。您需要一个(静态)分配的结构数组,您可以根据需要从中分配条目。
  • 只是为了澄清:一旦函数返回,局部变量就会停止存在。因此,一旦函数返回,所有指向这些局部变量的指针都变为dangling pointers

标签: c data-structures memory-management linked-list structure


【解决方案1】:

没有某种动态分配是不可能的。如果您不想使用malloc,您可以使用您自己的分配区域实现。

但是你不能使用悬空指针,这是你的实现所做的。

void insertAtStart(sll** head, int data)
{
    sll newNode = { data, NULL };

newNode 是一个具有自动存储持续时间的变量,这意味着它仅在声明它的函数返回(或以其他方式退出)之前存在。

    newNode.data = data;
    if (*head == NULL)
    {
        *head = &newNode;

所以现在*head 指向一个具有自动存储持续时间的对象。但是看看接下来会发生什么:

        return;

只要return 执行,insertAtStart 就会终止,并且它的所有局部变量的生命周期,包括newNode 都会突然结束。当一个对象的生命周期结束时,指向该对象的指针的可用性也会结束。

    }
    newNode.next = *head;
    *head = &newNode;
}

我应该注意,虽然有一些规则禁止你在这里做的事情,但实际上没有任何东西试图强制执行它们。事情总是以神秘的方式失败。

说对象的生命周期结束并不意味着存储对象的内存不复存在。您的计算机没有配备可以构建和拆卸物理内存的小型纳米机器人。这意味着内存不再包含该对象,并且可能(将)被重用于其他目的。

同样,尽管 C 标准明确指出指向已终止对象的指针不再可用(“当指针指向的对象...到达其生命周期结束时,指针的值变得不确定。”),实际上没有阻止您尝试使用指针;问题是它可能指向放置在同一内存中的不同对象。这就是这里发生的事情:结果是您的链表最终成为垃圾的循环列表。

【讨论】:

  • 再一次,如果我不想使用使用 malloc,使用 static 无论如何是一个不错的选择,因为对象的生命周期不会结束??跨度>
  • @Abinav:这将为您提供一个具有无限生命周期的对象。但是有人假设您的链表包含多个节点。如果您使用static 节点,您将用一个可靠地产生无限循环的程序替换当前的未定义行为:-)。
  • @Abinav:如果你打算用 C 编程,你需要让malloc 成为你的朋友。事实上,malloc 在您可能使用的所有其他编程语言中无处不在。只是它是自动调用的,所以你不会注意到它。
猜你喜欢
  • 2012-10-11
  • 2013-08-12
  • 2012-05-02
  • 1970-01-01
  • 2013-03-07
  • 2015-12-08
  • 1970-01-01
  • 1970-01-01
  • 2012-10-12
相关资源
最近更新 更多