此函数不返回预期结果(交换a
和b
)。
#include<stdio.h>
#include<stdlib.h>
void swap_one(int *x, int *y) {
int *tmp;
tmp = x;
x = y;
y = tmp;
printf("x = %d y = %dn", *x, *y);
}
void swap_two(int *x, int *y) {
}
int main() {
int a = 5;
int b = 100;
printf("Before a = %d b = %dnn", a, b);
int *p = (int *) malloc(sizeof(int));
int *q = (int *) malloc(sizeof(int));
p = &a;
q = &b;
swap_one(p, q);
printf("After a = %d b = %dn", a, b);
return 0;
}
但是下面的代码按预期工作。
#include <stdlib.h>
#include <stdio.h>
typedef struct ListElmt_ {
void *data;
struct ListElmt_ *next;
} ListElmt;
typedef struct List_ {
int size;
int (*match) (const void *key1, const void *key2);
void (*destroy) (void *data);
ListElmt *head;
ListElmt *tail;
} List;
void list_init (List *list) {
list->size = 0;
list->match = NULL;
list->destroy = NULL;
list->head = NULL;
list->tail = NULL;
}
int list_ins_next(List *list, ListElmt *element, void *data) {
ListElmt *new_element;
/* Alocate storage for the element. */
if ((new_element = (ListElmt *) malloc(sizeof(ListElmt))) == NULL) return -1;
/* new_element->data is of type void *. So we use (void *) data */
new_element->data = (void *)data;
if (element == NULL) {
/* Handle insertion at the head of the list */
if (list->size == 0) list->tail = new_element;
new_element->next = list->head;
list->head = new_element;
} else {
if (element->next == NULL) list->tail = new_element;
new_element->next = element->next;
element->next = new_element;
}
list->size++;
return 0;
}
/* Print the list */
static void print_list(const List *list) {
ListElmt *element;
int *data;
int i;
/* Display the linked list */
fprintf(stdout, "List size is %dn", list->size);
i = 0;
element = list->head;
while (1) {
data = element->data;
fprintf(stdout, "list[%03d] = %03dn", i, *data);
i++;
if (element->next == NULL) {
break;
} else {
element = element->next;
}
}
}
int main(int argc, char **argv) {
List list;
ListElmt *element;
int *data;
int i;
/* list = (List *) malloc(sizeof(List)); */
/* Initialize the linked list */
List *listPtr;
listPtr = &list;
list_init(listPtr);
/* Perform some linked list operations */
element = listPtr->head;
for (i = 10; i > 0; i--) {
if ( (data = (int *) malloc(sizeof(int))) == NULL) return 1;
*data = i;
if (list_ins_next(listPtr, NULL, data) != 0) return 1;
}
print_list(listPtr);
fprintf(stdout, "Value in *data is:%dn", *data);
return 0;
}
问题是:在swap_one
函数中,x=y
类似于new_element->next = element->next
或element->next = new_element
。为什么new_element->next = element->next
和element->next = new_element
工作,但swap_one函数中的x =y
不会交换a
和b
?
对不起,很多代码,但我真的对这个感到困惑。
谢谢。
指针按值传递。 交换这些变量中保存的指针值不会实现它们指向的数据的交换。
-
假设
&p
是地址0x1000,&q
是地址0x1004。 -
现在,您调用
swap_one(&p, &q);
-- 指针x
的值为 0x1000,指针y
的值为 0x1004。 -
现在交换指针值。
x
现在0x1004指向q
,y
现在0x1000指向p
。 然而,p
和q
从未在记忆中移动过。 您只更改了指针中存储的值。 -
当函数返回时,这些指针将超出范围。
p
和q
仍然保留与以前相同的内容,因为您从未首先修改过它们。
因此,若要交换它们指向的值,必须取消引用指针以获取实际数据。
int tmp = *x;
*x = *y;
*y = tmp;
将此与您的链表示例进行对比。 在该示例中,您有一个指向结构的指针,并且您正在修改其next
成员。 这实际上修改了内存中的指针,因为这是链表所在的位置以及它存储值的方式。
但是,如果您将这些指针指向某个假设函数,则会出现相同的问题:swap_next(node **x, node **y);
--x
和y
只是指向指针值的局部变量。 如果您交换它们,它们不会修改除自身以外的任何内容。 因此,相同的修复程序适用:要更改所指向的数据,您必须遵循指针。
swap_one
函数只是交换传递给函数的指针值,而不是指针指向的内容。 因此,您所做的任何更改都不会反映在函数之外。
您需要取消引用这些指针以读取/写入它们指向的内容。
void swap_one(int *x, int *y) {
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
printf("x = %d y = %dn", *x, *y);
}
在list_ins_next
函数中,您正在更改指针指向的内容,因此更改在函数外部可见。
变量x
和y
是swap_one()
的局部变量。 这是调用函数时发生的情况swap_one()
:
p = &a;
q = &b;
p (pointer) q (pointer)
--- ---
| |---+ | |---+
--- | --- |
| |
a ---- b ----
| | | |
---- ----
从main()
函数调用swap_one(p, q)
函数:
p (pointer) q (pointer)
--- ---
| |---+ | |---+
--- | --- |
| |
a ---- b ----
| | | |
---- ----
| |
| |
--- | --- |
| |---+ | |---+
--- ---
x (pointer) y (pointer)
pointing to a pointing to b
(x and y are parameters of swap_one())
执行swap_one()
函数的这些语句后:
tmp = x;
x = y;
y = tmp;
指针x
将指向y
指向的指针的地址,指针y
将指向调用swap_one()
时x
指向的指针的地址。
p (pointer) q (pointer)
--- ---
| |---+ | |---+
--- | --- |
| |
a ---- b ----
| | -----+ | |
---- | ----
| |
+--------|---------+
--- | | ---
| |---+ +---| |
--- ---
x (pointer) y (pointer)
pointing to b pointing to a
请注意,指针p
和指针q
仍分别指向变量a
和b
。这就是为什么当swap_one()
函数返回时,变量a
和b
的值不会交换。
如果要交换变量的值,其地址作为参数传递给函数swap_one()
而不是取消引用指针参数并替换该位置的值,即您应该在函数swap_one()
执行以下操作:
tmp = *x;
*x = *y;
*y = tmp;
通过这些更改,传递给函数swap_one()
地址的变量的值将被交换,因为现在您正在取消引用指针x
(即*x
) 和指针y
(即*y
),并在该位置分配值。
现在,来到第二部分代码的这一部分。以element
不NULL
的情况为例
} else {
if (element->next == NULL) list->tail = new_element;
new_element->next = element->next;
element->next = new_element;
请注意,element
指针的类型是ListElmt
的,是的,它也是函数list_ins_next()
局部指针变量。但是,在这里我们利用这个局部指针变量来修改它指向的结构成员的值。
new_element (pointer of type ListElmt)
----
| |-----+
---- |
|
-----------
| | |
-----------
^ ^
| |
data next
pointer pointer
element (pointer of type ListElmt, which is pointing to an existing node of list
---- passed to list_ins_next() function)
| |-----+
---- |
|
-----------
| | |
-----------
^ ^
| |
data next
pointer pointer
请注意,这
new_element->next
与
(*new_element).next
这意味着,取消引用new_element
指针(转到它指向的位置)并访问该位置的next
指针。
所以,这个
new_element->next = element->next;
将使new_element->next
指针指向指针所指向的内容element->next
并且这
element->next = new_element; // same as (*element).next = new_element;
将使element->next
指针指向指针所指向new_element
内容。执行这些语句后,
new_element (pointer of type ListElmt)
----
| |-----+
---- |
|
-----------
+--- | | |-------> (pointing to what element->next was pointing at)
| -----------
| ^ ^
| | |
| data next
| pointer pointer
--------------------+
|
element |
| |-----+ |
---- | |
| |
----------- |
| | |----+
-----------
^ ^
| |
data next
pointer pointer
因此,如果要在传递给函数的指针中进行更改,则必须在调用函数中取消引用它。
如果您仍然感到困惑,请只检查以下内容:
在第二个代码中,如果您执行的操作与第一个代码中执行的操作相同:
example = <some pointer of type ListElmt>;
即将其他一些相同类型的指针分配给example
,这是将要发生的事情:
element
---- -----------
| |---------------> | | |
---- -----------
(The original ListElmt type element
whose address passed to list_ins_next() function)
-----------
| | |
-----------
^ ^
| |
data next
pointer pointer
现在,当list_ins_next()
函数返回时,其地址传递给此函数的原始元素将保持不变。
附加:
在这里,您的程序正在泄漏内存:
int *p = (int *) malloc(sizeof(int));
int *q = (int *) malloc(sizeof(int));
p = &a;
q = &b;
因为当您分别将指针&a
和&b
分配给p
和q
时,分配给指针p
和q
的内存引用(使用malloc()
)将丢失。