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

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

◉ 着重强调

  ◆ 1、
  ◆ 2、
  ◆ 3、

  
  
  
  
  
  
  
  

Miscellaneous Symbols


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

  •  前言

  

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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 <stdio.h>
#include <stdlib.h>
#include <string.h>
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

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

  根据上述结果,分析如下:
  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方式显示。

  运行程序验证:

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


  •  Topic 3

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

  回头看上述范式,仅从字面上看,地址和数字,应该是可以任意取值的。
  既然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

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

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


  •  Topic 4

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

  先看(char *)的情况:

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

  程序情况:

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


  再看(float *)的情况:

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

  代码如下:

    ((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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容