基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22

←↑→↓↖↙↗↘↕⏤
unicode=Geometric Shapes
▶ 仅仅个别字不同的时候的对比标识

◉ 着重强调

  ◆ 1、
  ◆ 2、
  ◆ 3、

  
  
  
  
  
  
  
  

Miscellaneous Symbols


Dingbats
✍ 重点记忆,个人总结的点,或者知识。
✎✎

  •  前言

  

基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第1张图片
#include 
#include 
#include 

int main()
{

    int b[3]= {10,11,12};
    int *p=b;

    printf("b[0]=%d\n",b[0]);
    printf("b[1]=%d\n",b[1]);
    printf("b[2]=%d\n",b[2]);

    printf("*(b+0)=%d\n",*(b+0));
    printf("*(b+1)=%d\n",*(b+1));
    printf("*(b+2)=%d\n",*(b+2));

    printf("p[0]=%d\n",p[0]);
    printf("p[1]=%d\n",p[1]);
    printf("p[2]=%d\n",p[2]);

    printf("*(p+0)=%d\n",*(p+0));
    printf("*(p+1)=%d\n",*(p+1));
    printf("*(p+2)=%d\n",*(p+2));
}
b[0]=10
b[1]=11
b[2]=12
*(b+0)=10
*(b+1)=11
*(b+2)=12
p[0]=10
p[1]=11
p[2]=12
*(p+0)=10
*(p+1)=11
*(p+2)=12


  •  Topic 1

  代码如下:

#include 
#include 
#include 
int main()
{
    int b[3]= {10,11,12};
    printf("b[0]=%d\n",b[0]);
    printf("b[1]=%d\n",b[1]);
    printf("b[2]=%d\n",b[2]);

    printf("b+0=%x\n",b+0);
    printf("b+1=%x\n",b+1);
    printf("b+2=%x\n",b+2);
}

  输出结果如下:

b[0]=10
b[1]=11
b[2]=12
b+0=60fef4
b+1=60fef8
b+2=60fefc
基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第2张图片

  根据运行时的内存分布和运行结果的输出,大致可知作示意图如下(因多次调试运行,请忽略地址上的差异):

基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第3张图片

  根据上述结果,分析如下:
  1、数组名b,代表一个内存的地址。
  2、对地址的加n操作,实际上和b这个地址所具有的数据类型有密切的关系。此例中,b指向的是一个int型数组的首地址,而一个int占4Byte,所以b+1等于b的地址0x0060fef4+4=0x0060fef8

  c语言中,指针在概念上等同于内存地址。根据c语言指针的定义和使用方法,*(指针)就等于取该指针指向的内存地址内容。
  但是这里有一个问题,内存地址是一片连续的地址,系统如何知道取多大(几个字节)?是以该地址为起点,还是为终点?
  回想指针的定义。假如类似 定义如:int *p。
  对。系统会以int长度,也就是4个字节,来取内容。由于指针保存的就是一片地址的起始位置,所以,在取内容的时候,也是以该地址为起始地址来取内容。
  执行代码进行验证:

    int b[3]= {10,11,12};
    printf("*(b+0)=%d\n",*(b+0));
    printf("*(b+1)=%d\n",*(b+1));
    printf("*(b+2)=%d\n",*(b+2));
*(b+0)=10
*(b+1)=11
*(b+2)=12


  •  Topic 2

  来看数组元素的引用方式:

    int b[3]= {10,11,12};
    printf("b[0]=%d\n",b[0]);
b[0]=10

  综上表述,b代表一个地址,我们引用数组元素的方式,就是:

  简而言之,就是一个基址+偏移的构成。地址就是基址,数字就是偏移量。地址很容易确定,直接用程序输出都可以看到;偏移的数字也很好理解,0就是不偏移,1就是偏移一个单位,关键在于:这个单位,到底是多长?
  就本例来说,这一块内存地址,是用做int型数组的,默认隐含的单位就是,4Byte。
  现在几个要素都已经明晰,那么利用上述引用的模式,稍作变换:

  用语言表述,就是以(b+1)为基址,偏移0个单位,取4字节,以int方式显示。

