当前位置: 首页 > news >正文

详细介绍:数组初阶(2)

详细介绍:数组初阶(2)

目录

1.数组的本质

2.数组的边界与安全问题

3.数组的高级操作

4.数组与指针的深度关联(重点)

5.字符串数组 


这一章节主要内容:

1.数组的本质

2.数组的边界与安全问题

3.数组的高级操作

4.数组与指针的深度关联(重点)

5.字符串数组 

1.数组的本质

数组名:(重中之重)

数组名在除了sizeof(数组名)和&(数组名)的情况下表示的是首元素的地址。

sizeof(数组)&(数组名)表示的是整个数组。

#include 
int main() {int arr[5] = {1,2,3,4,5};// 1. 数组名通常是首元素地址(arr 等价于 &arr[0])printf("arr = %p\n", arr);           // 首元素地址(如 0x7ffd...)printf("&arr[0] = %p\n", &arr[0]);   // 与 arr 完全相同// 2. sizeof(arr) 计算整个数组的字节数(5个int,每个4字节 → 20)printf("sizeof(arr) = %zu\n", sizeof(arr));  // 输出 20// 3. &arr 取整个数组的地址(类型为 int(*)[5],即数组指针)printf("&arr = %p\n", &arr);         // 地址值与 arr 相同,但类型不同// 验证类型差异:&arr + 1 偏移整个数组的大小(20字节)printf("&arr + 1 = %p\n", &arr + 1); // 比 &arr 大 20(十进制)return 0;
}
  • 数组名不是可修改的指针(arr = &arr[1]; 会编译错误)。
  • &arr 的类型是 “指向整个数组的指针”,因此 &arr + 1 会跳过整个数组,而 arr + 1 只跳过一个元素。

数组长度计算:

计算公式:sizeof(arr)/sizeof(arr[0]);

#include 
int main() {int arr1[5] = {1,2};  // 长度固定为5,未初始化元素默认0(全局/静态数组)int arr2[] = {1,2,3}; // 省略长度,编译器自动计算为3// 计算数组长度的通用公式int len1 = sizeof(arr1) / sizeof(arr1[0]); // 5int len2 = sizeof(arr2) / sizeof(arr2[0]); // 3printf("arr1长度:%d,arr2长度:%d\n", len1, len2);// 错误:数组长度不可修改,不能动态扩容// arr1[5] = 6;  // 越界访问(有效下标0~4)return 0;
}
  • 局部数组未初始化的元素是随机值,全局 / 静态数组默认初始化为 0。
  • 若数组作为函数参数,sizeof(arr) 会退化为指针大小(如 64 位系统为 8),因此需额外传长度参数。

2.数组的边界与安全问题

1.数组越界的危害及规避

