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

7、C 语言数组进阶知识点总结

数组名的双重含义、下标运算符的本质、字符串常量特性及特殊数组类型等方面,数组进阶知识

C 语言数组进阶核心知识点总结

一、数组名的双重含义

数组名在不同场景下有两种核心含义:代表整个数组代表首元素的地址,这是数组操作的核心易错点,需严格区分。

1. 代表整个数组的场景

  • 数组定义时:数组名表示完整的数组对象,内存大小由定义时的元素个数决定,且数组名不可修改(类似常量指针)。

示例:int buf[5] = {0};buf代表整个数组,不可执行buf = buf + 1等修改操作)。

  • sizeof运算符中sizeof(数组名)计算的是整个数组的总字节数,而非指针大小。

示例:int buf[5]; printf("%lu", sizeof(buf));(输出 20,即 5 个 int 的总大小)。

  • 在取址符&&数组名表示整个数组的地址,其 “作用范围” 为数组总大小(地址 + 1 的偏移量等于数组总字节数)。

示例:

int buf[5];

printf("&buf: %p, &buf+1: %p", &buf, &buf+1);

// 地址相差20字节(5×4),证明&buf代表整个数组

2. 代表首元素地址的场景

  • 指针指向数组时:数组名被赋值给指针后,指针存储的是数组首元素的地址,指针 + 1 的偏移量等于单个元素的字节数。

示例:

int buf[5]; int* p = buf;

printf("p: %p, p+1: %p", p, p+1);

// 地址相差4字节(int的大小),证明p指向首元素

  • 函数传参时:数组作为函数参数时,会退化为首元素的指针(“数组退化”),函数内sizeof(数组参数)计算的是指针大小(与系统位数相关)。

示例:

void func(int arr[]) {

    printf("%lu", sizeof(arr)); // 64位系统输出8(指针大小)

}

int main() {

    int buf[5]; func(buf); // 传参时buf退化为指针

}

  • 使用scanf输入时scanf需要的是首元素地址,数组名直接作为参数即可,无需加&(否则类型不匹配)。

示例:char buf[128]; scanf("%s", buf);(正确,buf是首元素地址)。

  • 直接使用数组名时:数组名单独出现时,默认表示首元素地址(如打印地址或参与指针运算)。

示例:printf("buf: %p", buf);(输出首元素地址)。

二、数组下标运算符[]的本质

数组下标运算本质是指针运算的简写,编译器会自动将a[i]转换为*(a + i),二者完全等价。

1. 等价转换示例

  • buf[0]等价于*(buf + 0)(访问首元素)。
  • buf[3]等价于*(buf + 3)(访问第 4 个元素)。

2. 特殊推论:根据加法交换律

由于a + ii + a等价,因此i[a]a[i]完全等价(语法合法但不推荐使用,易降低可读性)。

示例:int buf[5] = {1,2,3,4,5}; printf("%d", 3[buf]);(输出 4,等价于buf[3])。

三、字符串常量的特性

字符串常量是一种特殊的匿名数组,存储在常量区(只读),默认以'\0'结尾,其特性与数组一致。

1. 核心特性

  • 匿名数组属性:字符串常量符合数组的双重含义(sizeof计算总大小含'\0'&取址代表整个字符串地址)。

示例:printf("%lu", sizeof("nihao"));(输出 6,即 5 个字符 + 1 个'\0')。

  • 只读性:字符串常量存储在常量区,不可修改(通过指针修改会导致段错误)。

示例:

char* p = "hello";

// *(p + 0) = 'H'; // 错误:修改常量区数据,触发段错误

  • 与字符数组的区别
    • 字符数组(char buf[] = "hello"):存储在栈区,可修改(复制常量区数据到栈区)。
    • 字符串常量(char* p = "hello"):存储在常量区,不可修改,指针仅指向首地址。

2. 常见操作注意事项

  • 函数传参:字符串常量作为参数传递时,退化为首元素指针(与数组传参一致)。
  • 不可用scanf修改scanf("%s", "hello");错误,因字符串常量在常量区不可写。

四、特殊数组类型

