使用递归在 C 中实现单链表:我做错了什么?

2024-04-03

我试图编写的程序的提示是这样的:

创建一个链表和一组操作它的函数。所有循环 必须使用递归来完成。以下功能是 该列表将使用的函数:

  • isempty():如果列表为空则返回true,否则返回true。
  • find(v):查找某个值并返回其索引。如果不成功,则返回一个指示失败的值。这将需要 递归。
  • add(v):将值为 v 的项目添加到列表的尾部
  • insert(i, e):在索引 i 处插入元素 e。这将需要递归。
  • delete(n):删除索引n处的元素。如果不成功,则返回一个指示失败的值。这将需要递归。
  • remove(v):删除某个值的第一个实例。如果不成功,则返回一个指示失败的值。这将需要 递归。
  • Replace(i, v):用值 v 替换索引 i 处的值。这将需要递归。
  • get(i):获取索引 i 处的值。这将需要递归
  • liststring():返回列表的字符串,显示每个元素的值,格式如下:[value, value, ... , value]。 这将需要递归。

我以前写过一个与此类似的程序,但我从未使用递归来导航链接列表。我尝试调整为链接列表编写的原始代码,但每次运行程序时都会出现内存泄漏和分段错误。我发现在尝试运行特定函数时会发生错误,因此我附加了插入节点函数、主函数和用于存储节点的结构。任何关于如何清理代码、更好地诊断我的问题或您注意到的错误的提示将不胜感激。

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

struct node_t {
    struct node_t *next;
    int value;
};

/**
 * @brief creates new node
 * 
 * @param value value to be stored in new node
 * @return pointer for new node
 */
struct node_t *create_node(int value) {
    struct node_t *node = (struct node_t *) malloc(sizeof(struct node_t));

    node->next = NULL;
    node->value = value;
    return node;
}

/**
 * @brief inserts node into linked list at index given by user
 * 
 * @param head pointer for node at front of linked list
 * @param index index/position of list to insert new node
 * @param value value to be stored in new node
 */
void insert_node(struct node_t *head, int index, int value) {
    struct node_t *tmp;

    if (index == 0) {
        tmp = head;
        head = create_node(value);
        head->next = tmp;
    } else if (head->next == NULL) {
        if (index == 0) {
            tmp = create_node(value);
            head->next = tmp;
            tmp->next = head->next->next;
        } else {
            printf("Index out of bounds.\n");
        }
    } else {
        if (index == 0) {
            tmp = create_node(value);
            head->next = tmp;
            tmp->next = head->next->next;
        } else {
            insert_node(head->next, index - 1, value);
        }
    }
}

int main(void) {
    struct node_t *head = NULL;
    char choice, tmp;
    int index = 0;
    int value, num;

    printf("Please enter the index at which you want to insert a new element: ");
    scanf("%d", &index);

    printf("Please enter the value you want to insert: ");
    scanf("%d", &value);

    insert_node(head, index, value);

    return 0;
}

当您将一个节点插入到列表的索引 0 处时,该节点将成为列表的新头节点。然而,这个函数签名...

