资讯动态

函数与扩容 | C指针基础(三)

发布时间:2026/10/5 6:59:22 来源:尧图企业网站定制
函数与扩容 | C指针基础三指针作为函数参数数组扩容错误示例数组整体赋值malloc 与 free注意点函数无法直接返回数组错误示例局部变量的限制将扩容封装为函数指针作为函数参数将数组名即数组首元素的地址作为函数参数传入时函数内部对数组元素的修改会直接作用于外部的原始数组。需要特别说明的是当数组名作为实参传入函数时它会退化为指向首元素的指针。因此形参写成int arr[]实际上等价于int *arr。下面通过一个例子来验证#includestdio.h// 形参 int arr[] 实际等价于 int *arrvoidprintArr(intarr[]){for(inti0;i10;i){arr[i]arr[i]1;// 通过指针修改元素值printf(%d,,arr[i]);}printf(\n);}intmain(){intarr[10]{0};printArr(arr);// 传入数组名即数组首元素的地址for(inti0;i10;i){printf(%d,,arr[i]);// 主函数中的数组同步被修改}return0;}运行后会发现函数内部对arr的修改会同步反映到main函数的数组中。原因是传入函数的正是数组首元素的指针形参和实参指向的是同一块内存对指针所指向内存的修改自然会影响原始数组。这也正是指针作为函数参数的重要用途——在函数中直接修改外部数据而无需返回整个数组。数组扩容在实际开发或竞赛题中我们有时无法预先确定数组需要多大的长度于是自然希望数组能够自动扩容。不过 C 语言原生数组一旦定义长度就是固定的通常需要借助动态内存分配来模拟“扩容”。#includestdio.h#includestdlib.hintmain(){intlen10;int*arr1(int*)malloc(len*4);// 字节单位for(inti0;ilen;i){// *(arr1 1) i * 5;arr1[i]i*5;}// 扩容len*2;int*arr2(int*)malloc(len*4);// 字节单位for(inti0;ilen;i){arr2[i]arr1[i];}// 替换地址arr1arr2;return0;}在这段代码中len表示数组的长度malloc用于动态分配内存。len * 4中的4代表int类型所占的字节数更推荐使用sizeof(int)(int *)则是强制类型转换。向动态内存写入数据时既可以使用指针访问也可以使用数组下标访问。所谓“扩容”本质是重新动态分配一块大小为len * 2的新空间把旧空间里的数据复制进去再将地址替换成新空间的地址。这样一来虽然arr1的变量名没变但它保存的指针已经变成了新空间的地址后续再通过arr1访问时实际访问的是arr2指向的新空间从而完成扩容。先展示正确方法下面看一些错误方法错误示例数组整体赋值#includestdio.h#includestdlib.hintmain(){intlen10;intarr1[len]{0};// 字节单位for(inti0;ilen;i){// *(arr1 1) i * 5;arr1[i]i*5;}// 扩容len*2;intarr2[len]{0};// 字节单位for(inti0;ilen;i){arr2[i]arr1[i];}arr1arr2;return0;}乍一看似乎没问题先创建新数组arr2逐个元素复制后再把arr1指过去好像就完成了扩容。但在 C 语言中这段代码存在多处无法通过编译的问题。首先int arr2[len] arr1;不是合法的数组初始化方式C 语言不允许用一个数组去初始化另一个数组。其次arr1 arr2;也是非法的因为数组名在表达式中会退化为指向首元素的指针但它本身并不是一个可以修改的指针变量而是一个编译期确定的常量地址不能作为左值被赋值。因此所谓的“旧数组 新数组”无法通过修改数组名来实现。另外在 C 语言中数组只能在定义或声明时完成一次初始化之后不能对整体再次赋值。malloc 与 freemalloc用于在程序运行期间从堆上动态申请一块连续内存并返回这块内存的首地址申请失败时会返回NULL。这块内存不会随函数结束自动释放因此适合用来构造需要跨函数使用的数组。malloc的语法结构如下指针变量(类型*)malloc(字节数);例如int *p (int *)malloc(n * sizeof(int));表示申请一块能存放n个int的连续内存并把首地址赋给int *类型的指针p。动态申请的内存在使用完毕后必须调用free主动释放否则会造成内存泄漏。释放后最好及时把指针置为NULL避免之后误用已经失效的地址形成“悬空指针”。同时要注意只能释放由malloc等动态分配函数返回的地址不能对同一块内存重复释放。free的语法结构如下free(指针变量);例如free(p);表示释放指针p所指向的、由malloc等函数动态申请的内存。释放后建议把指针置为NULL例如p NULL;避免形成悬空指针。一个示例如下#includestdlib.hintmain(){int*p(int*)malloc(sizeof(int));if(pNULL)return1;*p10;free(p);pNULL;return0;}这个示例完整演示了malloc和free的基本使用规范int *p (int *)malloc(sizeof(int));从堆上申请一块能存放一个int的内存并把这块内存的首地址赋给指针p。这里建议写sizeof(int)而不是写死4因为不同平台上int占用的字节数可能不同。if (p NULL) return 1;malloc有可能申请失败比如系统内存不足。申请失败时它会返回NULL此时p不指向任何有效内存不能再执行*p 10否则可能让程序崩溃。判断p NULL就是为了提前处理这种情况。return 1表示main函数以非 0 状态结束在 C 语言惯例中main返回0表示程序正常结束返回非0表示程序执行失败。*p 10;通过解引用指针p把10写入刚申请到的内存中。free(p);这块内存使用完毕后必须调用free主动释放否则会造成内存泄漏。p NULL;释放内存后把指针清空避免之后误用已经失效的地址形成悬空指针。return 0;最后返回0表示程序正常结束。注意点函数无法直接返回数组在 C 语言中函数无法直接将整个数组作为返回值输出。因为数组名在表达式中会退化为指向首元素的指针所以函数真正能返回的是数组首元素的指针而不是数组本身。虽然函数不能直接返回一个完整的数组但可以返回由malloc动态分配的数组首地址。下面是一个正确示例#includestdio.h#includestdlib.hint*createArray(intn){int*arr(int*)malloc(n*sizeof(int));returnarr;}intmain(){intn;scanf(%d,n);int*arrcreateArray(n);return0;}在上述代码中createArray根据传入的n使用malloc(n * sizeof(int))申请一块能够存放n个整数的连续内存空间并返回这块内存的首地址。main函数通过int *arr createArray(n);接收这个地址后就可以像普通数组一样使用arr[i]访问其中的元素。错误示例局部变量的限制#includestdio.h#includestdlib.hint*createArray(intn){intarr[n];returnarr;}intmain(){intn;scanf(%d,n);int*arrcreateArray(n);return0;}这段代码看似把数组返回给了主函数但其实arr只是函数内部临时创建的数组。函数一结束这块内存就不再属于当前程序里面原来保存的数据也可能被其他内容覆盖。此时返回的地址已经“失效”主函数再照着这个地址去读取数据结果就无法保证可能读到错误的值也可能直接让程序崩掉。正确做法还是像前面那样用malloc申请内存。malloc申请到的内存不会因为函数结束而自动消失因此返回它的地址才是安全的。将扩容封装为函数#includestdio.h#includestdlib.hint*expand(int*length,intarr[]){intnewLength*length*2;int*newArr(int*)malloc(newLength*sizeof(int));for(inti0;i*length;i){newArr[i]arr[i];}*lengthnewLength;returnnewArr;}intmain(){intlength5,num;int*arr(int*)malloc(length*sizeof(int));printf(Please enter a number: );scanf(%d,num);arrexpand(length,arr);return0;}把扩容逻辑单独抽成一个expand函数后主函数里的调用更清晰了arr expand(length, arr);一次调用就完成了“申请新空间、复制旧数据、更新长度、返回新地址”。下面结合代码梳理几个容易忽略的注意点为什么传length而不是length函数只能返回一个值这里已经用返回值返回了新数组的首地址没法再同时返回新的数组长度。于是我们把length的地址传进去让函数通过指针直接修改main里的length这样函数结束后长度变化仍然保留。这也是前面“指针作为函数参数”一节思路的延续。函数内部使用length时为什么加*形参int *length是一个指针保存的是外部length变量的地址。要读取它指向的值或修改它需要先解引用也就是写*length如果直接写length拿到的只是地址本身。形参int arr[]其实是语法糖。在函数形参中int arr[]等价于int *arr它接收的是数组首元素地址而不是把整个数组复制一份。所以函数内部通过arr[i]操作元素时实际上是在操作外部数组。还需要注意动态申请的内存使用完毕后应及时用free释放。本示例为保持简短没有展示释放步骤。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