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

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.xdnf.cn/news/17866.html

相关文章:

  • Mac 新电脑安装cocoapods报错ruby版本过低
  • 仪器制造业推广平台推荐有哪家
  • 计算机视觉(opencv)实战二——图像边界扩展cv2.copyMakeBorder()
  • K8S企业级应用与DaemonSet实战解析
  • 我们可以无损放大一个transformer吗
  • [vibe coding-lovable]lovable是不是ai界的复制忍者卡卡西?
  • 微美全息(WIMI.US)借区块链与聚类技术,开启物联网去中心化安全架构新纪元
  • Maven学习笔记
  • iOS Sqlite3
  • PDF 段落提取利器:Spring AI 的 ParagraphPdfDocumentReader 实战
  • docker 容器管理入门教程
  • 【科研绘图系列】R语言绘制微生物丰度和基因表达值的相关性网络图
  • 解剖HashMap的put <五> JDK1.8
  • 短视频流量|基于Java+vue的短视频流量数据分析系统(源码+数据库+文档)
  • Go语言实战案例:用Gin实现图书管理接口
  • 云原生俱乐部-k8s知识点归纳(1)
  • 当GitHub宕机时,我们如何协作?
  • Flutter sqflite插件
  • Docker运行python项目:使用Docker成功启动FastAPI应用
  • Java 中导出 Excel 文件的方法
  • 本地jar导入到本地仓科和远程仓库
  • [ HTML 前端 ] 语法介绍和HBuilderX安装
  • Spring Boot 3中JWT密钥安全存储方案
  • 图灵测试:人工智能的“行为主义判据”与哲学争议
  • 论,物联网日志系统架构如何设计?
  • 使用colmap自制3DGaussian_Splatting数据集
  • Java进阶学习之Stream流的基本概念以及使用技巧
  • 第四天~在CANFD或CAN2.0的ARXML文件中实现Multiplexor多路复用信号实战
  • 3D-R1、Scene-R1、SpaceR论文解读
  • Codeforces Round 1042 (Div. 3)