码迷,mamicode.com
首页 > 其他好文 > 详细

指针学习笔记

时间:2016-04-12 17:38:35      阅读:246      评论:0      收藏:0      [点我收藏+]

标签:

c语言的指针神秘而强大,刚开始接触的时候非常不能理解,随着对c语言、处理器和内存的慢慢熟悉,指针也是一点一点揭开神秘的面纱。现将一些个人的理解和思考,以笔记的形式保存下来,以便以后翻阅。

在我们编程的时候,申明一个变量,或者类的实例,都需要在内存中占用一定的空间,来保存这些数据。处理器要保存这些数据,首先需要一个地址,以便在再次用到这个变量的时候能读出保存在其中的值。就像人一样,假设你用一个仓库来存储东西,那么你将东西放置在仓库的某个地方以后,你就需要记住这个地址,以便在你重新用到这个东西的时候能准确无误的找到它。

那么假设我们在编程的时候有这样一条语句

char a=10;

那么处理器在内存中是如何保存这个变量呢,假设随便找个地址保存,通俗的来讲,应该是这样的

技术分享

当然实际中应该是二进制的,那么0X 0000 0000 就是这个地址,和实际中某一栋楼的某个房间的门牌号是类似的,0X0A就是这个地址保存的内容,也就是现实中这个门牌号所对应的房间中存放的东西。

一个地址中可以保存8bit也就是一个字节的内容,所能保存的数据范围就是0--255,如果是有符号的,那就是-128--127。显然这个数据范围有点小,那么要保存一个int类型的数据就需要连续的四个地址。假设编程中有这样一条语句

int a=328; 通俗来讲,应该是这样的(将328写成16进制,按高地位写进相应的地址)

技术分享

那么指针也是一样的,保存一个指针也需要4个字节的内存(各平台不同),就像现实中有一个门牌号,这个门牌号对应的房间中存放着相应的东西。只不过不同的类型,翻译的意义也就不一样,如果是int类型,那么房间的内容就翻译为值为xx的整数,如果是指针类型,那么房间的内容就翻译为一个地址。

假设这样一个程序:

#include <iostream>
using namespace std;
int main()
{	
	int a = 10;
	int *p;
	p = &a;
	cout << p << endl;
	cout << &p << endl;
}
输出如下:

技术分享

那么内存中的结构就是这样的

技术分享

其实有时候指针难理解就是因为申明的时候带个 * ,如果把这个星号和基本类型连在一块就很好理解了,比如 int* p,p也是一个普通的变量,它的类型是int* ,它的内容中保存的是一个地址,这个地址指向一个变量,这个变量的类型是int。还有一个地方就是指针内容中保存的这个地址,其实说白了就是一个32bit(平台差异,有所不同)的二进制数据,如果把它翻译理解成为一个整数,就是0--(2^32)-1中任意一个,可以是10,也可以是100、456132,只要不超出数据范围就行。也可以在编程的时候强制数据转换,将一个地址转换为一个int类型的整数。假设有这样一段代码:

#include <iostream>
using namespace std;
int main()
{	
	int a = 10;
	int b;
	int *p;
	b = (int)&a;
	cout << &a << endl;
	cout << b << endl;
	cout << *(int*)b<< endl;
}
输出是这样的:

技术分享

第一行就是变量a的地址,0X 0036 FD00,在程序中我们将a的地址强制转换为int类型,赋值给b,输出b,也就是3603712,因为b是一个整型变量,所以输出的时候是10进制显示,将3603712写成16进制就是0X 0036 FD00,在最后一行中,又将b的数据类型强制转换为 int*(和int一样,int*也是一种数据类型),然后用间接引用运算符*,取出这个地址保存的内容,也就是a的值10。

有关指针有很重要的两个运算符,一个是地址运算符&和间接引用运算符*。&很好理解,就是取出变量在内存中的地址,间接引用运算符*取出一个地址中保存的内容,很像读操作。在嵌入式编程中,假设知道某一段flash的地址,就可以用*运算符读出其中的内容。

和指针密切相关的一种数据结构就是数组,平时用数组的时候可能还不会觉得,其实数组也是和地址密切相关的,只不过这些底层的操作已经很好的被封装了。假设有这样一条语句,int num[3]={1,2,3},那么就会在内存中开辟出连续12字节长度的内存,每四个字节保存一个int类型的变量。num就是这一段内存的首地址。假设有这样一段代码

#include <iostream>
using namespace std;
int main()
{	
	int num[3] = { 1, 2, 3};
	cout << num << endl;
}

输出是这样的

技术分享

那么内存中的结构就是这样的
技术分享

给0X 0032 FA60这个地址起个别名就叫做num,也就是数组名,也可以说数组名就是这段内存的首地址。假设我们进行num[2]运算,[ ]也是一种运算符,它会将这段首地址偏移n*sizeof(t)个字节,取出其中保存的内容,其中n就是[ ]运算符中的数,t就是数组的类型,如果是int,那么就是sizeof(int)。既然数组的名字就是数组的首地址,那么就可以将这个地址赋值给指针,接着对指针的操作和对数组的操作就是等效的。假设有这样一段代码

#include <iostream>
using namespace std;
int main()
{	
	int num[3] = { 1, 2, 3};
	int* p;
	p = num;
	cout << p[1] << endl;
	cout << *(num + 2) << endl;
}
将num赋值给指针p以后,对指针的操作和对数组名的操作是等效的。num是一个地址,那么对地址+2,这和普通的+运算符是不一样的,相当于普通的+运算符加n*sizeof(t),n就是+运算符后面的操作数,t就是数组的类型,本例中是int,等于是将num的地址偏移8,也就是到了上图中0X 0032 FA68这个位置,再用简介引用操作符*取出其中的内容,也就是3。其实就等效于num[2]。

指针学习笔记

标签:

原文地址:http://blog.csdn.net/u011411195/article/details/51123400

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!