C(和C++)中的指针如果以正确的方式思考它们并不那么困难。
让我用下面的代码演示:
void foo(int i) {
i = i + 5;
}
int main()
{
int i = 5;
foo(i);
printf("i is %d\n", i);
return 0;
}
问:什么将foo()
后i
在main()
值叫什么名字?
A.i
被传递到由foo()
值,所以在该main()
i
不受foo()
修改。 i
仍然是5
现在,让我们改变一下代码:
void foo(int* i) {
i = malloc(sizeof(int));
}
int main()
{
int *i = 0;
foo(i);
printf("i is %p\n", i); /* printf a pointer with %p */
return 0;
}
问:什么将foo()
后i
在main()
值叫什么名字?
A.i
被传递到由foo()
值,所以在该main()
i
不受foo()
修改。 i
仍然是0.
换句话说,没有什么改变! i
现在是一个指针的事实并没有改变,它是通过值传递的。
实际上,在C中,所有的函数参数都是按值计算的。那么,我们如何获得修改变量的函数呢?
如果要将变量传递给该函数的某个函数进行修改,则必须将该变量的地址传递给该函数。 (此为C.是真正的在C++中,你也可以使用引用,但我在这里只谈到指针。)
当你传递一个变量的地址,你正在做两件事情:
您正在计算的可变
存储器地址,则通过值顺便指出存储器地址给该函数。
内存地址可用于修改内存地址指向的内存。由于函数内部的内存地址与函数调用外部的内存地址相同(因为它是按值传递的),所以它们指向的变量是相同的!
这真的是最棘手的概念,所以让我们画一些ascii。
| |
+------------+ <- 0x04762198
| |
| i |
| |
| |
+------------+ <- 0x0476219C
| |
让我来向您介绍int i
。 i
是从内存地址0x04762198
开始的4字节(在该系统上)。所有变量都存储在内存中的某个地方,并且将存储在像这样的内存地址中。
如果我们为i
指定一个值,则该值将存储在上述内存块中。
如果我们通过i
函数,i
的值将被复制到内存中的其他地方供函数使用。该内存的值将与我们原来的i
相同,但该变量的内存地址将在其他地方。
这是一个巧妙的位。如果我们将0x04762198
传递给函数,那么该函数现在可以访问原始的i
的内存位置!这是一个指针,所以叫指向内存中的地址。如果我们想使用指针修改原来的i
函数,我们解除引用它(例如,*ptr = 5;
)。我们实际上在做的是说“请将此值(5)存储在ptr
”“指向的内存中。
让我们再次修改代码来实现这一点:
/*
* The address of an int* is int**
*/
void foo(int** i) {
/* dereference to access and modify the original `i` */
*i = malloc(sizeof(int));
}
int main()
{
int *i = 0;
/*
* Pass the address of i, so foo() can modify i
*/
foo(&i);
printf("i is %p\n", i); /* printf a pointer with %p */
return 0;
}
看到区别?
现在,你能看到你在自己的程序中做错了吗?
注意:为了简洁起见,我省略了通常的错误检查(例如检查malloc()不返回NULL)。
你确定这是C吗? 'new'是一个C++关键字。 – C0deH4cker 2012-07-09 04:13:42
除此之外,“C或C++”的东西是不言而喻的。本代码中的指针误解同样适用于这两种语言。 – MatthewD 2012-07-09 06:29:38