void insert_node(struct node_t *head, int index, int value) {

...没有提供将新头节点传送回调用者的方法。因此,main()的头指针始终保持为空。解决此类问题有 2.5 种常用方法:

  1. 返回新的头节点:

    struct node_t *insert_node(struct node_t *head, int index, int value)
    

    当然,这需要调用者对返回值做正确的事情。

  2. 使用 in / out 参数将列表头传递给函数并使其能够直接设置新头:

    void insert_node(struct node_t **head, int index, int value) {
        // ... Work with *head ...
    
        // where appropriate:
        *head = new_head;
    }
    
  1. (5.) 创建一个表示整个列表的结构,而不是使用裸头指针。使头指针成为该结构的成员,并将指针传递给列表结构:
    struct list {
        struct node_t *head;
        // and maybe other members, too, such as a tail pointer
    };
    
    void insert_node(struct list *list, int index, int value) {
        // ... Work with list->head ...
    
        // where appropriate:
        list->head = new_head;
    }
    
    这实际上只是 (2) 的改进,因为两者的要点是它们增加了额外的间接级别。

但这只是间接导致记忆错误的原因。直接原因是你的insert_node()函数假设index传递给它的值对于列表有效。当它在列表中向指定索引前进时,它不关心节点是否next指针为空,因此如果索引太大,它将尝试取消引用其中的空指针。或者,如果索引为负数,则它会在每次递归调用时递减索引,并且仅在达到索引 0 时停止。

您应该验证索引是否为非负数,并且在进行过程中应该注意列表的末尾。当索引无效时,您应该以某种方式指示错误,尽管我将详细信息留给您。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用递归在 C 中实现单链表:我做错了什么? 的相关文章

  • C# 和 Javascript SHA256 哈希的代码示例

    我有一个在服务器端运行的 C 算法 它对 Base64 编码的字符串进行哈希处理 byte salt Convert FromBase64String serverSalt Step 1 SHA256Managed sha256 new S
  • 当我使用“control-c”关闭发送对等方的套接字时,为什么接收对等方的套接字不断接收“”

    我是套接字编程的新手 我知道使用 control c 关闭套接字是一个坏习惯 但是为什么在我使用 control c 关闭发送进程后 接收方上的套接字不断接收 在 control c 退出进程后 发送方的套接字不应该关闭吗 谢谢 我知道使用
  • 从父类调用子类方法

    a doStuff 方法是否可以在不编辑 A 类的情况下打印 B did stuff 如果是这样 我该怎么做 class Program static void Main string args A a new A B b new B a
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • 如何在列表框项目之间画一条线

    我希望能够用水平线分隔列表框中的每个项目 这只是我用于绘制项目的一些代码 private void symptomsList DrawItem object sender System Windows Forms DrawItemEvent
  • C++ 子字符串返回错误结果

    我有这个字符串 std string date 20121020 我正在做 std cout lt lt Date lt lt date lt lt n std cout lt lt Year lt lt date substr 0 4 l
  • 使闭包捕获的变量变得易失性

    闭包捕获的变量如何与不同线程交互 在下面的示例代码中 我想将totalEvents 声明为易失性的 但C 不允许这样做 是的 我知道这是错误的代码 这只是一个例子 private void WaitFor10Events volatile
  • 当 contains() 工作正常时,xpath 函数ends-with() 工作时出现问题

    我正在尝试获取具有以特定 id 结尾的属性的标签 like span 我想获取 id 以 国家 地区 结尾的跨度我尝试以下xpath span ends with id Country 但我得到以下异常 需要命名空间管理器或 XsltCon
  • 如何返回 json 结果并将 unicode 字符转义为 \u1234

    我正在实现一个返回 json 结果的方法 例如 public JsonResult MethodName Guid key var result ApiHelper GetData key Data is stored in db as v
  • 从路径中获取文件夹名称

    我有一些路c server folderName1 another name something another folder 我如何从那里提取最后一个文件夹名称 我尝试了几件事 但没有成功 我只是不想寻找最后的 然后就去休息了 Thank
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • 将 unsigned char * (uint8_t *) 转换为 const char *

    我有一个带有 uint8 t 参数的函数 uint8 t ihex decode uint8 t in size t len uint8 t out uint8 t i hn ln for i 0 i lt len i 2 hn in i
  • 将文本叠加在图像背景上并转换为 PDF

    使用 NET 我想以编程方式创建一个 PDF 它仅包含一个背景图像 其上有两个具有不同字体和位置的标签 我已阅读过有关现有 PDF 库的信息 但不知道 如果适用 哪一个对于如此简单的任务来说最简单 有人愿意指导我吗 P D 我不想使用生成的
  • 在 Dynamics CRM 插件中访问电子邮件发件人地址

    我正在编写一个 Dynamics CRM 2011 插件 该插件挂钩到电子邮件实体的更新后事件 阶段 40 pipeline http msdn microsoft com en us library gg327941 aspx 并且在此阶
  • WCF:将随机数添加到 UsernameToken

    我正在尝试连接到用 Java 编写的 Web 服务 但有些东西我无法弄清楚 使用 WCF 和 customBinding 几乎一切似乎都很好 除了 SOAP 消息的一部分 因为它缺少 Nonce 和 Created 部分节点 显然我错过了一
  • C - 直接从键盘缓冲区读取

    这是C语言中的一个问题 如何直接读取键盘缓冲区中的数据 我想直接访问数据并将其存储在变量中 变量应该是什么数据类型 我需要它用于我们研究所目前正在开发的操作系统 它被称为 ICS OS 我不太清楚具体细节 它在 x86 32 位机器上运行
  • Process.Start 阻塞

    我正在调用 Process Start 但它会阻止当前线程 pInfo new ProcessStartInfo C Windows notepad exe Start process mProcess new Process mProce
  • ASP.NET MVC 6 (ASP.NET 5) 中的 Application_PreSendRequestHeaders 和 Application_BeginRequest

    如何在 ASP NET 5 MVC6 中使用这些方法 在 MVC5 中 我在 Global asax 中使用了它 现在呢 也许是入门班 protected void Application PreSendRequestHeaders obj
  • 防止索引超出范围错误

    我想编写对某些条件的检查 而不必使用 try catch 并且我想避免出现 Index Out of Range 错误的可能性 if array Element 0 Object Length gt 0 array Element 1 Ob
  • 恢复上传文件控制

    我确实阅读了以下帖子 C 暂停 恢复上传 https stackoverflow com questions 1048330 pause resume upload in c 使用 HTTP 恢复上传 https stackoverflow

随机推荐