细谈C语言指针第一篇目——初识指针

有很多初学C语言的小伙伴留言表示指针入门太困难了,那么今天想和大家一起来叨一叨C语言指针的那些事😘

一、什么是指针和指针变量:

指针是内存中最小单元的编号,其中这里的内存中最小单元指的是字节(Byte),而它们的编号在计算机邻域则有个更为专业的称呼叫做地址。因此我们说:指针 = 地址。一个字节和一个地址之间的关系是一一对应的关系,一个字节在内存中只对应一个唯一的地址编号,一个地址编号标识着内存中唯一的字节单元。这样我们用户通过指针这个东西就能很方便地访问内存中的空间

另外我们平常口头上常常提到的那个指针,一般来说它指的是指针变量,指针变量和指针不同,指针变量是用来存放内存地址的。又因为我们前面提到说“ 指针 = 地址 ”,因此我们也可以说是指针变量是用来存放指针的,但是这种说法总觉得还是太拗口了,因此,你看到最多的说法还是指针变量用来存放地址。

总结来说地址,指针和指针变量它们三者之间的关系:

  • 对于计算机来说,指针就是地址;
  • 我们日常口语中的指针是指针变量,指针变量用来存放一个字节的地址。

二、&取地址操作符

这应该是老朋友了,在我们第一次使用scanf尝试输入一个变量地时候我们就用到了这个东西——scanf("%d", &a);这是C语言专门用来取出一个变量地址的符号。

注意,这里我们说的是变量的地址,地址是对内存里面单位字节的唯一标识,但是在C语言里面直接对一个单位字节的数据取地址是非常少的:除了char数据类型以外,几乎所有的数据类型的大小它都是大于一个字节的。也就是说只有在我们对一个char类型的变量进行取地址的时候,那访问的是单位字节,那没有任何疑问,直接把那个字节的地址,OK,那拿过来,你用吧!

但如果是大于一个字节的,比如说int——4个字节,那怎么办?这4个字节的地址我把哪个拿过来作为这个int类型变量的地址最为合适?我把4个里面的随便哪个拿过来作为变量地址可不可以呢?

这显然是没有道理的,我们希望看到的结果是一个变量也应该是唯一的地址编号进行标识,C语言的委员会也认识到了这个问题,并作出了如下规定:对于多字节的变量的地址,将它内存从低到高第一个字节的地址拿过来作为该变量的地址。什么意思呢?大家可以看下面这个例子:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a = 0x1234;//这是十六进制的表达方式,两个十六进制是四个比特位
	printf("%p", &a);//地址的打印请使用%p格式符
}

运行截图:

释:我们注意看红色的部分,首先是运行窗口部分,运行结果是0x0113FD74,这是我们&a的值。

其次我们再来看一下内存截图部分,在内存里面34和12都是16进制的形式,因此它们两个分别占据内存中不同的两个字节空间。既然是不同的字节空间,就会有不同的地址:

其中对于0x34这一部分来说它的地址编号是0x0113FD74,而对于0x12这一部分来说它的地址编号是0x0113FD75,0x12相较于0x34而言显然是高地址,&a的值拿到的a变量内存空间中内存地址编号较低的那一部分字节的地址编号,因此&a的值和0x34地址编号是相等的

三、如何去定义一个指针变量:

地址编号我们通过取地址操作符拿到了,我们希望能用一个容器来存放这个地址——于是指针变量粉墨登场。

关于指针变量的定义可以看以下两个例子:

//这里的p1和p2都是指针变量
int* p1;    //p1的定义还可以写作int *p1;
double* p2; //p2的定义还可以写作double *p2;

其中这里的“int”或者说“double”告诉用户说:这个指针里面放着的是哪种类型变量的地址,int就表示放着的地址指向的是int类型的变量,double则表示放着的地址指向的是double类型的变量,这是第一点。

