摘要:万字详解与的用法数组名的意义一维数组用法字符数组用法的用法字符串数组用法的用法指针与字符串用法用法二维数组数组名的意义在讲所有东西之前,需要先明确一个关键问题数组名,这里的数组名表示整个数组,计算的是整个数组的大小,单
在讲所有东西之前,需要先明确一个关键问题:
//一维数组 int a[] = { 1,2,3,4 }; printf("%d/n", sizeof(a)); printf("%d/n", sizeof(a + 0)); printf("%d/n", sizeof(*a)); printf("%d/n", sizeof(a + 1)); printf("%d/n", sizeof(a[1])); printf("%d/n", sizeof(&a)); printf("%d/n", sizeof(*&a)); printf("%d/n", sizeof(&a + 1)); printf("%d/n", sizeof(&a[0])); printf("%d/n", sizeof(&a[0] + 1));
运行结果:
解:
printf("%d/n", sizeof(a)); 16字节
因为int a[ ]里有4个元素,每个元素是int类型,占四个字节,所以整个数组大小为16字节
printf("%d/n", sizeof(a + 0)); 4/8字节在32/64位平台下
此时此刻的数组名a表示的是首元素地址,首元素地址+0,还是首元素地址,地址的大小为 4/8在32/64位平台下
printf("%d/n", sizeof(*a)); 4字节
a是数组名,表示首元素地址,然后对首元素地址解引用,所以*a就是首元素,首元素是个int型,大小为4字节
printf("%d/n", sizeof(a + 1)); 4/8字节在32/64位平台下
a是数组名,表示首元素地址,a+1是第二个元素的地址,所以大小为4/8字节在32/64位平台下
printf("%d/n", sizeof(a[1])); 4字节
a[1]就是第二个元素,大小为4字节
printf("%d/n", sizeof(&a)); 大小为4/8字节在32/64位平台下
&a取出的是整个数组的地址(从数值的角度看等于首元素地址),只要是地址,大小就为4/8字节在32/64位平台下
printf("%d/n", sizeof(*&a)); 16字节
&a取出的是整个数组的地址,* &a是对整个数组的地址解引用,拿到的是整个数组,所以大小为16字节
printf("%d/n", sizeof(&a + 1)); 4/8字节在32/64位平台下
&a是数组的地址,&a+1是数组的地址+1,虽然相当于跳过了整个数组,但还是一个地址,所以大小还是4/8
printf("%d/n", sizeof(&a[0])); 4/8字节在32/64位平台下
第1个元素地址,地址大小为4/8字节在32/64位平台下
printf("%d/n", sizeof(&a[0] + 1)); 4/8字节在32/64位平台下
第一个元素地址+1,就是第二个元素地址,地址大小为4/8字节在32/64位平台下
char arr[] = {"a","b","c","d","e","f"}; printf("%d/n", sizeof(arr)); printf("%d/n", sizeof(arr+0)); printf("%d/n", sizeof(*arr)); printf("%d/n", sizeof(arr[1])); printf("%d/n", sizeof(&arr)); printf("%d/n", sizeof(&arr+1)); printf("%d/n", sizeof(&arr[0]+1));
运行结果:
解:
printf("%d/n", sizeof(arr)); 6
此时此刻,sizeof(数组名) 计算的是整个数组的大小,这个数组有6个char类型元素,所以大小为6字节
printf("%d/n", sizeof(arr+0)); 4/8
这里的arr表示首元素地址,+0之后还是首元素a的地址,只要是地址,所以大小为4/8字节
printf("%d/n", sizeof(*arr)); 1
arr是首元素地址,对首元素地址解引用,即得到首元素 a ,a是char类型,所以大小为1
printf("%d/n", sizeof(arr[1])); 1
arr[1]表示的就是第二个元素b,大小为1
printf("%d/n", sizeof(&arr)); 4/8
这里&arr取的是整个数组的地址,是地址,所以大小为4/8字节
printf("%d/n", sizeof(&arr+1)); 4/8
&arr是数组的地址,&arr+1是数组的地址+1,虽然相当于跳过了整个数组,但还是一个地址,所以大小还是4/8字节
printf("%d/n", sizeof(&arr[0]+1)); 4/8
&arr[0]是首元素地址,+1后取到的是第二位元素的地址,也就是 b 的地址,大小为4/8字节;
strlen库函数是什么?请看下图
请看题:
char arr[] = {"a","b","c","d","e","f"}; printf("%d/n", strlen(arr)); printf("%d/n", strlen(arr+0)); printf("%d/n", strlen(*arr)); printf("%d/n", strlen(arr[1])); printf("%d/n", strlen(&arr)); printf("%d/n", strlen(&arr+1)); printf("%d/n", strlen(&arr[0]+1));
解:
printf("%d/n", strlen(arr)); 结果是未知数即随机值
因为arr是首元素地址,strlen函数拿到一个地址,从这个地址一路往后读取计数,直到读到 /0 为止,然鹅在arr这个字符数组里,没有 /0 让其读取,所以它会顺着内存地址一直往后,具体哪个内存单元里存有 /0 是未知的,所以长度结果就是个随机未知数
printf("%d/n", strlen(arr+0)); 结果是随机值
arr是首元素地址,+0后还是首元素地址,情况与上一题同理,结果是随机数
printf("%d/n", strlen(*arr)); 系统报错
*arr是对首元素地址解引用,得到的就是 字符a ,strlen接收到的其实是字符a的ASCII码值97 ,这个97不是一个合法地址,是个野指针,所以这行代码会报错
printf("%d/n", strlen(arr[1])); 系统报错
arr[1]是第二位元素,就是字符 b ,strlen接收到的是字符 b 的ASCII码值98,与上同理,会报错
printf("%d/n", strlen(&arr)); 随机值
&arr取到的是整个数组的地址,它的值实际上等于首元素地址,由于strlen函数的类型是char* ,传过来之后会进行一个类型的隐式转换,地址类型可能会不一样,但是strlen能接收这个地址,即接收到首元素地址并由此往后计数,所以结果也是一个随机值
printf("%d/n", strlen(&arr+1));结果是一个随机值,与strlen(&arr)得到的随机值相差6
&arr是取整个数组的地址,+1是跳过整个数组,拿到的是整个数组之后的地址,所以同理,结果也是一个随机值,只不过这个随机值与strlen(arr)得到的随机值相差6,如图:
printf("%d/n", strlen(&arr[0]+1)); 随机值
&arr[0]是取第一个元素地址,+1是取到第二个元素地址,即从 字符b 开始向后计数,但是不知道 /0 会出现在后边内存的哪个位置,所以结果也是随机数
char arr[] = "abcdef"; printf("%d/n", sizeof(arr)); printf("%d/n", sizeof(arr+0)); printf("%d/n", sizeof(*arr)); printf("%d/n", sizeof(arr[1])); printf("%d/n", sizeof(&arr)); printf("%d/n", sizeof(&arr+1)); printf("%d/n", sizeof(&arr[0]+1));
解:
printf("%d/n", sizeof(arr)); 7字节
abcdef/0 一共7个字节
printf("%d/n", sizeof(arr+0)); 4/8
arr表示首元素字符地址,+0之后还是首元素字符 a 的地址,大小为4/8字节
printf("%d/n", sizeof(*arr)); 1字节
arr是首元素地址,解引用*arr后就是首元素 字符a,大小为1字节
printf("%d/n", sizeof(arr[1])); 1字节
arr[1] 表示第二个元素,也就是字符 b ,大小为1字节
printf("%d/n", sizeof(&arr)); 4/8字节
&arr 是整个数组的地址,数组的地址也是地址,大小为4/8字节
printf("%d/n", sizeof(&arr+1)); 4/8字节
&arr 是数组的地址,&arr+1是跳过整个数组,得到数组后一位的地址,4//8字节
printf("%d/n", sizeof(&arr[0]+1)); 4//8字节
&arr[0]是第一个元素地址,&arr[0]+1 是第二个元素地址,大小为4/8字节
char arr[] = "abcdef"; printf("%d/n", strlen(arr)); printf("%d/n", strlen(arr+0)); printf("%d/n", strlen(*arr)); printf("%d/n", strlen(arr[1])); printf("%d/n", strlen(&arr)); printf("%d/n", strlen(&arr+1)); printf("%d/n", strlen(&arr[0]+1));
解:
printf("%d/n", strlen(arr)); 6
strlen只对abcdef计数, 不算/0一共6个字符,也就是6字节
printf("%d/n", strlen(arr+0)); 6
arr是首元素地址,+0后还是首元素的地址,从首地址开始计数,仍然为6字节
printf("%d/n", strlen(*arr)); 系统报错 printf("%d/n", strlen(arr[1])); 系统报错
*arr传入的是数组首元素,就是字符a,strlen接收到的其实是字符a的ASCII码值97,97不是合法地址,相当于野指针,所以会报错
arr[1]同理,传入的是第二个元素字符 b ,strlen接收到的是字符b 的ASCII码值98,是非法地址,所以也会报错
printf("%d/n", strlen(&arr)); 6
&arr是取得整个数组的地址,数值上等于首元素地址,strlen接收到的就是首元素地址,于是从首元素开始计数,结果为6字节
printf("%d/n", strlen(&arr+1)); 随机值
&arr+1得到的地址如上图所示,一直向后读取,不知道什么时候才能读取到/0,所以strlen得到的结果为随机值
printf("%d/n", strlen(&arr[0]+1));5字节
&arr[0]是第一个元素地址,+1之后得到第二个元素地址,从第二个元素地址开始读取,读到/0前,一共5个字节
const char *p = "abcdef"; printf("%d/n", sizeof(p)); printf("%d/n", sizeof(p+1)); printf("%d/n", sizeof(*p)); printf("%d/n", sizeof(p[0])); printf("%d/n", sizeof(&p)); printf("%d/n", sizeof(&p+1)); printf("%d/n", sizeof(&p[0]+1));
解:
printf("%d/n", sizeof(p)); 4/8字节
p是一个指针变量,存的是字符串首元素地址,所以是4/8字节
printf("%d/n", sizeof(p+1)); 4/8字节
p是一个指针变量,存的是字符串首元素址,+1之后就是字符串第二个元素的地址,也就是 b 的地址,是4/8个字节
printf("%d/n", sizeof(*p)); 1字节
p是一个指针变量,存的是字符串首元素地址,对其解引用,*p得到的是字符 a ,类型为char,大小为1个字节
printf("%d/n", sizeof(p[0])); 1字节
p[0] = *(p+0) = *p,这三种写法表示的都是首元素字符 a ,大小为1个字节
printf("%d/n", sizeof(&p)); 4/8字节
p是一个指针变量,是一个地址,对指针变量取地址,得到的是一个地址的地址,还是一个地址,所以大小还是4/8字节
printf("%d/n", sizeof(&p+1)); 4/8字节
p是个指针变量,字符串通过指针存到内存中,其实也可以理解成这是内存中一块连续的储存空间,就像数组一样,这里的 &p+1 ,p是一个指向字符串首元素的一级指针,&p是指针变量p的地址,是一个二级指针,+1之后,相当于二级指针+1,指向的是一块我们不知道的未知空间,但说到底还是一个地址,大小仍是4/8字节,如图所示:
printf("%d/n", sizeof(&p[0]+1)); 4/8字节
字符串也是一块连续空间,可以像数组一样通过 [ ] 访问,p[0] = *(p+0) = *p这三种表示方法都可以表示字符串元素,这里&p[0]表示首元素地址,+1就是第二个元素字符b的地址,是地址,大小为4/8字节
const char *p = "abcdef"; printf("%d/n", strlen(p)); printf("%d/n", strlen(p+1)); printf("%d/n"
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/119669.html
摘要:前言由于写的文章已经是有点多了,为了自己和大家的检索方便,于是我就做了这么一个博客导航。 前言 由于写的文章已经是有点多了,为了自己和大家的检索方便,于是我就做了这么一个博客导航。 由于更新比较频繁,因此隔一段时间才会更新目录导航哦~想要获取最新原创的技术文章欢迎关注我的公众号:Java3y Java3y文章目录导航 Java基础 泛型就这么简单 注解就这么简单 Druid数据库连接池...
摘要:目录前言架构安装第一个爬虫爬取有道翻译创建项目创建创建解析运行爬虫爬取单词释义下载单词语音文件前言学习有一段时间了,当时想要获取一下百度汉字的解析,又不想一个个汉字去搜,复制粘贴太费劲,考虑到爬虫的便利性,这篇文章是介绍一个爬虫框架, 目录 前言 架构 安装 第一个爬虫:爬取有道翻译 创建项目 创建Item 创建Spider 解析 运行爬虫-爬取单词释义 下载单词语音文件 ...
摘要:在项目中,为满足以上要求,我们将大量的参数配置在或文件中,通过注解,我们可以方便的获取这些参数值使用配置模块假设我们正在搭建一个发送邮件的模块。这使得在不影响其他模块的情况下重构一个模块中的属性变得容易。 在编写项目代码时,我们要求更灵活的配置,更好的模块化整合。在 Spring Boot 项目中,为满足以上要求,我们将大量的参数配置在 application.properties 或...
摘要:在项目中,为满足以上要求,我们将大量的参数配置在或文件中,通过注解,我们可以方便的获取这些参数值使用配置模块假设我们正在搭建一个发送邮件的模块。这使得在不影响其他模块的情况下重构一个模块中的属性变得容易。 在编写项目代码时,我们要求更灵活的配置,更好的模块化整合。在 Spring Boot 项目中,为满足以上要求,我们将大量的参数配置在 application.properties 或...
阅读 3894·2021-09-09 09:33
阅读 1733·2021-09-06 15:14
阅读 1895·2019-08-30 15:44
阅读 3043·2019-08-29 18:36
阅读 3731·2019-08-29 16:22
阅读 2072·2019-08-29 16:21
阅读 2492·2019-08-29 15:42
阅读 1628·2019-08-29 11:00