【C语言】带你完全理解指针(五)练习

复习一下对数组名的理解

数组名的理解
数组名是数组首元素的地址
但是有2个例外:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址

一维数组

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));

在32位下的结果是4 4 4/8 

  讲解:

printf("%d\n", sizeof(a));

sizeof(数组名),数组名单独放在sizeof中,所以计算的是整个数组的大小,4*4=16。

printf("%d\n", sizeof(a + 0));

 a是数组名是首元素地址,a+0(不是单独放在sizeof中)还是首元素地址,地址的大小是4/8。

printf("%d\n", sizeof(*a));

 数组名a是数组首元素的地址,*a就是首元素,大小就是4个字节

printf("%d\n",sizeof(a + 1));

数组名a是数组首元素的地址,a+1是第二个元素的地址,地址的大小4/8

printf("%d\n".sizeof(a[1]));

第二个元素的大小就是4个字节(int类型大小)

printf("%d\n", sizeof(&a));

 &a是数组的地址,数组的地址也是地址,是地址4/8个字节

printf("%d\n", sizeof(*&a));

计算整个数组的大小所以是16个字节。

sizeof(*&a)-->sizeof(a)两者等价

printf("%d\n", sizeof(&a + 1));

&a+1相当于&a是跳过整个数组,但是即使是跳过整个数组,&a+1依然是地址,是地址就是4/8个字节

printf("%d\n",sizeof(&a[0]));

在C语言中[](数组下标运算符)的优先级高于&(取地址运算符)。所以是先a[0]就是第一个元素,之后&,得到第一个元素的地址就是4/8.也就是第一个元素的地址。

printf("%d\n", sizeof(&a[0] + 1));

&a[0]是首元素的地址,&a[0]+1就是第二个元素的地址,大小4。

 字符数组

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));

 (32位下)【答案】:6 4 1 1 4 4 4

【解析】

printf("%d\n", sizeof(arr));

  数组名arr单独放在sizeof内部,计算的是整个数组的大小6。

printf("%d\n", sizeof(arr + 0));

 arr表示数组首元素的地址,arr+0还是数组首元素的地址,是地址就是4/8个字节

printf("%d\n", sizeof(*arr));

arr表示数组首元素的地址,*arr就是首元素,大小1个字节

  

printf("%d\n", sizeof(arr[1]));

arr[1]就是第二个元素,大小是1个字节

printf("%d\n", sizeof(&arr));

&arr是数组的地址,但是数组的地址也是地址,是地址就是4/8

printf("%d\n", sizeof(&arr + 1));

 &arr+1 是跳过数组后的地址, 是地址就是4。

printf("%d\n", sizeof(&arr[0] + 1));

  第二个元素的地址,是地址就是4。

看看strlen的结果,注意strlen统计的是\0之前的字符个数,现在这个数组中是没有\0的

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));

 【答案】32位环境下运行的结果

1、随机值

2、随机值

3、err

4、err

5、随机值

6、随机值-6

7、随机值-1

 【解析】

printf("%d\n", strlen(arr));

 因为字符数组arr中没有\0,所以在求字符串长度的时候,会一直往后找,产生的结构就是随机值

printf("%d\n", strlen(arr + 0));

arr + 0是首元素的地址,和第一个一样,也是随机值。strlen函数是接收一个地址然后往后面找\0。也是随机值

printf("%d\n", strlen(*arr));

 arr是数组首元素的地址,*arr就是数组首元素,就是'a'-97

strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,'a'的ASCII码值是97,那就是将97作为地址传参

strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了

printf("%d\n", strlen(arr[1]));

 同上

printf("%d\n", strlen(&arr + 1));

 &arr表示整个数组的地址,&arr + 1表示跳过整个数组(6个字节)向后查找\0,因此是随机值

printf("%d\n", strlen(&arr[0] + 1));

 第二个函数的地址。也是随机值。 &arr[0]表示首元素地址,&arr[0] + 1跳过一个元素,向后查找\0,因此是随机值

下面换成char arr[] = "abcdef";再来看看也就是末尾有\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", 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));


 

 【答案】32位环境下运行的结果

7

4

1

1

4

4

4



1、6

2、6

3、err

4、err

5、6

6、随机值

7、5

 【解析】

printf("%d\n", sizeof(arr));

 sizeof(数组名)表示整个数组,sizeof是会把\0也计入在内的,因此是7。 


printf("%d\n", sizeof(arr + 0));

 arr+0表示首元素地址,是地址就是4/8


printf("%d\n", sizeof(*arr));

 *arr表示首元素,首元素是char类型,所以就是1。 


printf("%d\n", sizeof(arr[1]));

 第二个元素,所以就是1。


printf("%d\n", sizeof(&arr));

&arr表示整个数组的地址, 是地址就是4/8 


printf("%d\n", sizeof(&arr + 1));

 &arr表示整个数组的地址, &arr + 1表示跳过整个数组,是地址就是4。


printf("%d\n", strlen(arr));

 统计\0前有多少个元素,就是6。


printf("%d\n", strlen(arr + 0));

 arr+0等于首元素地址,统计\0前有多少个元素,就是6。


printf("%d\n", strlen(*arr));

 *arr表示首元素,把元素作为地址直接进行访问,就是非法访问,因此程序会报错。 


printf("%d\n", strlen(arr[1]));

同上


printf("%d\n", strlen(&arr));

&arr是数组的地址这里其实数值和首元素地址一样,所以是6


printf("%d\n", strlen(&arr + 1));

跳过这个数组向后找|0,随机值。


printf("%d\n", strlen(&arr[0] + 1));

 &arr[0] + 1 表示第二个元素的地址,向后找\0等于5。



char* p = "abcdef";
//         012345printf("%d\n", strlen(p));printf("%d\n", strlen(p + 1));printf("%d\n", strlen(*p));printf("%d\n", strlen(p[0]));printf("%d\n", strlen(&p));printf("%d\n", strlen(&p + 1));printf("%d\n", strlen(&p[0] + 1));

【答案】

 6

5

err

err

随机值

随机值

5

 【解析】

printf("%d\n", strlen(p));//6

前面说了strlen接收的是指针,p就是这个字符串的指针也就是首元素的地址。所以是6

printf("%d\n", strlen(p + 1));

p+1是第二个元素的地址,向后找\0所以是5

printf("%d\n", strlen(*p))

 *p是这个字符串,非法访问。

printf("%d\n", strlen(p[0]))

 同理,这也是非法访问,p[0]是第一个元素。strlen要的是一个指针(地址)

printf("%d\n", strlen(&p));//随机值

这是这个指针的地址。

printf("%d\n", strlen(&p + 1));//随机值

printf("%d\n", strlen(&p[0] + 1));//5

 第二个元素开始向后找\0所以是5

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));//&p -- char**printf("%d\n", sizeof(&p + 1));printf("%d\n", sizeof(&p[0] + 1));

【答案】 

4

4

1

1

4

4

4

 解析

printf("%d\n", sizeof(p));

p是一个指针变量大小就是4/8


printf("%d\n", sizeof(p + 1));

p+1是'b'的地址,是地址大小就是4/8个字节


printf("%d\n", sizeof(*p));

*p 就是'a',就是1个字节


printf("%d\n", sizeof(p[0]));

p[0]--> *(p+0) --> *p 1个字节


printf("%d\n", sizeof(&p));//4/8

&p 的类型是 char**是二级指针,是指针就是4/8


printf("%d\n", sizeof(&p + 1));

&p + 1表示指向&p之后位置的指针。如果指针p在内存中占用4个字节,那么&p + 1将指向p之后的4个字节。

是地址就是4/8


printf("%d\n", sizeof(&p[0] + 1));//4/8 

&p[0] + 1得到是'b'的地址.是地址就是4/8

二维数组

int a[3][4] = {0};printf("%d\n",sizeof(a));printf("%d\n",sizeof(a[0][0]));printf("%d\n",sizeof(a[0]));printf("%d\n",sizeof(a[0]+1));printf("%d\n",sizeof(*(a[0]+1)));printf("%d\n",sizeof(a+1));printf("%d\n",sizeof(*(a+1)));printf("%d\n",sizeof(&a[0]+1));printf("%d\n",sizeof(*(&a[0]+1)));printf("%d\n",sizeof(*a));printf("%d\n",sizeof(a[3]));

【答案】 

48

4

16

4

4

4

16

4

16

16

16

【解析】

printf("%d\n", sizeof(a));//3*4*4 = 48

计算整个数组的大小是3*4个元素,每个元素是4字节所以是48字节


printf("%d\n", sizeof(a[0][0]));//4

第一个元素


printf("%d\n", sizeof(a[0]));//a[0]是第一行这个一维数组的数组名

a[0]是第一行这个一位数组的数组名。数组名算是单独放在sizeof内部了,计算的是整个数组的大小,大小是16个字节


printf("%d\n", sizeof(a[0] + 1));

a[0]作为第一行的数组名,没有单独放在sizeo内部,没有&

a[0]表示数组首元素的地址,也就是a[0][0]的地址

所以a[0]+1是第一行第二个元素的地址,是地址就是4/8个字节


printf("%d\n", sizeof(*(a[0] + 1)));//4

计算的是就是第一行第2个元素的大小。


注意这个
printf("%d\n", sizeof(a + 1));//4 / 8

a是数组首元素的地址,是第一行的地址 类型就是int(*)[4]。a+1 就是第二行的地址

加减整数的操作移动多少是看自己的类型的,第一行的地址的类型是int(*)[4]是数组指针


printf("%d\n", sizeof(*(a + 1)));//16

a+1就是第二行的地址,*(a+1) --> a[1] -> sizeof(*(a+1))->sizeof(a[1]) 计算的是第二行的大小

a+1 --> 是第二行的地址,int(*)[4]

*(a+1) 访问的第二行的数组


printf("%d\n", sizeof(&a[0] + 1));//4/8

&a[0]是第一行的地址,加一之后就是第二行的地址

&a[0]是第一行的地址 int(*)[4]

&a[0]+1 是第二行的地址 int(*)[4]


printf("%d\n", sizeof(*(&a[0] + 1)));//16 计算的是第二行的大小

看了上一个就知道这里相当数是把第二行的数组名直接放在sizeof

里面所以是第二行的大小16


printf("%d\n", sizeof(*a));//计算的是第一行的大小-16

a,int[*][4],解引用之后就是第一行这个一维数组

a是数组首元素的地址,就是第一行的地址

*a 就是第一行

*a --> *(a+0) --> a[0]


printf("%d\n", sizeof(a[3]));//16

a[3]--> int [4]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/623998.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【应用】SpringBoot-自动配置原理

前言 本文简要介绍SpringBoot的自动配置原理。 本文讲述的SpringBoot版本为:3.1.2。 前置知识 在看原理介绍之前,需要知道Import注解的作用: 可以导入Configuration注解的配置类、声明Bean注解的bean方法;可以导入ImportSele…

艾体宝方案 | ITT-Profitap IOTA——铁路运输的远程网络捕获和故障排除方案

在移动互联时代,铁路运输的数字化转型已成不可逆转的趋势。然而,随之而来的是对网络连接质量和故障排查的更高要求。本文将探讨如何利用艾体宝Profitap IOTA技术,在火车上实现远程网络捕获和故障排查,助力铁路运输行业迈向智能化未…

GPS定位原理及应用分析

一.定位原理 1.卫星定位(GPS,北斗导航) ①.硬件构成(24颗卫星,可构建一套导航系统) 为何是24颗卫星? 可以做到全球覆盖,同一地点地球上空可观测到4颗卫星。 …

数据分析(2)

数据分析(2) 本文介绍pandas的另一种数据类型DataFrame,中文叫数据框 DataFrame 定义: DataFrame是一个二维的矩阵数据表,通过行和列,可以定位一个值。 在某种程度上,可以认为DataFrame是“具有相同ind…

基于python的二手房数据分析建模及可视化研究,爬取链家二手房数据,可视化分析,房价预测模型

介绍 主要涉及通过爬取济南市链家二手房数据,然后对数据进行处理,包括缺省值处理,高德地图获取二手房地址所属市区,经纬度等数据处理。然后通过python的flask框架编写后端接口,把数据响应给前端。然后前端通过AJAX请求…

Xshell无法输入命令输入命令卡顿

Xshell是一款功能强大的终端模拟软件,可以让用户通过SSH、Telnet、Rlogin、SFTP等协议远程连接到Linux、Unix、Windows等服务器。然而,在使用Xshell的过程中,我们可能会遇到一些问题。比如输入不了命令,或者输入命令很卡。这些问题…

【安全】查杀linux挖矿病毒 kswapd0

中毒现象 高cpu占用,使用top命令查看cpu使用率长时间50%以上,cpu占用异常的进程八成就是挖矿病毒进程 此病毒隐藏了自己,top命令无法查看到挖矿病毒进程,可通过sysdig命令找到隐藏进程 安装sysdig curl -s https://s3.amazonaw…

元类的执行

class MetaB(type):def __new__(cls, name, bases, attrs):print(f"使用元类 {cls.__name__} 创建{name}类 ")return super().__new__(cls, name, bases, attrs)class A(metaclassMetaB):passclass C(A):pass元类MetaB的__new__方法应该只会在创建类A时被调用一次, 因…

全球最新国内外18个热门风景视频素材网站推荐

寻找最新的高清风景视频素材?这里有国内外共18个热门网站,精心整理供您选择。 国内资源: 蛙学网:免费提供多种无版权视频素材,资源丰富。新GG网:需QQ登录,提供丰富的视频模板,通过…

IIC和OLED再认识

IIC介绍 51是由于芯片功能不齐全,以至于需要软件编写IIC 而STM32芯片足够将IIC配置在硬件当中以至于直接读写即可 忘记了可回顾51的16.IIC 协议 和 OLED_oled,iic通信波特率-CSDN博客 在STM32中使用IIC可以直接调用HAL库的库函数: HAL_StatusTypeDe…

2024.4.16

三个按键的中断 do_irq.c #include "mykey.h" extern void printf(const char *fmt, ...); unsigned int i 0; void do_irq(void) {//获取中断号unsigned int irqno (GICC->IAR&0x3ff);switch (irqno){case 99://中断处理逻辑printf("KEY1_INTC\n&q…

java绘图在ubuntu报错

把JRT网站部署到ubuntu桌面系统上,开始没测试绘图部分功能,只试了连PostGreSql部分正常。后面试了生成位图部分发现报错。 报下面错误: (ColorModel.java:220)\n\tat java.desktop/java.awt.image.BufferedImage.(BufferedImage.java:286)\n…