指针理解的两个要点: 1.指针是内存中一个最小单元的编号,也就是地址。 2.平时所说的指针一般指指针变量,是用来存放内存地址的变量
也就是说,指针就是地址,口语中说的指针通常指的是指针变量。 事实上这样的讲法任然有些晦涩难懂,那么咱们换个说法。 其实指针(变量)是一种数据类型,和int、long、char之类的是一样的作用,用来给数据分类储存的。只不过指针是用来储存地址数据的。(所以,存放在指针中的值都被当成地址处理。) 那么地址又如何理解,在广阔的内存空间上存着许多对象,这就需要某种方式来表示各个对象内存中的位置 ,这就是地址。可以理解为整块内存是一栋楼,而每一块内存都有对应的门牌号。 总结 指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
指针存储的是地址,而一个字节给一个对应的地址比较合适。 对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0); 那么32根地址线产生的地址就会是:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 … 11111111 11111111 11111111 11111111
这里就有2的32次方个地址。 每个地址标识一个字节,那我们就可以给 (2^32Byte == 2^32/1024KB == 2^32 /1024/1024MB==2^32/1024/1024/1024GB == 4GB) 4G的空间进行编址。 同样的方法,那64位机器,如果给64根地址线,那能编址多大空间,自己计算。 这里我们就明白:
在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以 一个指针变量的大小就应该是4个字节。 那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址。
总结: 指针变量是用来存放地址的,地址是唯一标示一个内存单元的。 指针的大小在32位平台是4个字节,在64位平台是8个字节
正如前文所说指针变量存储地址,不同的数据类型占据不同的空间大小。所以也需要不同类型的指针类型。
指针的定义方式是: type + * 。
一般情况下,指向Type型对象的指针,即Type型指针并不只是表示指向“OO号”,更确切的说是指向“以OO号为首地址的Type型对象。除了使用一些特殊技巧的情况下,Type类型指针一般不会指向Type类型以外的对象。
空指针是能够和指向对象的指针明确区分的什么也不指向的特殊指针。表示空指针的对象式宏,是称为空指针常量的NULL。
单目运算符& | &a 取得a的地址(生成指向a的指针) |
---|---|
单目运算符* | *a * a指向的对象 |
值得注意的是arr[i]与*(arr+i)是一样的,我们都知道单独数组名在一般情况下是首元素的地址,而地址加减整数 |
int main()
{
int n = 10;
char* pc = (char*)&n;
//&n取出来是int*类型,存放到char*指针中去
//所以加上了强制类型转换
int* pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc + 1);
printf("%p\n", pi);
printf("%p\n", pi + 1);
return 0;
}
这里我们看到,虽然同样是加一,但是+1后的差距不同。
指针的类型决定了指针向前或者向后走一步有多大(sizeof(类型)) 指针加减整数代表指针指向的地址向后或者向前挪动。
两个指针相减,指针必须指向一段连续空间,减完之后的结构代表两个指针之间相差元素的个数
框起来的是元素之间的个数;
指针-指针=指针之间的元素个数 或者在数组中理解为下标-下标
注:高地址-地地址为正数,反过来为负数。
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s;
}
for(vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0; }
//简化代码
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0; }
实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。
标准规定: 允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。