前言:
大家好,经过上一篇C语言之指针(一)中,我们了解到了内存和地址以及指针变量、地址等一系列的指针知识,这些知识点作为指针学习的前备工作,这种知识更像是一种“内功”一样,知道了这些概念后,也更加有利于我们对于接下来的指针学习。这里将附上“C语言之指针(一)”的链接,供大家参考。C语言之指针(一)-CSDN博客
一、指针变量的大小
在前面我们了解到,32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产生的2进制序列当作是一个地址,那么一个地址就是32个比特位,也就是需要4个字节大小才能够存储。(一个字节=8个比特位)
如果指针变量是用来存放地址的,那么在32位机器下,指针变量的大小必须得4个字节才能够存储地址。
同理,在64位机器下,有64根地址总线,那么一个地址就是64个比特位,存储起来就是8个字节的空间。
代码如下:
#include <stdio.h>
//指针变量的⼤⼩取决于地址的⼤⼩
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)
int main()
{
printf("%zd\n", sizeof(char *));
printf("%zd\n", sizeof(short *));
printf("%zd\n", sizeof(int *));
printf("%zd\n", sizeof(double *));
return 0;
}
x86版本运行结果如下:
x64版本运行结果如下:
结论:
(1)32位平台下地址是32个bit位,指针变量⼤⼩是4个字节。
(2)64位平台下地址是64个bit位,指针变量⼤⼩是8个字节。
(3)注意指针变量的⼤⼩和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的。
二、指针变量类型的意义
首先,指针变量的大小和类型 无关,只要是指针变量且在同一个平台下,其大小是一样的,那么我们为什么还要去了解指针变量的类型呢?接下来我们深度解析一下。
3.1指针的解引用
接下来,我们就对两段代码来解析一下:
首先对于代码一来说,:其中创建的指针p的类型为“int*”类型,而在内存中的解引用操作时,“int*”类型一次可以访问4个字节,如下图所示:
由此可见,对于“int*”类型的解引用,一次改变的是4个字节,也就是将变量n的值改为0.
对于代码二来说,其中创建的指针p的类型为“char*”类型,而在内存中的解引用操作时,“char*”类型一次可以访问1个字节,如下图所示:
在内存中,一个int类型的变量有32位,只改变其中一个字节,即把上图中填充的部分改为0。
结论:指针的类型决定了对指针解引⽤的时候有多大的权限(⼀次能操作几个字节)。
比如: char* 的指针解引用就只能访问⼀个字节,而 int* 的指针的解引用就能访问四个字节。
3.2指针的加减(+/-)
先从一段代码入手:
#include <stdio.h>
int main()
{
int n = 10;
char* pc = (char*)&n;
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;
}
代码运算结果:
由此可知,对于一个char*类型的指针,其加一则地址会向后跳过一个字节,对于一个int*类型的指针,其加一则地址会向后跳过4个字节。
结论:指针加减的结果最终还是指针,即:指针+/-整数=指针。
四、const修饰的指针
4.1const修饰变量
变量是可以修改的,如果把变量的地址交给一个指针变量,通过指针变量也可以修改这个变量,但是如果我们希望能够对这个指针变量加上一些限制,这就是const的作用。
还是以代码为例:
以上代码中,m的本质是变量,是可以修改的,但是如果加上const这一限制条件,就使得m不可被随意修改。可如果非要改变m的值,那就要绕道而行,通过其地址的方法来改变。代码如下:
如此一来,m的值就可以被修改了,但是这里我们要思考一个问题,既然一开始要给m加上const来修饰,其目的就是为了m不被改变,但是我们发现通过地址也可以轻松的修改m的值,这样似乎前面的const就好像是有些多此一举了,这显然是不合理的,所以我们应该让p即使拿到m的地址也不可修改其值。
4.2const修饰指针变量
上述中我们了解到,const可以修饰变量,那么同理,const也可以修饰指针变量,其修饰方法有两种:
(1)const int* p / int const * p----const在*的前面
(2)int* const p----const在*的后面
对于两种const的修饰,其效果自然是不尽相同。
首先是const在“*”之前,它修饰的是*p,也就是指针指向的内容,它可以保证指针指向的内容不能通过指针来改变,但是可以修改指针指向的方向,也就是指针变量本身可以改变。
其次是const在“*”的右边,这时const修饰的是p也就是指针本身,它可以保证指针p指向的方向不发生改变,但是却可以改变通过解引用p所指向的内容。
接下来通过一段代码来直观理解这两种修饰方式:
#include<stdio.h>
int main()
{
int n = 10;
int m = 20;
const int* p = &n;
*p = 30;//当const在*之前时,修改其指向的内容时会报错
p = &m;//当const在*之前时,修改其指向的方向时,不报错。
return 0;
}
#include<stdio.h>
int main()
{
int n = 10;
int m = 20;
int* const p = &n;
*p = 30;//当const在*右边时,可以改变其指向的内容。
p = &m;//但如要修改其指向的方向,就会报错
return 0;
}