C语言小白深入理解指针1---int篇

        无论什么MCU,在程序里设定变量的时候,都会在内存里分配一个或多个内存块存储这个变量。比如一个RAM为1KB的8051 MCU,内部包含1024 BYTE的内存块,这些内存块都有自己的编号,从0x0000开始到0x03FF,当你在KEIL里边定义一个char i=250时,系统便会分配1个内存块给i,同理,当你定义一个int j=0x1234时,系统便会分配2个内存块给j,其中一个内存块存着0x12,另一个内存块存着0x34,但是具体哪个内存块在前,哪个在后呢?这跟硬件架构设计的大小端配置有关,比如STM32单片机采用小端编码方式,0x34的内存块在前,而对于8051单片机采用大端编码方式,0x12的内存块在前。

        这里说的在前是指内存块的编号比较小,在后是指内存块的编号比较大。

        对于8051单片机,0x12占用的内存块编号为0x0010,0x34占用的内存块编号为0x0011:

地址0x000F0x00100x00110x0012
数据       0x120x34

        这里说的编号实际就是内存块对应的地址,1KB内存的地址有1024个,从0x0000开始到0x03FF;

        这里说的地址实际就是指针,指针就是地址,地址就是指针!

        这里使用Code_Blocks工具在PC平台上测试一下int型的数据具体是如何存储的,它的指针到底是多少。

  • 首先定义1个变量fool,再定义2个不同类型的指针指向fool;
    unsigned  int16 fool=0x1234;
    unsigned  int8 *p8=&fool;
    unsigned  int16 *p16=&fool;
  • 先看一下fool的存储地址、p8的值、p16的值是多少:
printf("&fool = 0x%x\r\n",&fool);
printf("p8    = 0x%x\r\n",p8);
printf("p16   = 0x%x\r\n",p16);

运行结果:
&fool = 0x60fee4
p8    = 0x60fee4
p16   = 0x60fee4

结论: 无论什么类型的指针变量,只要指向同一个变量(fool),值都是一样的,也可以说指向的地址都一样。

  • 看下p8,p16各自的地址是多少:
printf("&p8 = 0x%x\r\n",&p8);
printf("&p16 = 0x%x\r\n",&p16);

运行结果:
&p8 = 0x60fee0
&p16 = 0x60fedc

结论: 指针变量自己也是一个变量,也有自己的内存块编号,又称地址或指针,他们自己的指针都是独立的,跟fool没有一毛钱关系。

  • 看下p8,p16各自指向的地址,里面存的是什么:
printf("*p8 = 0x%x\r\n",*p8);
printf("*p16 = 0x%x\r\n",*p16);

运行结果:
*p8 = 0x34
*p16 = 0x1234

结论: p16指向fool,里面存的就是fool定义的值0x1234没啥疑问。但是p8也是指向fool,为什么里面存的只有0x34,另一半0x12去哪了?

标识&p16&p8

&fool

p8

p16

p8+1

&fool+1

p8+2

p16+1

p8+3

地址0x60fedc...0x60fee0...0x60fee40x60fee50x60fee60x60fee7
数据       *&p8=p80x60fee4

*&p16=p16

 0x60fee4

*p8=0x34*(p8+1)=0x12吗?未知        未知
*p16=0x1234未知未知
  • 看下p8+1里面存的是什么:
printf("*(p8+1) = 0x%x\r\n",*(p8+1));

运行结果:
*(p8+1) = 0x12

结论: p8+1地址里面存的还真是0x12。所以现在有结论了,对与int型变量fool,存在2个内存块里,低字节0x34存在小地址里,高字节0x12存在大地址里,这与前文提到的8051单片机相反,属于小端存储方式!

  • 关于指针的其他用法:
printf("&fool+1 = 0x%x\r\n",&fool+1);
printf("p8+1 = 0x%x\r\n",p8+1);
printf("p16+1 = 0x%x\r\n",p16+1);

printf("*p8+1 = 0x%x\r\n",*p8+1);
printf("*p16+1 = 0x%x\r\n",*p16+1);

printf("&*(p8+1) = 0x%x\r\n",&*(p8+1));
printf("uint8(fool) = 0x%x\r\n",(uint8)fool);

运行结果:
&fool+1 = 0x60fee6  //fool是int型变量,地址+1后数字+2
p8+1 = 0x60fee5     //p8时char型变量,地址+1则数字
p16+1 = 0x60fee6    //p16是int型变量,地址+1后数字+2

*p8+1 = 0x35        //*p8表示地址p8指向的变量,即0x34+1
*p16+1 = 0x1235     //*p16表示地址p16指向的变量,即0x1234+1

&*(p8+1) = 0x60fee5 //p8+1表示0x12所在的地址,*指向这个地址存储的变量=0x12,&读出0x12所在的地址, 
                      实际等效为p8+1
(uint8)fool = 0x34  //对fool变量强制转换成char型,只保留低地址1个字节,高地址的没有了

好奇想看一下0x60fee6,0x60fee7里存了啥:

printf("*(p8+2) = 0x%x\r\n",*(p8+2));
printf("*(p8+3) = 0x%x\r\n",*(p8+3));
printf("*(p16+1) = 0x%x\r\n",*(p16+1));

运行结果:
*(p8+2) = 0x40
*(p8+3) = 0x67
*(p16+1) = 0x6740
&p16&p8

&fool

p8

p16

p8+1

&fool+1

p8+2

p16+1

p8+3
地址0x60fedc...0x60fee0...0x60fee40x60fee50x60fee60x60fee7
数据       *&p8=p80x60fee4

*&p16=p16

 0x60fee4

*p8=0x34*(p8+1)=0x12*(p8+2)=0x40*(p8+3)=0x67
*p16=0x1234*(p16+1)=0x6740
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值