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

目录

一.相关知识点

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.rhkb.cn/news/38692.html

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

相关文章

ABC392题解

A 算法标签: 模拟 #include <iostream> #include <algorithm> #include <cstring>using namespace std;int main() {ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);int w[3];for (int i 0; i < 3; i) cin >> w[i];sort(w, w 3);if (w[0]…

Quartus + VScode 实现模块化流水灯

文章目录 一、通过VScode编写Verilog代码二、模块化编程三、代码示例 一、通过VScode编写Verilog代码 1、下载Vscode 2、下载相关插件 搜索Verilog就会弹出有如图所示的插件&#xff0c;下载并安装 3、创建Quartus项目 4、创建完成后点击Tools&#xff0c;选择Options 然后在…

简单讲一下控制系统所用的PID公式

2025年3月23日电子电工实验室讲课大纲 哈喽&#xff0c;小伙伴们大家好&#xff0c;今天我们来讲一下PID&#xff01;首先我们的针对的场景是什么——循迹小车&#xff01; 就是我们刚入手STM32时&#xff0c;我们可能会制作一个循迹小车。我们想让那个小车走直线&#xff0c;但…

直观理解ECC椭圆曲线加密算法

数学还是挺有逻辑的&#xff0c;给出计算的操作步骤 就能得出想要结果 背景&#xff1a; ● ECC 是一种极其巧妙的 非对称加密算法 , 其完美利用了 椭圆曲线几何累加 不可逆的性质 ● 拥有 密钥体积小&#xff0c;计算速度快的优势&#xff0c;被广泛用于各种区块链&#xff0c…

深度解析 Android Matrix 变换(二):组合变换 pre、post

前言 在上一篇文章中&#xff0c;我们讲解了 Canvas 中单个变换的原理和效果&#xff0c;即缩放、旋转和平移。但是单个旋转仅仅是基础&#xff0c;Canvas 变换最重要的是能够随意组合各种变换以实现想要的效果。在这种情况下&#xff0c;就需要了解如何组合变换&#xff0c;以…

c++之迭代器

一.迭代器的基本概念 1.什么是迭代器 迭代器是一种对象&#xff0c;它提供了一种访问容器中各个元素的方法&#xff0c;同时隐藏了容器内部的实现细节。简单来说&#xff0c;迭代器就像是一个指针&#xff0c;它可以指向容器中的某个元素&#xff0c;并且能够通过一些操作&am…

在 .NET 9.0 Web API 中实现 Scalar 接口文档及JWT集成

示例代码&#xff1a;https://download.csdn.net/download/hefeng_aspnet/90408075 介绍 随着 .NET 9 的发布&#xff0c;微软宣布他们将不再为任何 .NET API 项目提供默认的 Swagger gen UI。以前&#xff0c;当我们创建 .NET API 项目时&#xff0c;微软会自动添加 Swagger…

【操作系统笔记】操作系统的功能

上节课,我们学习了《什么是操作系统》。接下来,我们来看看操作系统有哪些功能? 这里讲的内容有两部分,一个是操作系统的目标,另外一个就是操作系统的功能。这两个细节可能会在考试的时候考到,但是最近好些年很少考到了。为了理解,我们还是一起来看一下。 操作系统的目标…

C/C++蓝桥杯算法真题打卡(Day7)

一、P8723 [蓝桥杯 2020 省 AB3] 乘法表 - 洛谷 算法代码&#xff1a; #include<bits/stdc.h> // 包含标准库中的所有头文件&#xff0c;通常用于竞赛编程中简化代码 using namespace std; // 使用标准命名空间&#xff0c;避免每次调用标准库函数时都要加std:: ty…

数据结构5(初):排序

目录 1、排序的概念以及常见的排序算法 1.1、排序的概念 1.2、常见的排序算法 2、常见排序算法的实现 2.1、插入排序 2.1.1、直接插入排序 2.1.2、希尔排序 2.2、选择排序 2.2.1、直接选择排序 2.2.2、堆排序 2.3、交换排序 2.3.1、冒泡排序 2.3.2、快速排序 2.3.…

