【问题标题】:Programming in C, Stephen Kochan, Chapter 11, Exercise 2C 语言编程,Stephen Kochan,第 11 章,练习 2
【发布时间】:2015-04-13 13:25:28
【问题描述】:

这是我在堆栈上的第一个问题。

Stephen Kochan 所著的 Programming in C (Third Edition) 一书中第 11 章 - 指针中的练习 2 有问题。

问题说: 编写一个名为 insertEntry 的函数,将新条目插入到链表中。让该过程将指向要插入的列表条目的指针(本章定义的结构条目类型)作为参数,以及指向列表中要插入新条目的元素的指针。

我的代码是这样的:

#include <stdio.h>


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


void insertEntry ( struct entry newEntry, struct entry EntryNo ){

    newEntry.next = EntryNo.next;
    EntryNo.next = &newEntry;
}


int main (){
    struct entry n1, n2, n3, n4, newEntry;

struct entry *listPointer = &n1; // with this pointer we mark the start of the list
n1.value = 100;
n1.next = &n2;
n2.value = 200;
n2.next = &n3;
n3.value = 300;
n3.next = &n4;
n4.value = 400;
n4.next = (struct entry *) 0; // we pinpoint that n4 will be the last entry of our list

newEntry.value = 340;

printf("The list before adding a new entry:\n");
while ( listPointer != (struct entry*) 0 ){
    printf("%i\n", listPointer->value );
    listPointer = listPointer->next;
}
listPointer = &n1;

insertEntry ( newEntry, n3 );

printf("The list after adding a new entry:\n");
while ( listPointer != (struct entry*) 0 ){
    printf("%i\n", listPointer->value );
    listPointer = listPointer->next;
}

return 0;

}

输出是:

The list before adding a new entry:
100
200
300
400
The list after adding a new entry:
100
200
300
400

然而,当我编写如下所示的代码时,我得到了所需的输出(这是值 300 和 400 中的新条目。

#include <stdio.h>


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


int main (){
struct entry n1, n2, n3, n4, newEntry;

struct entry *listPointer = &n1; // with this pointer we mark the start of the list
n1.value = 100;
n1.next = &n2;
n2.value = 200;
n2.next = &n3;
n3.value = 300;
n3.next = &n4;
n4.value = 400;
n4.next = (struct entry *) 0; // we pinpoint that n4 will be the last entry of our list

newEntry.value = 340;

printf("The list before adding a new entry:\n");
while ( listPointer != (struct entry*) 0 ){
    printf("%i\n", listPointer->value );
    listPointer = listPointer->next;
}
listPointer = &n1;

newEntry.next = n3.next;
n3.next = &newEntry;

printf("The list after adding a new entry:\n");
while ( listPointer != (struct entry*) 0 ){
    printf("%i\n", listPointer->value );
    listPointer = listPointer->next;
}

return 0;

}

输出是:

The list before adding a new entry:
100
200
300
400
The list after adding a new entry:
100
200
300
340
400

所以问题出在第一个代码上的函数上,比如添加的条目的值没有注册(或者没有从函数正确返回)。我不知道,因为我在这里很困惑。如果有人可以帮助我,我将不胜感激。提前谢谢你。

【问题讨论】:

  • 该函数的参数应该是struct entry*。如果您在理解上有困难,我建议您阅读有关指针和函数参数(按值调用与按引用调用)的更多信息。
  • 详细阐述 holgac 的回答:甚至结构也可以按值传递(这种变化发生在 80 年代的某个时候)。您的insertEntry() 函数对元素的副本 进行操作,并且完全不影响列表中的所有原件。您认为更改以某种方式不会“注册”的直觉完全是当场的 ;-)。

标签: c


【解决方案1】:

您需要将对象的地址传递给您的函数。函数原型将是:

void insertEntry ( struct entry *newEntry, struct entry *EntryNo )

调用函数时,传递地址为:

insertEntry ( &newEntry, &n3 );

此外,由于我们已经修改了函数以将指针作为参数,因此我们还需要在函数内进行一些修改:

void insertEntry ( struct entry *newEntry, struct entry *EntryNo ){

(*newEntry).next = (*EntryNo).next;
(*EntryNo).next = newEntry;

}

工作代码:http://ideone.com/qSdsy0

【讨论】:

  • 非常感谢大家。 (虽然我只能接受一个答案)我对这些做了更多的挖掘,现在我理解得更好了。还有一个问题,如果你能回答的话。这里: (*EntryNo).next = newEntry;为什么 newEntry 也没有分配为指针?
  • 那是因为:newEntry已经是一个指针,我们不需要解引用它。
  • 在 main 函数中,我定义了 newEntry 类型、struct entry(一个具有 int 的结构和一个 struct entry 类型的指针)。现在在 insertEntry 函数中,我可以直接访问 newEntry 的地址,这意味着我可以从该函数更改其内存地址中的内容。但是,为什么我不能假设 newEntry.next 也不是指针?是不是因为在这个函数中我只提供了newEntry的地址(所以它不知道newEntry.next的地址)?
  • next 是一个指针,也是结构的成员。因此,您可以使用newEntry-&gt;next,而不是(*newEntry).next。我希望这会有所帮助:*.com/questions/22350755/… 请阅读 cmets,也给出了解释。 :)
  • 我现在明白了。谢谢!
【解决方案2】:

由于您将对象直接传递给您的函数,因此它适用于对象的副本,而不是对象本身。为了直接处理对象,您需要传递对象的地址

【讨论】:

  • @RestlessC0bra 数组指向内存地址,但结构没有。
  • @RestlessC0bra 我并没有对你自己的问题有这个限制。
  • @RestlessC0bra ,不过你可以接受其中之一