第二点这里的符号 * 是告诉我们的用户说变量p1亦或是p2它是一个指针,而不是一个普通的int类型的变量。我们习惯于用字母p去指代一个指针变量,因为它是单词point(指针)的首字母。最后,值得我们大家去注意的是,这个符号只要是位于类型名和变量名之间,它靠近哪一个都是没有问题的。

最后也正是由于这一点,对于一些初学者来说,在理解上比较容易出问题的是,误把 int* 当作是一个类型,于是在一些特定的代码场景下,就可能会出现下面小明同学的这种理解:

小明同学😎分析代码一:
int* p, q;    --分析结果:p,q都是指针。    //评价:error

小明同学😎分析代码二:
int *p, q;    --分析结果:p是指针,q是int类型的变量//评价:right
​

其实两个代码中都只有p是指针,q都是int类型的变量,换句话说C语言里面并没有 int* 这种数据类型 ,符号 * 针对的是变量本身,而非数据类型。如果你希望q也是一个指针,请也给它一个 * 的帽子:即int *p, *q。

四、指针变量的大小:

对于C语言而言,只要是一个变量,它就应该有一个明确的以字节为单位的大小,指针变量千千万,比如存放char类型变量地址的指针变量,亦或是int类型变量地址的指针变量。总之很多很多对不对,那么对于不同的指针变量它们在内存中的大小是怎样的呢?

我们使用sizeof单目操作符来做点事情看一下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	char c = 0;
	char* pc = &c;
	printf("c的大小%d ", sizeof(c));
	printf("存放变量c地址的指针大小%d\n", sizeof(pc));

	int a = 0;
	int* pa = &a;
	printf("a的大小%d ", sizeof(a));
	printf("存放变量a地址的指针大小%d\n", sizeof(pa));

	double d = 0;
	double* pd = &d;
	printf("d的大小%d ", sizeof(d));
	printf("存放变量d的地址指针大小%d\n", sizeof(pd));
}

x86架构下运行截图

我们发现指针变量的大小并不取决于它里面放的是哪种类型变量的地址,无论是 char* ,int*亦或是double*它们的大小都是4个字节(sizeof操作符可以让你获取到一个变量的大小,且以字节为单位),实际上指针变量的大小取决于你当前编译器的架构,我们这里是x86——32位环境架构,我们再换成x64——64位环境架构来看一下运行结果:

x64架构下运行截图

指针变量的大小在64位环境架构下都变成8Byte的大小了……为什么是这样的呢?实际上这个故事还要从地址的产生方式说起:

地址实际上是由一些计算机内部电线产生的,这些专门用来表示地址的电线在计算机里面有一个专业的称呼叫地址线,并将地址线通电时的状态记作1,不通电时的状态记作0。由此对于内存中的每一根地址线都有2种状态,0或者1。

其中在x86也就是32位环境架构机器下,用32根地址线来表示一个地址编号,一个0或者1的内存大小是1Bit,32根地址线产生的地址编号也就是32Bit的大小,然后同时考虑到8Bit=1Byte,所以32Bit就是4字节的空间大小,因此在这样的环境架构下一个指针变量的大小就是4Byte。

同理也可以推出x64也就是64位环境架构机器下的指针变量是8Byte。

最后的注意事项:

指针变量才有大小的概念,地址编号是没有大小的说法的。因此你不能说地址的大小是4个字节,这是错误的。

这是因为地址编号本身作为一种编号来使用它只有标识的作用,它是人潜意识里面的一种概念,是没有大小的这种说法的;只是在我们需要将一个地址用一个容器,也就是指针变量存放起来的时候,这时候才有了给它分配内存空间,也才有了内存大小的概念。

作者语录:

通过这一博客的学习,我想你对地址,指针和指针变量有了非常清晰的认识。同时也知道了一个地址它是如何产生的。一个指针变量有什么用,以及它是如何被定义的,它的大小是多少……等等这样一些基本的问题,这对于我们入门指针的学习有着极其重要的作用。

在后续的博客创作中,博主也将继续推进这个栏目的更新,期待和大家一起揭秘更多指针的秘密。我们一起加油吧,奥力给!!!🙂🙂🙂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值