C语言篇 -(1)初识C语言 – (11)指针,结构体

      • 指针
        • 内存
        • 指针变量的大小

今天,我们来讲一下指针和结构体

指针

都说指针很难,其实很好理解的,我来带你了解一下

内存

说指针就不得不说一下内存
内存是电脑上特别重要的存储器
我们可以打开任务管理器

在任务管理器里面可以看到内存的使用情况,有每个软件运行所占的内存,可以看到计算机中程序的运行都是在内存中进行的

但是我们需要有效的使用内存空间,这里我们买个4G内存的电脑,可以把4G的内存分成一个一个的小空间,这样就会方便管理

就像这样,

这是一大块儿的内存,我们要怎么去管理它呢” />

里面有很多的房间,但是都没有编号,我买了个外卖,我说有一个房间是我住的,送外卖的也不知道我在那个房间,只能一个一个的去找.

但是我给每一个房间都编上号,像这样

我说我在305号宿舍,送外卖的是不是唰的一下就找到我了
内存就是13栋宿舍楼,内存单元就是房间,内存这么大的一块儿空间,分成一个一个的内存单元,每一个内存单元都有一个地址,这个地址就是房间的编号,是不是就能很好的管理内存了

我们再来说一下地址线
我们的电脑有32位的,也有64位,这里指的是有32条地址线和64地址线,地址线通电就会产生脉冲,每一个地址线都有两种状态,也就是二进制里面的1/0
这里就说32位的电脑

这里有32根的地址线

每根地址线都有1/0的选择

它的组合有:

0000 0000 0000 0000 0000 0000 0000 00000000 0000 0000 0000 0000 0000 0000 00010000 0000 0000 0000 0000 0000 0000 0010…………1111 1111 1111 1111 1111 1111 1111 11101111 1111 1111 1111 1111 1111 1111 1111

一共有223种,也就是4,294,967,296
所以有223个编号,对应223个地址

4,294,967,296byte4,294,967,296÷1024=4,194,304kb4,194,304÷1024=4,096MB4,096÷1024=4GB

所以32位的电脑可以访问4GB大小的空间

我们现在常见的都是64位的电脑,类比上面,可以知道它可以访问很大的空间,它是有这个能力的

我们认定1个地址管理1个字节的大小
但是为什么不是一个bit呢?
之前我们讲过计算机最小的单元是bit(比特位),1个字节=8个bit

我来解释一下

创建一个数据类型里面最小的字符类型char a;,这个a的大小是一个字节,

如果我们一个地址只对应一个bit,但是一个最小的char类型的变量a就占8个地址,是不是太浪费了
就像送快递,我在13栋305宿舍,你非得给我送到13栋305宿舍第5块瓷砖上,是不是没有必要

这样有什么用呢?
来看一下代码的运行过程

int main(){int a = 0;&a;return 0;}

这里的int a = 0;的意思就是向内存申请4个字节的空间来存放0,

&是取地址操作符(之前没有讲),它的作用是把a这个变量的地址给取出来

我们来调试一下
(如何调试看这一篇博客的问题三)

打开监视(在调试开始的时候才有)
调试->窗口->监视->输入监视的变量



看到没有,a被创建了,&a也把地址取了出来,它的地址是0x009dfa5c,这个地址里面存储了10这个值,

我们再打开内存(在调试开始的时候才有)
调试->窗口->内存

自动改为4
a的地址0x009dfa5c填在里面,回车,就会查到这个地址

红框就是地址,橙框就是内存中的数据,紫框就是内存数据的文本分析(编译器想尝试分析一下你里面存的是什么东西,很明显,是不准确的)

来说一下橙框里面的
0a 00 00 00
这个是十六进制
a代表的就是存储的值10

你发现没有,红框里地址0x009dfa5c下面的不是0x009dfa5d,而是0x009dfa60,相差3个地址
橙框里0a就是地址0x009dfa5c,后面的00 00 00分别是0x009dfa5d 0x009dfa5e 0x009dfa5f
这三个地址没有写,

我们开辟了4个字节,分配了四个地址,为什么a的值存在第一个而不是后面呢?以后我们会讲到

之前我们存的是a的值,那么我们怎么把&a取出来的地址存起来呢?

int main(){int a = 10;int* p = &a;return 0;}

int* p就是指针变量p,跟之前讲的那些变量一样,都是变量,指针变量p可以把&a取出来的地址存起来
int* pp指向的就是a的地址,而*就是说明p是一个指针,int指的是p所指向a的地址所存放的类型是int类型

int main(){char a = 'w';char* p = &a;return 0;}

char* pchar就是指针变量p所指向a的地址所存放的类型是char类型

我们每一次运行的时候,变量a存的地址都是不一样的,而且地址我们是不能改的,编译器已经把地址给你分配好了,不能随便改,这一点要记住(用这个printf("%p",p);打印一下试试看,看看地址是不是在变化)

有一句话,在锤子眼里,什么都是钉子
指针变量眼里,你放在里面的都是地址,它只能用来存放地址

既然我们把这个a的地址存在了指针变量p中,那么我们可以通过这个地址来找到它所指向的对象吗
我们用*p;来进行这个过程
这里的*叫解引用操作符,意思是通过指针变量p存放的地址,来找到p指向的对象,即*p就是a

总结一下&*这两个操作符,它们是一一对应的
&是取出a的地址,*是根据地址重新回到a,一来一去的
试一试:

#includeint main(){int a = 10;int* p = &a;*p = 20;//这里的*p其实就相当于a了//打印a的地址和a的值printf("%p\n", p);//打印地址用%pprintf("%d\n", a);return 0;}

运行的结果:
008FFD9C
20

可以看到,最开始赋予a的值是10,但是把20赋予*p后,打印的a的值是20,所以就能看出来*p其实就是变量a

指针变量的大小

之前我们用sizeof计算了char,short,int,long,float,double的大小,分别是1,2,4,4-8,4,8
那么我们来计算一下指针变量的大小

int main(){printf("%zu\n", sizeof(char*));printf("%zu\n", sizeof(short*));printf("%zu\n", sizeof(int*));printf("%zu\n", sizeof(long*));printf("%zu\n", sizeof(float*));printf("%zu\n", sizeof(double*));return 0;}

运行的结果:
4
4
4
4
4
4

为什么会是这样,它们指向的类型不是不一样吗?
不管创建什么类型的指针,都是在创建指针变量,指针变量是用来存放地址的
而指针变量的大小取决于一个地址存放的时候需要多大空间
32位的机器上的地址有32bit位,也就是4byte
64位的机器上的地址有64bit位,也就是8byte

我们刚才是在32位平台上运行的,所以大小是4个字节

我们改一下,改成x64,也就是64位的平台

再运行一下:
8
8
8
8
8
8

看到没有,指针变量的大小只跟在哪个平台上有关,在32位平台就是4个字节,在64位平台上就是8个字节

写指针变量有两种形式

int a = 10;int* p = &a;int *p = &a;

你可以把*向左贴,也可以向右贴,这都是可以的,这个是写代码的习惯,各有优点。
比如,你看看这行代码

int* p1, p2, p3;

你认为p1,p2,p3都是指针变量吗?
不,当然不是,这个*其实只给了p1,只有p1是指针变量,而p2,p3都只是跟着int,没有分配*,所以它俩都是整型
我们这样写

int *p1, p2, p3;

是不是能很好的理解了,*只贴向p1,所以只有p1是指针变量
我们要把它们全部变成指针变量,就这样做

int *p1, *p2, *p3;

所以它们各有优点,看个人习惯

指针就学到这里吧,简单了解一下就行了