基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第4张图片

  运行程序验证:

    printf("(b+1)[0]=%d\n",(b+1)[0]);
(b+1)[0]=11
基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第5张图片
    printf("(b+1)[1]=%d\n",(b+1)[1]);
(b+1)[1]=12
基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第6张图片
    printf("(b+2)[0]=%d\n",(b+2)[0]);
(b+2)[0]=12


  •  Topic 3

基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第7张图片

  思考如何把起始地址更换为红色箭头所示?

  回头看上述范式,仅从字面上看,地址和数字,应该是可以任意取值的。
  既然b是个地址,那么应该可以通过加减进行运算改变。直接操作吗?似乎不可行,比如:

    printf("b+0=%x\n",b+0);
    printf("b+1=%x\n",b+1);
    printf("b+2=%x\n",b+2);

  结果是:

b+0=60fef4
b+1=60fef8
b+2=60fefc

  运算结果表示出,此时的b,表现出了指针的特性,系统把b当做了一个指针。那么如何实现b在数学上的加操作呢?对!强制类型转换!灵(wei)活(xian)的C!

     printf("b address =%x\n",b);
     printf("b address + 1=%x\n",(int)b+1);
b address =60fef4
b address + 1=60fef5

  到此,地址的问题解决了。那么来验证输出一下:

    printf("((int)b+1)[0]=%x\n",((int)b+1)[0]);

  结果报错:

||=== Build: Debug in 1 (compiler: GNU GCC Compiler) ===|
C:\Users\lo\Desktop\1\main.c|37|error: subscripted value is neither array nor pointer nor vector|
||=== Build failed: 1 error(s), 4 warning(s) (0 minute(s), 0 second(s)) ===|

  提示:下标值既不是数组也不是指针也不是向量。

  为什么?考虑一下b的前后“属性”:
  1、一开始,b的表现,体现了指针的属性
  2、为了数学上+1,进行了强制类型转换int
  是不是感觉少了什么?对!恢复b的原有特性。

         (int *)((int)b+1)

    printf("((int *)((int)b+1))[0]=%x\n",((int *)((int)b+1))[0]);
((int *)((int)b+1))[0]=b000000
基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第8张图片

  测试((int *)((int)b+1))[1],继续验证

    printf("((int *)((int)b+1))[0]=%x\n",((int *)((int)b+1))[1]);
((int *)((int)b+1))[1]=c000000
基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第9张图片


  •  Topic 4

  参考上图,注意(int *)的强制类型转换,int不仅决定了取数据的字长(4Byte),也决定了4Byte中的内容,以整数的格式显示出来。
  那么,把int 换成 char(占1Byte)或者float(占4Byte),程序又会如何输出?

  先看(char *)的情况:

  预想的结果,应该是这样的:

基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第10张图片

  程序情况:

    printf("((char *)((int)b+1))[1]=%x\n",((char *)((int)b+1))[3]);
((char *)((int)b+1))[1]=b


  再看(float *)的情况:

  为了有一个正确的显示结果,首先把数组空间自第二个字节起,至第五个字节内容赋值,预期的结果如下:

基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第11张图片

  代码如下:

    ((char *)((int)b+1))[0]=0x60;
    ((char *)((int)b+1))[1]=0x76;
    ((char *)((int)b+1))[2]=0x9f;
    ((char *)((int)b+1))[3]=0x3f;

  因为x86平台使用小端字节序,所以这4个字节按照float数据格式排列起来,应该为:3F9F7660。
  这个值等于十进制小数1.2458。
  具体计算过程可以移步基础C++教学⮱⮱007【10进制小数与2进制小数的转换】2019-12-15

  执行程序验证,注意使用%f格式输出:

    printf("((float *)((int)b+1))[0]=%f\n",((float *)((int)b+1))[0]);
((float *)((int)b+1))[0]=1.245800
基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22_第12张图片

你可能感兴趣的:(基础C++教学⮱⮱008【C中的数组名和指针】2019-12-22)