VS2022中通过VCPKG安装的ceres之后调试ceres的例程设置

1.采用C20. vcpkg中设置: 2.增加预处理宏: GLOG_USE_GLOG_EXPORT 3.屏蔽sdl错误 在 项目-属性-C/C -命令行中添加 /sdl /w34996 #include "ceres/ceres.h" //#include <iostream> //#include<glog/logging.h>using ceres::AutoDiffCostFunction; usi…

Pydantic字段级校验:解锁@validator的12种应用

title: Pydantic字段级校验:解锁@validator的12种应用 date: 2025/3/23 updated: 2025/3/23 author: cmdragon excerpt: Pydantic校验系统支持通过pre验证器实现原始数据预处理,在类型转换前完成字符清洗等操作。格式验证涵盖正则表达式匹配与枚举值约束,确保护照编号等字…

函数递归和迭代

1.什么是递归&#xff1f; 在C语言中递归就是自己调用自己。 看一下简单函数的递归&#xff1a; 上面的代码实现演示一下函数的递归&#xff0c;最终是会陷入死循环的&#xff0c;栈溢出 。 1.1递归的思想&#xff1a; 把一个大型的问题一步一步的转换成一个个小的子问题来解…

发票查验/发票验真如何用Java实现接口调用

一、什么是发票查验&#xff1f;发票验真接口&#xff1f; 输入发票基本信息发票代码、发票号码、开票日期、校验码后6位、不含税金额、含税金额&#xff0c;核验发票真伪。 该接口也适用于机动车、二手车销售发票、航空运输电子客票、铁路电子客票等。 二、如何用Java实现接口…

AM32-MultiRotor-ESC项目固件编译和烧录方法介绍

AM32-MultiRotor-ESC项目固件编译和烧录方法介绍 &#x1f4cd;AM32-MultiRotor-ESC项目地址:https://github.com/AlkaMotors/AM32-MultiRotor-ESC-firmware&#x1f388;Updater with V8 Bootloader&#xff1a; https://github.com/AlkaMotors/F051_Bootloader_Updater&#…

HarmonyOS:@AnimatableExtend 装饰器自学指南

在最近的项目开发中&#xff0c;我遇到了需要实现复杂动画效果的需求。在探索解决方案的过程中&#xff0c;我发现了 AnimatableExtend 装饰器&#xff0c;它为实现动画效果提供了一种非常灵活且强大的方式。然而&#xff0c;在学习这个装饰器的过程中&#xff0c;我发现相关的…

Windows server 2022域控制服务器的配置

Windows server 2022介绍 一、核心特性与改进 安全核心服务器&#xff08;Secured-Core Server&#xff09; 硬件级安全&#xff1a;支持基于硬件的安全功能&#xff08;如TPM 2.0、Secure Boot、基于虚拟化的安全防护VBS&#xff09;&#xff0c;防止固件攻击。受信任的启动链…

C++语法之模板函数和模板类

模板函数是什么&#xff1f;就是不指定类型的函数&#xff0c;不指定类型如何写代码?所以得用到模板&#xff0c;可以先用模板代替&#xff0c;就好像方程式&#xff0c;先用x,y代替一样。 它的写法是这样&#xff0c;定义函数时&#xff0c;开头加一句:(其中的T就相当于x,y之…

时序分析笔记

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、周期约束 二、建立时间和保持时间 三、时序路径 四、时序模型 前言 约束文件笔记&#xff0c;傅里叶的猫的视频。 一、周期约束 时序约束就是告诉软件输…

六十天前端强化训练之第二十八天之Composition 函数完全指南

欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗&#xff0c;谢谢大佬&#xff01; 目录 一、核心概念解析 1.1 什么是 Composition 函数 1.2 为什么需要封装 1.3 设计原则 二、实战案例&#xff1a;鼠标跟踪器 2.1 未封装版本 2.2 封装后的 Composition 函数…