`
he91_com
  • 浏览: 378249 次
文章分类
社区版块
存档分类
最新评论

指针本质论

 
阅读更多
				指针本质论 
1.指针是什么? 和一般变量有什么区别?
	指针就是地址,和一般变量没有本质区别,仅仅是它有自己的规则。
int a=100;  
int *p=&a;

printf("%d\n",a);    // 100
printf("%p\n",p);    //0xbfa47858

a是一个变量名,类型是int,值是100,a有自己的地址&a
p是一个变量名,类型是int*,值是0xbfa47858,p有自己的地址&p

我们发现指针和普通变量没什么区别,那到底为什么我们觉得它难呢?

主要是指针是一种新的变量类型,它有自己的一套运算规则。

2.指针的运算规则

#1.指针的类型

	定义不同的指针,它有自己的类型.  如,
int *p       ->    int 型指针
char *p      ->    char 型指针
int (*p)[2]  ->    int型的数组指针
void (*p)()  ->    函数指针
...
果然很多,怪不得那么难.

#2.指针的强制类型转换

int *p;
char *q=(char*)p; 

这是把int型指针转换成char型指针,和变量的强制类型转换一样,so easy...
	
#3.指针的加减规则
指针有自己一套加减规则。

int a=100;  
int *p=&a;
printf("%d\n",a);    // 100
printf("%p\n",p);    //0xbfa47858
p=p+1; p是int型指针,sizeof(int)=4,所以p+1其实加的是一个int型变量的大小,所以p=0xbfa4785c

char *p;
p=0x77777777;   //p是一个变量,可以给p直接赋值
p=p+1; p是char型指针,sizeof(char)=1,所以给p+1其实加的是一个char型变量的大小,所以p=0x77777778

....

我们发现,还是so easy...


#4. 指针的解引用,也就是*p

解引用是有步骤的
	如 type *p;  求*p  //type是类型
     1.找到指针所存放的内存单元
     2.从这个地址开始读取sizeof(type)个字节大小
     3.把读取的内容按type类型解释,解释出来的就是*p

eg.
short a=256; 
short *p=&a;

printf("%d\n",*p);  //256,so easy...

1.p所对应的就是a的地址
2.a->00000001 00000000,读取2个字节,所以读取到的就是00000001 00000000
3.把00000001 00000000解释成为short类型,明显是256

char *q=(char*)p;
printf("%d\n",*q);  //0, maybe not so easy....
1.p所对应的就是a的地址
2.a->00000001 00000000,读取1个字节(sizeof(char)),所以读取到的就是00000000(小段字节序)
3.把00000000解释成为char类型,明显是0

如果上面的都懂了,那么下面的就不是难事

我要读取a的高地址,怎么写? 
char *q=(char*)p+1;  //(char*)p指向a的地地址,+1,因为是char型指针,所以加一个字节,指向a的高地址 
printf("%d\n",*q);   // 读取sizeof(char)个字节,即00000001,所以是输出1


short a=256; 
char *p=&a;
printf("%d\n",*(short*)p); 
p指向a的低地址,将p强制转换为short型制作,所以读取sizeof(short)个字节,所以输出256

short a=256;
char *p=&a;
printf("%d\n",*((char*)(short*)p+1));  //输出结果为1,so easy... 


再来点有挑战的吧!
short a=256;
char *p=&a;
printf("%d\n",*(short*)(*(int*)&p));  //256
如果这道题目做对了,那么指针也就被你俘虏了。
关键就是这是为什么是int*,主要是指针所占空间是4个字节(32位主机)

#5.那么数组指针和指针数组到底怎么回事?

数组指针是指针,指针数组是数组,就这区别

数组指针只存在与多维数组吗?,下面将带给你不一样的认识
我们知道数组名所代表的就是数组首地址,那么对数组名取地址得到的是什么?

一维数组:
int a[2]={1,2};

(gdb) p a
$5 = {1, 2}

(gdb) p &a[0]
$6 = (int *) 0xbffff0c0   //&a[0]是普通int型指针
(gdb) p &a[0]+1
$7 = (int *) 0xbffff0c4  //所以+1加的是sizeof(int)

(gdb) p &a
$8 = (int (*)[2]) 0xbffff0c0   //一维数组名的地址其实是个数组指针,这个就有点像sizeof(a)返回的是整个数组大小
(gdb) p &a+1
$9 = (int (*)[2]) 0xbffff0c8   //所以+1加的是2*sizeof(int)

(gdb) p a+1
$10 = (int *) 0xbffff0c4    //我们发现当数组名用于表达式时自动转换为数组首地址


二维数组:
int a[2][2]={1,2,3,4};

(gdb) p a
$1 = {{1, 2}, {3, 4}}
(gdb) p &a[0]
$2 = (int (*)[2]) 0xbffff0b8  //因为是二维数组,所以&a[0]是数组指针
(gdb) p &a[0]+1
$3 = (int (*)[2]) 0xbffff0c0  //所以+1,加的是2*sizeof(int)

(gdb) p &a
$4 = (int (*)[2][2]) 0xbffff0b8  //对数组名取地址代表的是整个数组的首地址,有点整体的意思
(gdb) p &a+1
$5 = (int (*)[2][2]) 0xbffff0c8  //所以+1加的是sizeof(a)

(gdb) p a==&a
$7 = 1
(gdb) p a==&a[0]
$8 = 1
(gdb) p a==&a[0][0]
$9 = 1    

其实从值的角度来说,a,&a,&a[0],&a[0][0]都是数组首地址的值

int a[2][2]={1,2,3,4};
int (*p)[2]=a;

如果我要输出3:
printf("%d\n",**(p+1)); //3
这个p已经是指针了,为啥要**呢,难道这是指针的指针?

在一维数组中我们知道: *(a+i)=a[i],在二维数组中同样成立.
*(p+1)=a[1],只不过此时的a[1]代表的是第二行的首地址,所以会出现**的问题.

printf("%d\n",*(int*)(p+1));  // 3,这样写我想更清楚,易懂


我们来点难点的吧?

short a[2][2]={256,256,256,256};
short *q=a[1];
printf("%d\n",**(char(*)[2])q); // 0,你对了吗?

q指向的是a[1]首地址,即256,然后将256当作2列char型数组,00000001 00000000,
所以最后输出来的是低地址的值->0


再来一个更变态的吧!!

char a[2][4]={8,7,6,5,4,3,2,1};
short *q=a;
printf("%d\n",*(*(((short(*)[2])q)+1)+1)); //小段字节序算

答案是258,你做对了吗?

解释:
(short(*)[2])q               ->  将q转换为short型的数组指针
*(((short(*)[2])q)+1)        ->  此时指向的是4
*(*(((short(*)[2])q)+1)+1)   ->  此时指向的是2,00000010 00000001,而00000010是低地址,
所以最后为00000001 00000010  ->  258


分享到:
评论

相关推荐

    C#本质论(中文版)

    C#本质论(中文版) 继承 数组 集合 反射 内存管理和指针

    C#5.0本质论第四版(因文件较大传的是百度网盘地址)

    C#5.0本质论第四版,高清扫描的,对C#5.0技术讲的比较详细,第1章 C#概述 1 1.1 Hello,World 1 1.2 C#语法基础 3 1.2.1 C#关键字 3 1.2.2 标识符 4 1.2.3 类型定义 5 1.2.4 Main 6 1.2.5...

    Mouse_control:使用手势控制鼠标指针

    使用手势控制鼠标指针 抽象的 这个项目是一个鼠标模拟系统,它执行由鼠标执行的与您的手部动作和手势相对应的所有功能。 简而言之,摄像机会捕获视频,并根据您的手势,您可以移动光标并执行左键单击,右键单击,...

    网络安全论文.doc

    引起缓冲区溢出问题的根本原因是 C(与其后代 C++)本质就是不安全的,没有边界来检查数组和指针的引用,也就是开发人员必须检查 边界(而这一行为往往会被忽视),否则会冒遇到问题的风险。标准 C 库中还存在许多...

    编程新手真言......

    8.32 设计方法论 196 8.33 真正的interface 198 8.34 真正的对接口进行编程 200 8.35 实践方法之极限编程 200 8.36 设计模式复用与框架复用 201 第三部分 进阶: C,C++代码阅读与控制 201 第9章 语法与初级标准库 ...

    基于JAVA超级玛丽游戏GUL 设计软件源码+WORD毕业论文文档.zip

    浏览器和Java类库一起从本质上决定了Java应该用来写哪种类型的应用程序,而高速的游戏和图象则不在其中。这给Java带来了不好的影响,因为人们注意的不是语言,而是它的运行环境。现在,浏览器已经不能控制一切了,...

    网络安全论文(1).doc

    引起缓冲区溢出问题的根本原因是 C(与其后代 C++)本质就是不安全的,没有边界来检查数组和指针的引用,也就是开发人员必须检查 边界(而这一行为往往会被忽视),否则会冒遇到问题的风险。标准 C 库中还存在许多...

    动态无状态计算机:我提出了一种仅基于连接,链接或指针在“逻辑几何”上运行的“动态无状态计算机”,这比在数学二进制位上运行的三个基本布尔逻辑门更简单每个电脑都在那里吗

    动态无状态计算机 ...一种用经典位的运算来描述,另一种用量子态的演化来描述,因此通用图灵机以及所有经典计算机可能无法模拟某些行为以相反,从物理上讲,有可能实现一种与经典计算机科学本质上不同的新

    内存操作模块!通过汇编和API实现!-易语言

    以实现对齐如果结构像平时那样直接声明为结构时,E会自动把结构转换为C/C++中的标准的那种,但结构写为通用型时E只简单传递结构指针不做转换R_指针到数据_变量()【本质是将源数据的值写入目标变量,源数据不是基本...

    华为编程开发规范与案例

    其中红色部分巧妙的利用指向指针的指针为指针puc_card_config_tab赋值,而在兰色部分使用该指针。但在Get_Config_Table函数中有可能失败返回而不给该指针赋值。因此,以后使用的可能是一个非法指针。 指针的使用是...

    COM实验报告.pdf

    其中可以选择的组件对象类型很多,但本质上,就是让向导帮忙加上一些 默认接口。 3. 增加自定义类 CMath(接口 IMath),见图 5。 图 5 填写类名 4. 填写属性接口,见图 6。 图 6 选择属性 4 5. 添加接口成员函数 图 7 ...

    windows驱动开发技术详解-part2

    开发的本质。 本书是作者结合教学和科研实践经验编写而成的,不仅详细介绍了Windows内核原理,而且介绍了编程技 巧和应用实例,兼顾了在校研究生和工程技术人员的实际需求,对教学、生产和科研有现实的指导意义 ,...

    Windows驱动开发技术详解的光盘-part1

    归纳了多种调试驱动程序的高级技巧,如用WinDBG和VMWARE软件对驱动进行源码级调试,深入Windows操作系统的底层和内核,透析Windows驱动开发的本质。 本书是作者结合教学和科研实践经验编写而成的,不仅详细介绍了...

    我的编程感悟(中文PDF)(共37M二分卷)分卷二

    9.5.3 再论动态内存分配 269 9.6 template 272 9.6.1 封装C++的成员函数调用 272 9.6.2 常数数量的对象复制 274 9.6.3 对象计数 275 9.6.4 避免重复代码 277 9.6.5 选择最佳的容器 279 9.6.6 延迟运算 281 9.6.7 ...

    我的编程感悟(中文PDF)(共37M二分卷)分卷一

    9.5.3 再论动态内存分配 269 9.6 template 272 9.6.1 封装C++的成员函数调用 272 9.6.2 常数数量的对象复制 274 9.6.3 对象计数 275 9.6.4 避免重复代码 277 9.6.5 选择最佳的容器 279 9.6.6 延迟运算 281 9.6.7 ...

    Linux多线程服务端编程:使用muduo C++网络库

    1.9再论shared_ptr 的线程安全.. . . . . . . . . . . . . . . . . . . . . . . . 17 1.10shared_ptr 技术与陷阱. . . .. . . . . . . . . . . . . . . . . . . . . . . . 19 1.11对象池. . . . . . . . . . . . . ....

Global site tag (gtag.js) - Google Analytics