【问题标题】:Programming in C, Stephen Kochan - Chapter 11, Exercise 3C 语言编程,Stephen Kochan - 第 11 章,练习 3
【发布时间】:2016-04-10 16:17:38
【问题描述】:

我正在使用 Stephen Kochan 编写的 Programming in C 一书自学 C,并且我已经完成了以下关于指针的练习:

  1. 编写一个名为insertEntry 的函数将新条目插入到链表中。让该过程将指向要插入的列表条目的指针(如本章定义的 struct entry 类型)和指向列表中要插入新条目的元素的指针作为参数。

struct entry结构定义如下:

struct  entry
{
    int x;
    struct entry  *ptr;
};

这是我的代码:

#include <stdio.h>

void insert_entry (struct entry  *new_entry, struct entry  *prev_entry);

struct entry
{
    int x;
    struct entry  *ptr;
};

int main (void)
{
    struct entry  n1, n2, n3, new_entry;
    struct entry  *list_ptr = &n1;

    n1.x = 1;
    n1.ptr = &n2;

    n2.x = 2;
    n2.ptr = &n3;

    n3.x = 4;
    n3.ptr = (struct entry *) 0;

    insert_entry (&new_entry, &n2);

    // Loop to display the list to check if insert_entry worked
    while ( list_ptr != (struct entry *) 0 ) {
        printf ("%i\n", list_ptr->x);
        list_ptr = list_ptr->ptr;
    }
}

void insert_entry (struct entry  *new_entry, struct entry  *prev_entry)
{
    new_entry->ptr = prev_entry->ptr;
    prev_entry->ptr = new_entry;

    // Assign a value to make it easier to check if the function worked 
    new_entry->x = 3;
}

这段代码工作得很好,可以完成工作。但是接下来是练习#3:

  1. 练习 2 中开发的函数仅在列表中现有元素之后插入一个元素,从而防止您在列表前面插入新条目。您如何使用相同的功能却又克服了这个问题? (提示:考虑设置一个特殊的结构来指向列表的开头。)

我不知道如何继续。如果我设置另一个结构,我将无法在不更改 insert_entry 函数的形式参数的情况下将其作为参数传递。但是我不能使用list_ptr 指针,因为如果我将它作为第二个参数传递给insert_entry 函数,那么new_entry-&gt;ptr = prev_entry-&gt;ptr; 语句就没有意义了。

关于此练习 #2 的其他问题,但我无法找到任何关于此的内容。帮助将永远感激。提前致谢。

*编辑:这就是我的代码现在的样子(感谢 u/ringzero):

#include <stdio.h>

void insert_entry (struct entry  *new_entry, struct entry  *prev_entry);

struct entry
{
    int x;
    struct entry  *ptr;
};

int main (void)
{
    struct entry  n_start, n1, n2, n3, new_entry;
    struct entry  *list_ptr = &n_start;

    n_start.ptr = &n1;

    n1.x = 1;
    n1.ptr = &n2;

    n2.x = 2;
    n2.ptr = &n3;

    n3.x = 3;
    n3.ptr = (struct entry *) 0;

    insert_entry (&new_entry, &n_start);

    // Loop to display the list to check if insert_entry worked
    while ( list_ptr != (struct entry *) 0 ) {
        printf ("%i\n", list_ptr->x);
        list_ptr = list_ptr->ptr;
    }
}

void insert_entry (struct entry  *new_entry, struct entry  *prev_entry)
{
    new_entry->ptr = prev_entry->ptr;
    prev_entry->ptr = new_entry;

    // Assign a value to make it easier to check if the function worked 
    new_entry->x = 0;
}

n_start 应该是一个虚拟结构。代码的唯一问题是循环显示n_start.x 的值。我怎样才能让它不显示?

【问题讨论】:

  • 这不是辅导网站。但作为提示:了解“环列表”。
  • 据我了解,练习希望你用它教给你的概念来解决它,这是一个基本的链表。
  • 不要在其他函数中声明函数。声明应该在全局范围内,就像函数在全局范围内定义一样。 (是的,按照您的做法在语法上是有效的;我只是不鼓励使用它。另请参阅 GCC 选项 -Wnested-externs。)
  • 您尚未初始化 new_entry,因此其 .x 值未定义(这就是您拥有“测试模式”new_entry-&gt;x = 3; 的原因)。 .ptr 值无关紧要,因为无论如何插入代码都会设置它。您应该将打印循环分解为一个函数。然后,您应该调用该函数两次,一次是在插入新条目之前,一次是之后。您可能最终决定打印指针(指向当前节点的指针和指向下一个节点的指针)。见Correct format specifier to print pointer (address)
  • 如果我初始化 new_entry.x 或稍后为其分配一个值,这并没有什么不同。不管怎样,主要问题都解决了。我只需要知道如何在不显示虚拟结构的情况下显示列表 (n_start)。顺便说一句,感谢功能范围提示,FTFY。

标签: c pointers struct


【解决方案1】:

作者 Stephen Kochan 有一个网站:classroomm.com

那里有一个论坛,其中有一小部分与他的书“Programming in C, 3rd edition”有关。它包括奇数章末练习的答案。你会发现它非常有用。

以下是来自该网站的相关信息,作为如何回答练习的小提示:

你可以通过设置一个“虚拟”结构变量来解决这个问题 称为listHead,

例如:

     struct entry  listHead;  

然后您可以通过将 listHead 的下一个成员指向实际的第一个成员来将其设置为指向列表的头部 列表条目:

       listHead.next = &entry1;  

现在要在列表的前面插入一个名为 newEntry 的新条目,您可以这样写:

       insertEntry (&new_entry, &list_head);

我不会发布我为练习编写的代码——如果你自己解决它,你会学到更多。

【讨论】:

  • 非常感谢。我想我现在明白了。现在唯一的问题是循环还显示了n_start 结构的x 成员,它应该是一个虚拟结构。
  • @Hello_World:您需要在打印条目列表之前设置 list_ptr = n_start.ptr。此外,n_start.next = &n1;应该是 n_start.ptr = &n1;