1. 零长数组(int arr[0]

  • 概念:长度为 0 的数组,不占用内存,仅作为 “地址入口”,类似指针但无独立内存。
  • 用途:放在结构体末尾,用于动态拓展结构体的内存(解决结构体长度固定的问题)。

示例:

struct Student {

    char name[128];

    int score;

    char extra[0]; // 零长数组,作为拓展入口

};

// 申请包含100字节拓展空间的结构体

struct Student* s = malloc(sizeof(struct Student) + 100);

strcpy(s->extra, "拓展信息"); // 使用零长数组存储额外数据

2. 不定长数组(char arr[] = "abc"

  • 概念:定义时不指定长度,由初始化列表的元素个数自动确定长度(含字符串的'\0')。
  • 特点
    • 优点:不浪费内存(长度恰好匹配初始化数据)。
    • 缺点:定义后长度固定,不可修改;需通过sizeof计算长度(sizeof(arr)/sizeof(arr[0]))。

示例:char buf[] = "hello";(长度为 6,含'\0')。

3. 变长数组(int arr[n]n为变量)

  • 概念:定义时使用变量指定长度的数组,长度在运行时确定(区别于编译期确定的普通数组)。
  • 特点

int n = 5;

int buf[n]; // 合法:变长数组,长度为5

// int buf[n] = {0}; // 错误:变长数组不可初始化

    • 长度由变量决定,定义后固定(不可动态改变)。
    • 不可初始化(初始化在编译期完成,变量值此时未知)。
    • 适用于处理长度动态变化的数据(如未知大小的图片、文件内容)。

示例:

五、核心注意事项

  1. 数组退化:函数传参时数组必然退化为指针,需额外传递数组长度参数(如void func(int arr[], int len))。
  2. 字符串操作:区分字符数组(栈区,可修改)与字符串常量(常量区,只读),避免通过指针修改常量区数据。
  3. 特殊数组适用场景
    • 零长数组:结构体动态拓展。
    • 不定长数组:初始化数据长度已知且固定的场景。
    • 变长数组:处理长度动态变化但定义后固定的数据(如用户输入长度的缓冲区)。
  1. 避免越界:所有数组操作需严格控制在定义的长度内,通过sizeof或显式参数确保不越界。

总结

数组进阶的核心是理解数组名的双重含义及 “数组退化” 特性,这是避免指针越界、内存错误的关键。特殊数组(零长、不定长、变长)则为不同场景提供了灵活的内存管理方案,需根据实际需求选择:零长数组适合结构体拓展,不定长数组适合固定初始化数据,变长数组适合动态长度场景。掌握这些知识,能更高效、安全地操作数组与字符串。

http://www.dtcms.com/a/331446.html

相关文章:

  • 解决SQL Server连接失败:Connection refused: connect
  • 力扣(LeetCode) ——225 用队列实现栈(C语言)
  • C++中的回调函数
  • C++中的内存管理(一)
  • BitDock——让你的Windows桌面变为Mac
  • 【ai写代码】lua-判断表是否被修改
  • Mysql基本使用语句(一)
  • [激光原理与应用-271]:理论 - 波动光学 - 电磁波谱,光是一种可视化的电磁波
  • 广义矩估计随机近似中1.2和2.1的差异
  • 获取iframe中canvas画面
  • 爬虫数据存储全攻略:从 Robots 协议到文件存储
  • C++11新特性深度解析
  • Linux软件下载菜单脚本
  • Effective C++ 条款41:理解隐式接口和编译期多态
  • 系统设计——DDD领域模型驱动实践
  • 深入浅出词向量(Word2Vec):从理论到实践
  • 数据结构初阶(13)排序算法-选择排序(选择排序、堆排序)(动图演示)
  • 【Java 后端】Spring Boot 集成 JPA 全攻略
  • HTTPS 工作原理
  • 电池充放电测试仪厂家:技术深耕与场景驱动的行业进阶
  • Java使用Apache POI读取Excel文件
  • Vue浅学
  • 深入解析 GitHub Actions 工作流文件编写:从入门到实战
  • 简单的 HTTPS 学习
  • 第四天-创建一个Classic CAN(经典CAN2.0)/CANFD的系统描述ARXML文件
  • 读From GPT-2 to gpt-oss: Analyzing the Architectural Advances
  • IPv6互联网地址解析
  • 从合规到卓越:全星QMS如何成为制造企业的质量战略引擎
  • linux 软硬链接详解
  • 《算法导论》第 25 章:所有结点对的最短路径问题