#include 
int main() {int arr[3] = {10,20,30};int x = 100;// 越界访问:修改了数组外的内存(可能覆盖x的值)arr[5] = 200;  // 编译不报错,但运行时可能导致x变为200printf("x = %d\n", x);  // 输出可能为200(取决于内存布局)// 正确做法:用长度控制循环int len = sizeof(arr)/sizeof(arr[0]);for(int i=0; i

那么我们应该如何正确初始化呢,这个我们在上节课中已经讲过,在这不做赘述。

3.数组的高级操作

 数组作为函数参数(退化问题)

数组作为参数的时候,会退化成指针,丢失长度,那么什么是数组退化呢,我们后边有专门一章节来详细讲解,让你搞懂数组退化,现在只是简单阐述一下。

#include 
// 错误:函数内无法通过sizeof获取原数组长度(arr已退化为指针)
void printArr1(int arr[]) {int len = sizeof(arr)/sizeof(arr[0]); // 计算错误(8/4=2,64位系统)printf("错误长度:%d\n", len);
}
// 正确:额外传入长度参数
void printArr2(int arr[], int len) {for(int i=0; i

在上面的代码中,arr是int[5]类型,但在数组做函数参数的时候,会后退化成指针,退化成

int*类型。退化后只有4个字节(x86操作系统)。

  • void func(int arr[]) 等价于 void func(int *arr),函数无法知道数组实际长度。
  • 必须通过额外参数传递长度(如 printArr2),或使用结束标记(如字符串的 '\0')。

数组的拷贝与比较

#include 
#include  // 包含memcpy
int main() {int arr1[5] = {1,2,3,4,5};int arr2[5];// 错误:数组不能直接用=赋值// arr2 = arr1;  // 编译错误// 正确1:循环逐个拷贝for(int i=0; i<5; i++){arr2[i] = arr1[i];}// 正确2:用memcpy内存拷贝(效率更高)memcpy(arr2, arr1, sizeof(arr1)); // 拷贝整个arr1到arr2// 错误:数组不能直接用==比较(比较的是首地址)if(arr1 == arr2) printf("相等"); // 永远为假(地址不同)// 正确:循环逐个比较元素int isEqual = 1;for(int i=0; i<5; i++){if(arr1[i] != arr2[i]){isEqual = 0;break;}}printf("元素是否相等:%s\n", isEqual ? "是" : "否"); // 是return 0;
}
  • memcpy(dest, src, n) 按字节拷贝,需确保目标数组有足够空间。
  • 比较数组时必须遍历所有元素,任何一个不等则数组不等。

后面我们会详细讲解memcpy函数和相关的函数。

4.数组与指针的深度关联(重点)

 数组下标与指针的等价性

arr[i] 本质是 *(arr + i),指针偏移与下标访问完全等价。

#include 
int main() {int arr[5] = {10,20,30,40,50};// 下标访问与指针访问等价printf("arr[2] = %d\n", arr[2]);         // 30printf("*(arr + 2) = %d\n", *(arr + 2)); // 30(等价)// 反向等价(不推荐,可读性差)printf("2[arr] = %d\n", 2[arr]);         // 30(等价于*(2 + arr))// 指针变量操作数组int *p = arr; // p指向首元素printf("p[3] = %d\n", p[3]);             // 40printf("*(p + 3) = %d\n", *(p + 3));     // 40(等价)return 0;
}
  • 数组下标是指针偏移的 “语法糖”,编译器会自动转换为指针操作。
  • 指针变量 p 可像数组一样用 p[i] 访问,与 arr[i] 逻辑一致。

5.字符串数组 

字符串数组就是字符串这就话对吗?

字符数组不一定是字符串,字符串必须以 '\0' 结尾。

#include 
#include 
int main() {// 字符数组(无'\0',不是字符串)char arr1[3] = {'a','b','c'};printf("strlen(arr1) = %zu\n", strlen(arr1)); // 结果随机(未找到'\0')// 字符串(以'\0'结尾)char str1[4] = {'a','b','c','\0'}; // 显式加'\0'char str2[] = "abc"; // 隐式加'\0'(长度为4:'a','b','c','\0')printf("strlen(str2) = %zu\n", strlen(str2)); // 3(统计'\0'前的字符)printf("str2 = %s\n", str2); // 正确打印:abc(遇到'\0'停止)return 0;
}
  • strlen 等字符串函数依赖 '\0' 判断结束,无 '\0' 会越界。
  • 用 " " 初始化的字符数组会自动添加 '\0',推荐用这种方式定义字符串。
  • strlen的返回类型size_t。
http://www.jsqmd.com/news/44916/

相关文章:

  • Gemini 3 Pro入门教程:从零开始学会使用最新gemini-3-pro-preview API接入
  • 20232314 2025-2026-1 《网络与系统攻防技术》实验七实验报告
  • 高州市陈郁强副主任擅长做肠癌手术:口碑优秀+医术高超!
  • 102302156 李子贤 数据采集第三次作业
  • SHELL脚本的基础入门
  • roocode_kilocode对比
  • 工程成本管理软件新纪元:选软件看这三点!
  • 全国计算机等级考试——二级JAVA完整大题题库【五十三道】
  • 【C + +】unordered_set 和 unordered_map 的用法、区别、性能全解析 - 实践
  • Spring AI 代码分析(一)--工程结构
  • Spring Boot迅速集成MiniMax、CosyVoice实现文本转语音
  • Cursor接入飞书MCP
  • 完整教程:微信生态新机遇:视频号推客模式助力商家突围
  • linux framework
  • linux framebuffer
  • Spring AI 代码分析(二)--Model 领域
  • gdb实践((2510更新)
  • Mars项目与TensorFlow集成指南
  • win10/win11系统默认应用或文件打开方式重启后被自动重置的解决办法
  • 详细介绍:第八节_PySide6基本窗口控件_按钮类控件(QAbstractButton)
  • 哪里有免费的编程体验课?2025国内外优质平台与真实体验价值分析
  • 2025 上海办公室 商铺装修核心服务商 TOP5 解析报告:双场景适配能力与品质选型全景指南
  • Luogu P6234 [eJOI 2019] T 形覆盖 题解 [ 紫 ] [ 图论建模 ] [ 分类讨论 ] [ 基环树 ]
  • gemini3-思考模式 测评
  • AI Compass前沿速览:Gemini 3、Grok 4.1、GPT-5.1、千问、Lumine-3D开世界AI智能体
  • 人工智能之编程进阶 Python高级:第八章 网络并发类模块
  • 2025CCPC济南站游记
  • ssh登录报错Permission denied(publickey,gssapi-keyex,gssapi-with-mic,password
  • Bisq交易协议全解析:从多签到MuSig的技术演进
  • 十六岁的断章