C语言数组详解:创建初始化、内存存储与传参陷阱

宋时安
宋时安
发布时间:2026-10-16| 7人浏览过
原创

本文深入解析C语言一维及二维数组的创建与初始化规范,特别是字符数组的 \`\0\` 结尾机制。通过对比不同方式定义字符串的差异,揭示数组名在 sizeof 和 & 操作下的特殊含义,并详细剖析函数传参时数组退化为指针导致的长度计算错误,最后提供带状态标志的冒泡排序正确实现方案。

1. 一维数组的创建和初始化

第1步:创建数组并规范语法

数组是相同类型元素的集合。创建时需指定元素类型和常量大小(C99之前):

// type_t 为元素类型,const_n 为常量表达式
type_t arr_name[const_n];

int arr1[10]; // 合法
char arr3[10];
// int count = 10;
// int arr2[count]; // C89标准不支持,易引发歧义,建议使用常量或宏

第2步:初始化并注意字符数组的结束符

初始化可通过直接赋值确定大小,不指定大小时由内容决定:

int arr[] = {1, 2, 3};              // 自动推断大小为3
char arr_str[] = "abcdef";          // 隐式包含结尾 ' ',实际占用7字节

仔细区分以下五种字符串/字符数组的定义差异:

char arr1[] = "abc";                // 包含' ', 长度4
char arr2[3] = {'a','b','c'};       // 无' ', 打印将导致乱码
char arr3[] = {'a','b','c'};        // 同上
char arr4[4] = {'a','b','c'};       // 末尾未赋值为' '(可能为0),但逻辑上不应依赖
char arr5[] = {'a','b','c',' '};   // 显式包含' ', 长度4

推荐使用双引号 char arr1[] = "abc"; 的形式,编译器会自动处理结尾标识。

第3步:使用下标访问与内存连续存放验证

数组下标从 0 开始。可通过指针递增观察内存地址规律:

int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *p = &arr[0];
for (int i = 0; i < 10; i++) {
    printf("&arr[%d]=%p <==> %p\n", i, &arr[i], p++);
}

执行结果表明,随着下标增加,内存地址连续递增(每个 int 占 4 字节)。

2. 二维数组的创建和使用

第4步:创建并初始化二维数组

二维数组可看作“行”与“列”的组合。初始化时若省略行数,列数必须指定:

int arr[][4] = {{1, 2}, {3, 4}};    // 自动推断为2行
int arr1[][5] = {1, 2, 3, 4, 5, 6}; // 不完全初始化,补充全零

第5步:遍历二维数组并观察内存连续性

二维数组在内存中依然是连续存放的:

int arr[3][5] = {{1, 2},{3, 4},{5, 6}};
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 5; j++) {
        printf("&arr[%d][%d]=%p\n", i, j, &arr[i][j]);
    }
}

&arr[0][3] 与 &arr[1][0] 地址相连。

3. 数组越界风险与控制

C语言不进行越界检查,程序员需自行保证范围限制(0 到 n-1)。当循环条件写成 <= 时极易触发越界:

int arr[10] = {1, ..., 10};
for(int i=0; i<=10; i++) { // i=10 时为非法访问
    printf("%d\n", arr[i]);
}

4. 数组作为函数参数的核心陷阱

第6步:理解数组传参时的退化现象

常见的冒泡排序实现错误在于函数内调用 sizeof(arr):

void bubble_sort_err(int arr[]) {
    // 此时 arr 退化为指针!sizeof(arr) 等于指针大小(如4),非数组总大小
    int sz = sizeof(arr)/sizeof(arr[0]); 
}

通过单步调试可见,虽然主函数传入了10个元素,但进入函数后数组被视为首元素地址(指针),长度为1而非10,导致排序失效。

第7步:掌握数组名的两个特例

  • sizeof(数组名):表示整个数组的大小。
  • &数组名:表示整个数组的地址。
  • 除此之外,所有数组名均代表首元素地址。

验证如下:

printf("%p\n", arr);      // 首元素地址
printf("%p\n", &arr);     // 数组地址(数值同,但类型意义不同)

第8步:修正冒泡排序实现

在调用者计算好元素个数 sz 并传给函数:

void bubble_sort(int* arr, int sz) {
    int i, j, flag;
    for(i = 0; i < sz - 1; i++) {
        flag = 1;
        for(j = 0; j < sz - 1 - i; j++) {
            if(arr[j] > arr[j+1]) {
                int tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
                flag = 0;
            }
        }
        if(flag == 1) break; // 提前终止优化
    }
}

int main() {
    int arr[] = {3, 1, 2, 4, 5, 6, 8, 9, 7, 10};
    int sz = sizeof(arr)/sizeof(arr[0]);
    bubble_sort(arr, sz);
    // ... 输出结果 ...
}

总结

以上就是C语言数组的详细内容,更多关于C语言数组的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。