您是按值传递,而不是按引用传递。你传值的是指针,但指针还是传值。你可以改变它指向的东西;您无法更改调用函数中的指针。如果你想这样做,你必须将一个指针传递给指针,就像在你的第二个代码片段中一样。
这是一个基于您的代码的衍生程序,其输出来自 Mac OS X 10.8.3 上的 64 位构建。我在地址打印中使用了 12 以在本机上给出统一宽度的指针输出;您可以调整它以适合您的机器。
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
static int q = 42;
static void ptrAllocation(int *p, int **z)
{
printf("p now points at: %2d (0x%.12" PRIXPTR ")\n", *p, (uintptr_t)p);
printf("z now points at: %2d (0x%.12" PRIXPTR ") (0x%.12" PRIXPTR ")\n", **z, (uintptr_t)*z, (uintptr_t)z);
int k = 10;
int *t = &k;
*z = &q;
p = t;
printf("After:\n");
printf("p now points at: %2d (0x%.12" PRIXPTR ")\n", *p, (uintptr_t)p);
printf("z now points at: %2d (0x%.12" PRIXPTR ") (0x%.12" PRIXPTR ")\n", **z, (uintptr_t)*z, (uintptr_t)z);
}
int main(void)
{
int i = 5;
int j = 7;
int *a = &i;
int *b = &j;
printf("Before:\n");
printf("a now points at: %2d (0x%.12" PRIXPTR ")\n", *a, (uintptr_t)a);
printf("b now points at: %2d (0x%.12" PRIXPTR ")\n", *b, (uintptr_t)b);
ptrAllocation(a, &b);
printf("a now points at: %2d (0x%.12" PRIXPTR ")\n", *a, (uintptr_t)a);
printf("b now points at: %2d (0x%.12" PRIXPTR ")\n", *b, (uintptr_t)b);
}
样本输出:
Before:
a now points at: 5 (0x7FFF59E1852C)
b now points at: 7 (0x7FFF59E18530)
p now points at: 5 (0x7FFF59E1852C)
z now points at: 7 (0x7FFF59E18530) (0x7FFF59E18538)
After:
p now points at: 10 (0x7FFF59E18534)
z now points at: 42 (0x000105DE8050) (0x7FFF59E18538)
a now points at: 5 (0x7FFF59E1852C)
b now points at: 42 (0x000105DE8050)
研究输出应该可以帮助您更好地了解正在发生的事情。如果需要,您可以打印更多地址值。
请描述堆栈和指针在上面的程序中是如何工作的。
我将讨论我展示的程序,因为地址可供讨论。
该变量q
位于地址 0x000105DEE8050。在内部main()
,变量i
存储在堆栈中的内存位置 0x7FFF59E1852C;该变量j
存储在内存位置 0x7FFF59E18530。变量a
包含的地址i
;b
包含的地址j
;自身地址b
为0x7FFF59E18538;的地址a
未显示在输出中。
当ptrAllocation()
被调用时, 的值a
被压入堆栈, 的地址b
也被压入堆栈。这是推送值的顺序的实现细节。
在内部ptrAllocation()
,变量p
包含函数中值的a
副本main()
。该变量z
包含函数中的b
地址main()
。变量k
在堆栈上;该变量t
包含 的地址k
。
赋值通过参数*z = &q;
将地址分配给q
指针;它通过改变调用函数中的值来改变指向的地方——这只有在传递了地址的情况下才有可能。b
z
b
b
b
赋值p = t;
更改了局部变量(其中包含变量inp
中的内容的副本),使其指向所指向的内容,即. 因此,'After' 打印语句注意到指向值 10。指向的值在并且仍然是 42;是 的地址。a
main()
t
k
p
**z
q
*z
q
返回时,代码a
中的main()
代码不变,因为它的地址没有传递给ptrAllocation()
,但b
由于它的地址被传递给ptrAllocation()
并ptrAllocation()
修改了指针而发生了变化。
正如对问题的评论中所述,您的第二次实施ptrAllocation()
也存在缺陷:
void ptrAllocation(int **p)
{
int k = 10 ;
int *t = &k;
*p = t ;
printf("\np now points : %d",**p);
}
调用此函数后,传递给它的指针无法可靠地解除引用,因为*p
指向的局部变量一旦ptrAllocation()
返回就不再有效。k
你可以通过 make into来解决这个问题static int k = 10;
,或者通过安排*p
指向其他一些int
在函数之外具有范围的值——在函数之外定义的变量,或者动态分配的变量:
void ptrAllocation(int **p)
{
static int k = 10;
int *t = &k;
*p = t ;
printf("p now points : %d\n", **p);
}
或者:
void ptrAllocation(int **p)
{
*p = malloc(sizeof(*t));
if (*p != 0)
{
**p = 10;
printf("p now points : %d\n", **p);
}
}
请注意,顺便提一下,我留下的代码在每个printf()
语句的末尾都有换行符。养成在输出行末尾放置换行符的习惯。如果不这样做,则不知道输出何时会出现(因为它可能会一直保持到下一次生成换行符时)。