【问题标题】:Linked list in C losing head informationC中的链表丢失头部信息
【发布时间】:2011-02-01 05:35:15
【问题描述】:

我已经在 C 中实现了一个基本的链表,作为开发简单 shell 的项目的一部分 - 它通过维护 shell 在后台运行的 pid 列表来支持进程的后台处理。代码如下。第一次插入queue_process(some_pid) 可以正常工作,但随后链表的行为就好像列表中从来没有任何节点(即调试函数总是打印“没有现有进程”)。我已经检查了这个文件和调用这些函数的文件是否会重置头指针无济于事。我的链表逻辑是否遗漏了什么?

对 queue_process EDIT: 的调用发生在由 shell 启动的子进程中,看起来像这样 /EDIT:queue_process(getpid())

谢谢!

    void queue_process(pid_t pid_to_insert)
{
    pmesg(2, "In queue_process.\n");
    if (head == NULL)
    {
        pmesg(3, "No existing processes.\n");
        head = malloc(sizeof(struct xssh_process));
        head->pid = pid_to_insert;
        head->next = NULL;
    }
    else
    {
        pmesg(3, "There are existing processes.\n");
        struct xssh_process *new_process = malloc(sizeof(struct xssh_process));
        new_process->next= head;
        head = new_process;
    }
    print_processes();
}

void print_processes()
{
    pmesg(2, "In print_processes.\n");
    struct xssh_process *at_node = head;
    if (head == NULL) { pmesg(2, "There are currently no background processes.\n"); return; }
    pmesg(2, "Process IDs from head (most recently executed) to tail: %i -> ", at_node->pid);
    while (at_node != NULL)
    {
        pmesg(2, "%i ->", at_node->pid);
        at_node = at_node->next;
    }
    pmesg(3, "Head's pid in print is %i.\n", head->pid);
}

【问题讨论】:

  • 找到一个不同的链表实现会更好吗?这段代码或总体程序似乎存在某种固有缺陷。
  • “struct xssh_process”的声明是什么?它是一个完整的结构还是只是一个标签?在编写链表时,您可能一开始使用了不完整的结构标记,以使节点能够指向自身。

标签: c linked-list


【解决方案1】:

这对您遇到的错误没有帮助,但是您的代码让我觉得过于复杂:

pmesg(2, "In queue_process.\n");
if (head == NULL)
{
    pmesg(3, "No existing processes.\n");
    head = malloc(sizeof(struct xssh_process));
    head->pid = pid_to_insert;
    head->next = NULL;
    tail = malloc(sizeof(struct xssh_process));
    tail = head;
}
else
{
    pmesg(3, "There are existing processes.\n");
    struct xssh_process *new_process = malloc(sizeof(struct xssh_process));
    new_process->next= head;
    head = new_process;
}

这可以简化很多。由于您无论如何都在列表的开头插入,因此您不需要为空列表提供单独的逻辑:

void queue_process(pid_t pid_to_insert) { 
   struct xssh_process *new_process = malloc(sizeof(*new_process));
   new_process->pid = pid_to_insert;
   new_process->next = head;
   head = new_process;
}

同样地,print_processes 可以稍微缩减一下:

void print_processes() { 
    struct xssh_process *p;
    for (p=head; p!=NULL; p=p->next)
        printf("%d\n", p->pid);
}

OTOH,链表在我看来是一个糟糕的选择——鉴于指针至少与 PID 一样大,至少 50% 的内存是指针的开销。

【讨论】:

    【解决方案2】:

    根据您提供的额外信息:

    对 queue_process 的调用发生在 shell启动的子进程 看起来像这样: queue_process(getpid())

    您正在尝试添加到子进程(由fork() 创建)中的链表,然后在父进程中检查该链表。

    这不起作用 - fork() 创建一个完整的、独立流程副本。除了显式标记为共享的内存之外,在fork() 之后对变量所做的修改对每个进程都是私有的。父母不会看到孩子所做的修改,孩子也不会看到父母所做的修改。

    您应该有父调用queue_process(child_pid),其中child_pidfork() 的返回值。

    【讨论】:

    • 一个新手错误肯定...解决了问题。
    【解决方案3】:

    当一个变量的值神秘地改变时,通常是因为你写的超出了另一个变量的边界,而这个变量恰好在内存中是相邻的。

    尝试在您的调试器中在head 上设置一个观察点,该观察点将在该变量更改时进入调试器。这应该可以让您很快找到问题。在gdb 中,命令为watch head

    【讨论】:

    • 我编辑了这个问题,提供了有关调用此代码的位置的更多信息。我确实设置了一个调试点,但这似乎没有效果。
    【解决方案4】:

    试试这个:

    void queue_process(pid_t pid_to_insert)
    {
        pmesg(2, "In queue_process.\n");
        if (head == NULL)
        {
            pmesg(3, "No existing processes.\n");
            head = malloc(sizeof(struct xssh_process));
            head->pid = pid_to_insert;
            head->next = NULL;
            // This malloc is not required
            // tail = malloc(sizeof(struct xssh_process));
            tail = head;
        }
        else
        {
            pmesg(3, "There are existing processes.\n");
            struct xssh_process *new_process = malloc(sizeof(struct xssh_process));
            new_process->next= head;
            head = new_process;
        }
        print_processes();
    }
    
    void print_processes()
    {
        pmesg(2, "In print_processes.\n");
        if (head == NULL) { pmesg(2, "There are currently no background processes.\n"); return; }
        struct xssh_process *at_node = head;
    
        // While at_node != null
        do
        {
            pmesg(2, "%i ->", at_node->pid);
            at_node = at_node->next;
        }
        while (at_node != null);
        pmesg(3, "Head's pid in print is %i.\n", head->pid);
    }
    

    【讨论】:

    • 不幸的是,仍然有同样的问题。
    • 每当你调用你的函数时,它会打印进入队列的最后一个进程还是第一个进程?它是否打印剩余的进程?我问这个的原因是,解决方案取决于声明“头”和“尾”指针的位置。
    • 打印最近输入的进程。我使用有关调用此代码的位置的其他信息编辑了问题。
    猜你喜欢
    • 1970-01-01
    • 2020-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多