C指针本质探究
-
指针是什么
我的解释是,把内存看成能容纳东西的房间。这个房间的大小是一个字节(8位)。房间可以容纳东西(内容),房间有自己的门牌号(地址)。
例如:
int a = 5;
我们申请了一个名为a的房间,这个房间一共由四个基本房间组成(32位),这个房间里存放的内容为5,那它的门牌号呢?c语言不需要我们直接接触地址,如果学过汇编就很清楚这个问题了,c中我们可以用 &a 取得a的地址,即这个房间的门牌号。
上面是示意图,能类比内存的模样。如果我们认为第六个房间里放的是门牌号,那么它指向的是一号房间。
我们定义
int *p = &a;
这时候p这个房间里面就存放了a的门牌号,注意p自己也是房间,也有门牌号。
因为不论何种类型的指针存放的都是地址,所以其所需的房间大小都是一样的。
-
指针类型的作用
定义一个指针变量,我们需要这样做:
int *p;
前面提到所有类型的指针所需的空间都是一样大的,为什么指针需要分类型?
我们这样访问指针:
int b = *p;
访问的时候出了需要知道目标房间的门牌号,还要知道由多少间基本房间(字节)组成。char类型占一个基本房间,int类型占4个基本房间(32位),自定义的类型也许更多。所以访问的时候仅仅知道房间的门牌号还是不够的,还需要知道其大小。我们用*p的时候,编译器需要知道我们要从其地址开始读几个字节的数据,所以我们需要定义指针的类型。
例:
#include <stdio.h> #include <stdlib.h> struct TY { char s[100]; }; int main() { int *pa = 0x0; char *pb = 0x0; TY *pc = 0x0; ++pa; ++pb; ++pc; printf("%d %d\n",pa,sizeof(int)); printf("%d %d\n",pb,sizeof(char)); printf("%d %d\n",pc,sizeof(TY)); return 0; }
void *类型指针加大了c指针的灵活性。我的上一篇博文《void*指针实现支持所有数据类型的容器》,就是用void*实现的,在计算偏移地址的时候,我把void*强制转换成char*,这样每次++就会移动一个字节。
-
指针的作用
指针很灵活,不仅能够访问数据,还能访问函数。
如果有汇编基础,就知道在内存里数据和代码是没有区别的。所以指针能够指向数据,也就能够指向函数代码入口。
用指针访问数组,传递参数,访问某个特定地址,有用的地方很多
-
指针的潜在风险
c中的指针是允许强制转换类型的。如
int *a; char c; a = (int*)&c;
这样是允许的,但是有什么风险?
结合上面说的,指针类型制定了其访问的长度。如果按上面那样做,再有这样的句子:
*a = ‘c’;它修改的就不仅是c的哪一个字节了,而是四个字节。虽然执行
printf(“%c\n”,c)
输出的是c。那是因为小端机的原因,结果没错,但是把后面三个不属于c的字节给写了,越界访问呐。
还有指针悬空,内存泄露等问题。所以用指针时候需要注意。