腊月的季节

C语言的指针和变量

谈一谈指针

今天一天基本都在看指针,变量,变量名,变量值,变量作用域等等。
至于我怎么研究起指针来了,因为我想知道别人是怎么想的。
我们都知道内存是计算机一部分,那么了解他,对于你了解其他的任何东西都有好处。
要想了解指针我觉得最好是抛开书上的概念,老师对你们的说的只是概念,并不能让你们的自己去思考。
其实指针也是数据,变量也是数据,你看到的都是数据。
首先,我从内存编址说起,如果内存不编址,可想而知那是肯定找不到的。就像你去电影院,每个座位没有编号你能找到吗?很显然是不可能的。在对内存进行编址的时候,为了统一化,无论从硬件还是软件都以字节为单位。在造硬件的时候,造硬件的人都是以byte字节为最小单位,包括后来的4G内存,8G内存或者更高,没有哪个造硬件的自己造了一个4G+1bit的内存吧,我想是没有的,如果是这样就浪费了一个晶体管。那么在这个基础上,我们要根据内存的的大小来编址,那么在起初的32位系统中,人们采用的是4字节编址,这是为什么呢,因为四字节编址可以编出4294967295个地址,也就是4G,那么刚好满足了4G的内存,这也是为什么32位系统,只能安装4G的内存,因为它的编址方式与64位不同,64位编址采用8字节编址,那么64位可以编出多少个地址呢?大约应该是1个T吧,总之你也不可能安装1个T的内存条吧,估计都买不起。大家也可以看到仅仅多加了三十二个开关,编址的地址数量成指数级增长。好了,言归正传,当然我在这里举例子可能还会用十进制来表示,但是你要记住32系统的内存编址采用的是4字节。那么我们现在就开始模拟给内存编址吧。
(提醒:关于栈,堆,我这里不做讨论。)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

当然内存里面的值我默认的是零。在说一遍,里面的编址1实质上应该是00000000000000000000000000000001.
那么下面讲的所有我都会在此基础上进行阐述。
还是从最牛的C语言开始吧!
在C语言中,当我们定义
int i=20;时到底完成了什么?
首先需要分配内存,那么我们把int类型的i的值放入到内存地址1中,

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

也就是说i的内存在编译后分配的内存地址是1,那么今后所有用到i变量的内存地址都是1,这也是语言编译的厉害之处啊。(插一句,我想说我理解的编译,编译是什么,编译是我从内存中取到我定义的所有变量的地址和值,那么你用高级语言写的所有代码都将变成二进制,那么他们怎么读取呢,这很好办,先读取类型,如果是int取16位二进制,放进去这就是值,那么他的地址4字节也会随着标识着他,你会发现,只要你按照计算机执行的规律去编写,计算机就会给你规律的结果),那么现在我在C语言再定义一个
int *p;
那么它是什么意思呢?如果不要int,其实我可以告诉你,它可以指向内存中的任何地址,但是加了int,也就是说它只能指向int数据类型的内存地址。那么你可以把20这个数据的内存地址赋值给p,一定要记住,在C语言中指针虽然也是数据,但是被写这个语言的人给限制了,它只能存储地址,不能存储数值。比如你要*p=20,那是不可能的,计算机不会拒绝你,但是C语言会拒绝你这样做。因为它到时候会用*p取数据,会把你当前存储的数值当做地址来操作数据。如何把20这个数据的内存地址赋值给p呢,C语言也提供了相应的操作符&,很多人在&和*之间感觉很模糊,那么我一会儿会让你很清楚。直接p=&b;这样就把b的内存地址赋值给了指针p。
内存就变成了这样。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

内存地址2保存的是1,是b变量20的地址,那么你在操作*p的时候,他先去取地址,取的1地址,再去1地址找数据。这就是指针的作用。那么你们可能会想,这样的指针能有什么用,我直接用i取不就行了吗?其实这个问题,我还真想过,我们学java不必考虑内存地址,你定义了什么,它就指代什么,你不能改变它,也不能取得它的地址。我举个简单的例子吧!大家都知道当我们在全局变量中定义了a=3函数void add(int a),那么在调用add(a)时传入了实参a,但是在add函数内部调用a的时候,其实a的一个拷贝。也就是说你在函数中如何操作a都不会影响到全局的a,当然java有引用可以解决这个问题,引用也就相当于地址。但是就针对于我们刚才那个问题,C语言指针的解决当然比Java更快,更方便。所以这也是C/C++比Java快的原因吧。我直接通过内存地址进行编程,而你需要分配一块区域创建对象,再取引用对象里面的内容,当然会影响你的性能。那么我们取了内存的地址后,我们可以传递这个指针,在任何地方改变这个指针的指向的数据,都会改变源数据。
至于**q那就更直观了。
**q是指针的指针。
也就是**q = p;
那么**q应该是

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

那么当你输出*q的时候是p的地址,**q的时候是输出数据,q输出的是i的地址。

&和*

&是取数据的地址,*是创建存储地址的变量。
比如我们上面的**q,如果使用&q那么取得是q存储的地址数据的地址,这里是把q当成了变量,比如再用&(*q)取得是*q存储的地址数据的地址。不知道你们是否能理解。

推荐文章

结构体类型完全归纳 http://blog.chinaunix.net/uid-20672257-id-2955765.html

C++网络编程(一)http://www.cnblogs.com/hlxs/archive/2011/09/09/2172351.html

addrinfo结构体原型http://www.cnblogs.com/cxz2009/archive/2010/11/19/1881661.html

WSAStartup函数的用途http://blog.csdn.net/stpeace/article/details/13279349

内存分配http://blog.csdn.net/youoran/article/details/10990815

C语言指针http://www.cnblogs.com/thrillerz/p/4642944.html

彻底搞定C语言指针http://blog.chinaunix.net/uid-22889411-id-59688.html

热评文章