【发布时间】:2013-09-09 02:52:43
【问题描述】:
给定以下结构:
struct node
{
int data;
struct node *next;
};
以下两个函数有什么区别:
void traverse(struct node *q);
和
void traverse(struct node **q);
它们是如何使用的?
【问题讨论】:
给定以下结构:
struct node
{
int data;
struct node *next;
};
以下两个函数有什么区别:
void traverse(struct node *q);
和
void traverse(struct node **q);
它们是如何使用的?
【问题讨论】:
一个指向节点的指针:
void traverse(struct node *q);
另一个是pointer-to-pointer-to-node(注意函数名的变化)。
void insert(struct node **q);
当您需要访问指向的内容时使用前者。当您需要访问指向的内容时使用后者-with 即您可能需要从调用方修改实际的指针变量作为潜在的 in and out 参数。
前者的一个很好的例子是遍历链表的枚举。您没有修改列表头,您只需要一个指向开始节点的指针。
后者的一个很好的例子是当你将一个节点压入堆栈时,列表头指针本身将在完成函数之前被更改。
像 C 中的所有东西(不支持数组)一样,如果您想将某些东西修改为输出参数,您需要将该参数声明为正式的指针类型并传递您正在修改的东西的地址。在后一种情况下(我认为这是引起混乱的情况),我们需要修改的是指针变量本身,因此必须将其声明为指针指针和 address然后传入一个指针。
例子大声说话,所以看看:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
void traverse(struct node* p)
{
while (p)
{
printf("%d\n", p->data);
p = p->next; // note. modifies only our local variable p.
// caller side uneffected.
}
}
void insert(struct node **pp, int data)
{
struct node *p = malloc(sizeof(*p));
p->data = data;
p->next = *pp;
*pp = p; // note: save new list head here.
}
int main(int argc, char *argv[])
{
struct node *head = NULL;
insert(&head, 1);
printf("head = %p\n", head);
insert(&head, 2);
printf("head = %p\n", head);
insert(&head, 3);
printf("head = %p\n", head);
traverse(head);
// yes, I know its leaking memory. that isn't the subject of this question.
return 0;
}
输出
head = 0x1001000e0
head = 0x100103b40
head = 0x100103b50
3
2
1
【讨论】:
第一个是单指针。它可以修改数据和下一步,但不能修改传递给函数的参数指向的内容。这通常在已经为结构分配空间时使用。
q->data = 4; /* works */
q = malloc(sizeof(struct node)); /* new memory CANNOT be seen outside the function */
第二个是双指针,所以你不仅可以修改字段data和next,还可以为它malloc空间,让新的空间在函数外可见。
(*q)->data = 4; /* works */
*q = malloc(sizeof(struct node)); /* new memory CAN be seen outside the function */
【讨论】:
struct node *q 表示变量 q 是指向节点的指针。
struct node **q 表示变量 q 是指向节点的指针。
struct node theNode;
struct node *p1 = &theNode;
struct node **p2 = &p1;
【讨论】:
这类似于passing by value and passing by reference的区别。
这里通过struct node *q可以修改q指向的内容,使输入指针指向的内容生效,而不是指针本身。所以它类似于passing by value,其中q是struct node *类型的值
虽然通过struct node **q 可以改变一切,包括输入指针的值和地址(可能是struct node *p; 并传递&p),并导致p。
【讨论】: