指针,数组 易混题解析(一)

server/2025/3/28 4:03:57/

目录

一.相关知识点

1.数组名是什么?

两个例外:

2.strlen

3.sizeof

4. * (  ) 与 [  ]  的互换

二.一维数组

三.字符数组

1. 字符

(1)sizeof

(2)strlen

2.字符串

(1)sizeof

(2)strlen

3.字符指针

(1)sizeof

(2)strlen

四.二维数组


一.相关知识点

1.数组名是什么?

一维数组数组名是首元素的地址。

二维数组数组名是首元素地址,是第一行的地址(一维数组的地址)。

        

两个例外:

1. sizeof(数组名),这里的数组名是表示整个数组,计算的是整个数组的大小,单位是字节

2. &数组名,这里的数组名是表示整个数组,& 数组名取出的是数组的地址

2.strlen

库函数,用来求字符串长度,统计的是\0之前出现的字符个数,一定要找到 ' \0 ' 才算结束,所以可能存在越界访问的。

头文件:#include <stdio.h>

注意:strlen 的函数参数是字符指针类型,我们要传给它开始统计字符长度位置的地址

3.sizeof

操作符,只关注变量占用内存空间的大小,单位是字节,不关心内存中存放的是什么

注意:1.sizeof 内部的表达式不计算

int main()
{int a = 0;short s = 5;printf("%d\n", sizeof(s = a + 3));//2printf("%d\n", s);//5return 0;
}

原因:

2.sizeof 根据类型判断大小,不会访问对应空间(不存在越界访问数组的情况)

变量是有类型的,数组也是有类型的。去掉名字就是类型

int main()
{int a = 0;int arr[10];printf("%d\n", sizeof(a));printf("%d\n", sizeof(int));printf("%d\n", sizeof(arr));printf("%d\n", sizeof(int [10])); //数组 arr 的类型:int [10]return 0;
}

4. * (  ) 与 [  ]  的互换

二.一维数组

int main()
{int a[] = { 1,2,3,4 };return 0;
}

易混例题: 

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

1. 这里是数组名的两个例外情况之一,计算的是整个数组的大小。答案:4 * 4 = 16

2.3. 注意:这里sizeof( ) 里面不止有数组名,不是两个例外情况之一。

a 是数组首元素的地址,a + 0 也是数组第一个元素的地址,a + 1是第二个元素的地址。是地址就是4/8字节。答案:4/8

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

不是两个例外,a 是数组首元素地址。

*a是数组首元素,a[1] 是第二个元素。计算的是数组首,第二个元素的大小,单位字节。答案:4

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

1. &a是整个数组的地址,整个数组的地址也是地址,地址的大小就是4/8字节

&a 的类型:int (*)[4] 数组指针 

2. &a是数组的地址,*&a就是拿到了数组。*&a --> a,a就是数组名,sizeof(*&a)-->sizeof(a)。计算的是整个数组的大小,单位是字节-16。

3. &a是整个数组的地址。&a+1,跳过整个数组,指向数组后边的空间,是一个地址,大小是4/8字节。

&a+1 的类型还是 int (*)[4] 数组指针

是否会越界访问?

不会。&a 与 &a+1 类型相同。sizeof 根据类型判断大小,不会访问对应空间。所以大小也相同。

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

&a[0]是首元素的地址,&a[0] + 1是第二个元素的地址,计算的是首元素地址的大小,地址的大小就是4/8字节

三.字符数组

1. 字符

int main()
{char arr[] = { 'a','b','c','d','e','f' };return 0;
}

(1)sizeof

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

1. arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节,6

2. arr 是首元素的地址,arr + 0 还是数组首元素的地址,4/8

3. arr 是首元素的地址,*arr是数组的首元素,计算的是首元素的大小:1字节

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

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

1. 取出的数组的地址,数组的地址也是地址,是地址大小就是4/8

2. &arr+1是跳过整个,指向数组后边空间的地址,4/8

3. &arr[0] + 1是数组第二个元素的地址,是地址4/8字节

(2)strlen

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[0] + 1));

1.2. 两个传的都是首元素地址,让 strlen 从首元素位置开始统计。但没有 ' \0 '  不止何时停止,随机值。

3. &arr虽然是数组的地址,但是也是从数组起始位置开始的,计算的还是随机值

&arr 的类型:char (*)[6] 数组指针

4. &arr是数组的地址,&arr+1是跳过整个数组的地址,求字符串长度也是随机值

5. &arr[0] + 1是第二个元素的地址,是'b'的地址,求字符串长度也是随机值

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

*arr 和 arr[1] 分别是数组第一元素 'a'  ASCII码值是97;第二元素 'b'  ASCII码值是98

strlen('a')    等价于   strlen(97)。直接让 strlen 从内存编号97的地址开始统计。非法访问,这样写是错的!

97作为地址访问内存,抱歉,97这个地址不能直接访问。只有把这片空间分配给你,你才有权限访问它。

2.字符串

int main()
{char arr[] = "abcdef"; // 数组是7个元素// [ a b c d e f \0 ]return 0;
}

(1)sizeof

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

1. 数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节:7

2. arr+0是首元素的地址,大小是4/8

3. *arr是数组首元素,大小是1字节

4. arr[1]是数组的第二个元素,大小是1字节

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

1. &arr是数组的地址,数组的地址也是地址,是4/8字节

2. &arr + 1是跳过整个数组的地址,是4/8字节

3. &arr[0] + 1是第二个元素的地址,是4/8字节

(2)strlen

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[0] + 1));

1. arr是数组首元素的地址,strlen从首元素的地址开始统计\0之前出现的字符个数,是6

2. arr + 0是数组首元素的地址,同第一个,结果是6

3. &arr虽然是数组的地址,但是也是从数组起始位置开始的,直至 \0 。 6

4. &arr + 1是跳过数组后的地址,统计字符串的长度是随机值

5. &arr[0]+1是b的地址,从第二个字符往后统计字符串的长度,大小是5

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

非法访问

3.字符指针

int main()
{const char* p = "abcdef";return 0;
}

错:把字符串 abcdef 放到指针 p 里           对:把首字符的地址放到 p 里

字符串里面的内容,地址是连续的

字符串打印只要告诉我起始位置,就可以打印,直到 \0

(1)sizeof

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

1. p是指针变量,大小就是4/8字节

2. p + 1是b的地址,是地址,就是4/8个字节

3. *p是'a',sizeof(*p)计算的是字符的大小,是1字节

4. p[0] --> *(p+0) --> *p  就同上一个,1字节

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

1. 取出 p 的地址,p 是 char* 类型的指针,&p 取出 char* 的地址,是二级指针 char* *。是指针大小就是4/8

2. &p + 1是跳过p变量后的地址,4/8字节

3. p[0] 就是‘a’ , &p[0]就是a的地址,+1,就是b的地址,是地址就是4/8

    也可以这样理解:

(2)strlen

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

1. p 指向 a 的地址,从 a 开始统计长度。6

2. p+1 指向 b 的地址,从 b 开始统计长度。5

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

*p 和 p[0] 都是 ' a '    非法访问 

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

1. &p拿到的是p这个指针变量的起始地址,从这里开始求字符串长度完全是随机值

2. &p+1是跳过p变量的地址,从这里开始求字符串长度也是随机值

3. &p[0] + 1是b的地址,从b的地址向后数字符串的长度是5

四.二维数组

int main()
{int a[3][4] = { 0 };return 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)));

1. 计算整个数组的大小 3*4 * 4 = 48

2. a[0][0] 的第一行第一个元素。4

3. a[0]是第一行的数组名,数组名单独放在sizeof内部,计算的就是数组(第一行)的大小,16个字节

4. a[0]是第一行的数组名。没有单独放在sizeof内部;没有取地址。表示的就是数组首元素的地址,是a[0][0]的地址。

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

5. *(a[0] + 1)是第一行第2个元素,计算的是元素的大小。4个字节

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

1. a是二维数组的数组名,数组名表示首元素的地址,就是第一行的地址,a+1就是第二行的地址。

   第二行的地址也是地址,是地址就是4/8

a - int (*)[4]    a+1--> int(*)[4]

2. a+1是第二行的地址,*(a+1)表示的就是第二行。16              *(a+1)--a[1]

3. &a[0]是第一行的地址,&a[0]+1是第二行的地址,地址的大小就是4/8

4. *(&a[0] + 1) 是对第二行的地址解引用,得到的就是第二行,计算的就是第二行的大小。16

5. a表示首元素的地址,就是第一行的地址,*a就是第一行,计算的就是第一行的大小。     *a -- *(a+0)--a[0]

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

类型:int [4]    大小:16

如果数组存在第四行,a[3]就是第四行的数组名,数组名单独放在sizeof内部,计算的是第四行的大小


http://www.ppmy.cn/server/178672.html

相关文章

数据可视化(matplotlib)-------辅助图标的设置

目录 一、认识图表常用的辅助元素 坐标轴 二、设置坐标轴的标签、刻度范围和刻度标签 &#xff08;一&#xff09;、设置坐标轴的标签 1、xlabel()------设置x轴标签 2、ylabel()------设置y轴标签 &#xff08;二) 、设置刻度范围和刻度标签 1、xlim()和ylim()函数分别可…

WRF移动嵌套结合伏羲模型与CFD(PALM)高精度多尺度降尺度分析研究

随着大气科学与数值模拟技术的发展&#xff0c;高精度多尺度气象模拟日益成为科研与应用的热点问题。本文将详细介绍如何使用WRF移动嵌套技术结合伏羲&#xff08;Fuxi&#xff09;模型&#xff0c;并通过CFD模型PALM实现精细化降尺度&#xff0c;以满足城市或区域局地精细化气…

【YOLO项目】毕设大作业之车道线检测

LA:162个 Left Arrow 左箭头 SA:1440个 Straight Arrow 直箭头 PC:839个 Pedestrian Crossing 人行横道 DM:1047个 Diamond 菱形 BL:191个 Bus Lane 公交专用道 JB:172个 Junction Box 路口导流区 RA:352个 Right Arrow 右箭头 SLA:241个 Straight-Left Arro…

数据结构——B树、B+树、哈夫曼树

目录 一、B树概念1.B树的构造2 .B树的特点 二、B树概念1.B树构造2.B树的特点 三、B树和B树的区别四、哈夫曼树1.哈夫曼树的基本概念2.哈夫曼树的构建 一、B树概念 B树的出现是为了弥合不同的存储级别之间的访问速度上的巨大差异&#xff0c;实现高效的 I/O。平衡二叉树的查找效…

人工智能(AI)在律师行业的应用挑战和机会

人工智能(AI)在律师行业的应用正在迅速扩展,为法律实践带来了效率提升和新的可能性,但同时也伴随着一些挑战。以下是AI在律师行业的主要应用和面临的挑战: 一、人工智能在律师行业的应用 1. 法律研究与案例分析 应用: AI可以通过自然语言处理(NLP)技术快速分析大量法律…

机器学习周报-文献阅读

文章目录 摘要Abstract 1 文章内容1.1 方法及模型1.1.1 所提方法1.1.2 PID误差校正原理1.1.3 1D-CNN1.1.4 LSTM 1.2 数据集、测试设置、结果和分析1.2.1 实验数据集设置1.2.1.1 混沌时间序列数据集1.2.1.2 实际池塘养殖水质数据集1.2.1.3 数据集设置的意义 1.2.2 模型性能评价指…

【QT】一文学会 QT 多线程(QThread )

一、Qt 多线程概述 在 Qt 中&#xff0c;多线程的处理一般是通过 QThread类 来实现。 QThread 代表一个在应用程序中可以 独立控制 的线程&#xff0c;也可以和进程中的其他线程共享数据QThread 对象管理程序中的一个控制线程。 创建线程的两种方式 ① 使用 QThread 类  Q…

单片机自学总结

自从工作以来&#xff0c;一直努力耕耘单片机&#xff0c;至今&#xff0c;颇有收获。从51单片机&#xff0c;PIC单片机&#xff0c;直到STM32&#xff0c;以及RTOS和Linux&#xff0c;几乎天天在搞:51单片机&#xff0c;STM8S207单片机&#xff0c;PY32F003单片机&#xff0c;…