我们先来回想下变量,在程序中的变量只是一段存储空间的别名,那么是不是必须要通过这个别名才能使用这段存储空间呢?答案肯定不是的,我们还可以通过指针来使用这段存储空间。在指针声明时,* 号表示所声明的变量为指针。在指针使用时,* 号表示取指针所指向的内存空间中的值。我们通过下面这幅图可以更加直观的看出他们的关系
通过这个图片我们是不是更加直观的看出它们的关系呢。上面即表示的是变量 p 保存着变量 i 的内存地址,即 p <--> &i; *p <--> i。
下来我们通过示例代码进行分析说明,代码如下
#include <stdio.h> int main() { int i = 0; int* pI; char* pC; float* pF; pI = &i; *pI = 10; printf("%p, %p, %d\n", pI, &i, i); printf("%d, %d, %p\n", sizeof(int*), sizeof(pI), &pI); printf("%d, %d, %p\n", sizeof(char*), sizeof(pC), &pC); printf("%d, %d, %p\n", sizeof(float*), sizeof(pF), &pF); return 0; }
我们在678行分别定义了 int* char* float* 类型的指针,在第10行通过指针 pI 指向了 i 的地址,再通过第12行的取指针的内容并赋值来达到改变 i 的值。那么我们接下来打印下指针 pI 的地址,i 的地址还有 i 的值分别是什么。还有看下三种不同类型的指针所占的内存大小和地址各是什么,编译结果如下
那么我们看到指针 pI 和 i 的地址相同,并且 i 的值已经通过指针成功改变为10。接着我们看到不管是什么类型的指针所占的内存大小都是4,并不是我们之前所认为的 int 为4,char 为1,float 为4啦,它们的地址连续着。说明指针在内存中并没有类型之分,所存储的内存都是在同一个段上。
我们接下来再来看个传值调用和传址调用。那么在程序中,指针也是变量,因此可以声明指针参数。当一个函数体内部需要改变实参的值,则需要使用指针参数。函数调用时实参值将复制到形参,指针适用于复杂数据类型作为参数的函数中。我们下来利用示例代码进行说明传值调用和传址调用的区别,代码如下
#include <stdio.h> int swap(int a, int b) { int c = a; a = b; b = c; } int main() { int aa = 1; int bb = 2; printf("aa = %d, bb = %d\n", aa, bb); swap(aa, bb); printf("aa = %d, bb = %d\n", aa, bb); return 0; }
我们想当然是 swap 函数能完成两个数交换的功能,我们来编译下,看看是否能交换呢?
结果是这样的,卧槽,是我们搞错了嘛。看来看去觉得程序就该这么写啊,我们再来仔细分析下。我们在第19行只是将变量 aa 和 bb 的值复制给了 swap 函数的实参 a 和 b。在 swap 函数内部确实完成 a 和 b 的值交换,但只是 a 和 b 的值交换了而已。换句话说,这时他两跟变量 aa 和 bb 没啥关系,我们这种就属于传值调用。我们再将 swap 函数改成下面这样呢?看看结果如何
int swap(int* a, int* b) { int c = *a; *a = *b; *b = c; }
再将 main 函数中第19行改成 swap(&aa, &bb); 我们来看看编译结果如何
我们看到加了个 * 号,竟然神奇般改变了 aa 和 bb 的值。感觉很神奇啊,我们仔细分析下,这就是属于利用指针指向变量 aa 和 bb 的地址,然后再通过 * 取地址处的内容再赋值改变。这样就是我们所说的传址调用啦。
我们下来再来看看一个笔试面试中经常会问到的问题:a> const int* p;b> int const* p;c> int* const p;d> const int* const p 四种有什么区别。我们来一一分析:a> p 可变但它指向的内容不可变;b> p 可变但它指向的内容不可变;c> p 不可变但它所指向的内容是可变的;d> p 和它所指向的内容都是不可变的。我们对待这种问题有个口诀就是:左数右指。什么意思呢?就是当 const 出现在 * 号左边时指针指向的数据为常量,当 const 出现在 * 号右边时指针本身为常量。这样是不是就很好记了呢?反正博主是记住了哈。
我们下来再来个示例代码对其进行说明,代码如下
#include <stdio.h> int main() { int i = 0; const int* p1 = &i; int const* p2 = &i; int* const p3 = &i; const int* const p4 = &i; *p1 = 1; // compile error p1 = NULL; // ok *p2 = 2; // compile error p2 = NULL; // ok *p3 = 3; // ok p3 = NULL; // compile error *p4 = 4; // compile error p4 = NULL; // compile error return 0; }
我们看到第12行明显会出错,因为 const 出现在 * 号的左边,左数右指嘛,就是它所指向的内容是不可变的。第15行也是同样的错误。第19行则是因为 p3 是 const 出现在 * 号的右边,所以它本身不可变。p4 前后都有 const,所以第21、22行均会出错。我们来看看分析是否正确呢
我们看到结果与我们分析的是一致的,我们以后遇到这种笔试面试题岂不是送分题啦?哈哈,开个玩笑了,其实还是很简单的只需记住口诀就好。我们看看指针是否是那样传说中的难呢?其实也不难的。通过对指针的学习,我们总结如下:1、指针是 C 语言中一种特别的变量;2、指针所保存的值是内存的地址;3、可以通过指针修改内存中的任意地址内容。
欢迎大家一起来学习 C 语言,可以加我QQ:243343083。
原文地址:http://blog.51cto.com/12810168/2104633