引言
在之前的数组增删查改1.0项目中,我仅仅简单的封装了各函数,并通过"老土"且麻烦的方式,即通过每次注释代码,来调整想要实现的功能。该方法用户交互性差且不直观,而且不能实现功能的一起实现。因此,改进方法实现更高效,用户交互性更强的数组增删查改项目。
一、代码整体结构
本文实现的动态数组包含以下核心功能:
- 初始化数组并赋予初始值
- 向末尾添加元素
- 按下标插入元素(支持自动扩容)
- 按下标删除元素
- 按值删除元素
- 按下标 / 值查找元素
- 修改指定元素
- 交互式菜单操作
代码采用模块化设计,将不同功能封装为独立函数,主函数负责流程控制和用户交互。
二、代码逻辑及分析
1、头文件和宏定义
#include <stdio.h> // 提供输入输出函数(printf/scanf)
#include <stdlib.h> // 提供动态内存分配函数(malloc/realloc/free)
#define len 100 // 初始容量的宏定义
功能说明:
stdio.h
用于用户交互(输入输出提示信息)。stdlib.h
是动态数组的核心依赖,提供内存分配(malloc
)、扩容(realloc
)和释放(free
)函数。- 宏
len
定义数组初始容量,方便后续功能实现。
2. 添加元素功能
(1)向末尾添加元素
// 添加单个元素到末尾
void add(int e, int arr[], int s) {
arr[s] = e;
}
实现思路:
- 参数
e
为待添加元素,arr
为目标数组,s
为当前元素个数。 - 直接通过
arr[s] = e
赋值。
用户界面:

(2)按下标插入元素(支持自动扩容)
// 按照下标添加单个元素
void addByIndex(int *arr, int *size, int *capacity) {
int index, newNum;
printf("请输入要插入的下标:");
scanf("%d", &index);
printf("请输入要插入的元素:");
scanf("%d", &newNum);
// 检查下标合法性
if (index < 0 || index > *size) {
printf("下标不合法!\n");
return;
}
// 检查是否需要扩容
if (*size == *capacity - 1) {
*capacity *= 2; // 容量翻倍
int *newarr = (int *)realloc(arr, *capacity * sizeof(int));
if (newarr == NULL) { // 检查内存分配是否成功
printf("内存分配失败,扩容失败\n");
return;
}
arr = newarr; // 更新数组指针
printf("数组扩容成功,新容量:%d\n", *capacity);
}
// 元素后移,为新元素腾出位置
for (int i = *size; i > index; i--) {
arr[i] = arr[i - 1];
}
arr[index] = newNum; // 插入新元素
(*size)++; // 更新元素个数
}
实现思路:
- 输入与合法性检查 :接收用户输入的下标和元素,检查下标是否在
[0, size]
范围内(size
位置即末尾插入)。 - 自动扩容 :当元素个数接近容量上限(
size == capacity - 1
)时,将容量翻倍,通过realloc
重新分配内存,并更新数组指针。 - 元素后移:从最后一个元素开始,依次将元素向后移动 1 位,为新元素腾出位置。
- 插入与更新 :在目标下标插入新元素,元素总数
size
加 1。
关键要点:
- 扩容策略:容量翻倍(避免频繁扩容)。
用户界面:

3. 删除元素功能
(1)按下标删除元素
// 根据下标删除元素
int removeElement(int index, int arr[], int s) {
if (index < 0 || index >= s) {
printf("输入的下标不在合理范围内\n");
return 0;
}
int oldVal = arr[index];
for (int i = index; i < s - 1; i++) {
arr[i] = arr[i + 1];
}
arr[s - 1] = 0;
return oldVal;
}
实现思路:
- 合法性检查 :确保下标在
[0, size-1]
范围内。 - 保存被删除值:记录目标下标元素,用于返回结果。
- 元素前移:从删除位置开始,用后一个元素覆盖当前元素,直到倒数第二个元素。
- 清空残留值:最后一个元素置 0。
用户界面:

(2)按值删除元素
// 根据元素值删除
int deleteByElement(int arr[], int *size) {
printf("请输入删除的元素值:");
int deletedVal;
scanf("%d", &deletedVal);
int position = -1;
for (int i = 0; i < *size; i++) {
if (arr[i] == deletedVal) {
position = i;
break;
}
}
if (position != -1) {
int deleted = arr[position];
for (int i = position; i < *size - 1; i++) {
arr[i] = arr[i + 1];
}
(*size)--;
printf("删除成功,被删除的元素是:%d\n", deleted);
return deleted;
} else {
printf("未找到该元素,删除失败\n");
return -1;
}
}
实现思路:(仅删除第一个匹配项)
- 查找目标位置:遍历数组,找到第一个与目标值匹配的元素下标。
- 执行删除 :若找到,复用 "按下标删除" 的逻辑(元素前移),更新元素总数
size
。 - 结果反馈:返回被删除元素或提示未找到。
用户界面:

4. 查找与修改功能
(1)按值查找元素
// 根据元素值查找
void searchElement(int arr[], int size) {
printf("请输入查找的元素:");
int find;
scanf("%d", &find);
int position = -1;
for (int i = 0; i < size; i++) {
if (arr[i] == find) {
position = i;
break;
}
}
if (position != -1) {
printf("已查找到元素%d,位于下标%d\n", find, position);
} else {
printf("未查找到元素%d\n", find);
}
}
实现思路:遍历数组匹配目标值,记录第一个匹配项的下标并输出结果。
用户界面:


(2)修改元素
// 修改元素
void reviseElement(int arr[], int size) {
printf("请输入要修改的元素:");
int rev;
scanf("%d", &rev);
int revpos = -1;
for (int i = 0; i < size; i++) {
if (arr[i] == rev) {
revpos = i;
break;
}
}
if (revpos != -1) {
printf("已找到元素%d,请输入修改后的元素:", rev);
int newrev;
scanf("%d", &newrev);
arr[revpos] = newrev;
printf("修改成功\n");
} else {
printf("未找到元素%d,无法修改\n", rev);
}
}
实现思路:先查找目标值的下标,找到后直接通过下标赋值修改。
用户界面:

5. 主函数:初始化与交互逻辑
int main() {
int size = 8; // 初始元素个数
int capacity = len; // 数组容量(动态管理,初始为len=100)
int *arr = (int *)malloc(capacity * sizeof(int)); // 动态分配数组
// 初始化数组内容
int initArr[] = {1, 4, 5, 6, 9, 8, 2,3};
for (int i = 0; i < size; i++) {
arr[i] = initArr[i];
}
while (1) {
printf("\n功能列表:\n");
printf("1. 添加单个元素到末尾 -> 101\n");
printf("2. 根据下标增加元素 -> 102\n");
printf("3. 根据下标删除单个元素 -> 201\n");
printf("4. 根据元素值删除 -> 202\n");
printf("5. 根据下标查找单个元素 -> 301\n");
printf("6. 根据元素值查找 -> 302\n");
printf("7. 修改元素 -> 401\n");
printf("8. 结束程序 -> 999\n");
printf("请输入功能编号:");
int id = 0;
scanf("%d", &id);
// 功能分支处理
while (1) {
printf("\n功能列表:\n");
printf("1. 添加单个元素到末尾 -> 101\n");
printf("2. 根据下标增加元素 -> 102\n");
printf("3. 根据下标删除单个元素 -> 201\n");
printf("4. 根据元素值删除 -> 202\n");
printf("5. 根据下标查找单个元素 -> 301\n");
printf("6. 根据元素值查找 -> 302\n");
printf("7. 修改元素 -> 401\n");
printf("8. 结束程序 -> 999\n");
printf("请输入功能编号:");
int id = 0;
scanf("%d", &id);
if (id == 101) {
int num = 0;
printf("请输入一个整数:");
scanf("%d", &num);
if (size < capacity) { // 容量足够时直接添加到末尾
add(num, arr, size);
size++;
} else {
printf("数组已满,需扩容后添加(可使用"根据下标增加元素"功能)\n");
}
} else if (id == 102) {
addByIndex(arr, &size, &capacity); // 传递容量变量的地址
} else if (id == 201) {
int index = 0;
printf("请输入要删除的下标:");
scanf("%d", &index);
int deleted = removeElement(index, arr, size);
if (index >= 0 && index < size) {
printf("被删除的元素是:%d\n", deleted);
size--;
}
} else if (id == 202) {
deleteByElement(arr, &size);
} else if (id == 301) {
int index;
printf("请输入要查找的下标:");
scanf("%d", &index);
if (index >= 0 && index < size) {
printf("下标%d对应的元素是:%d\n", index, arr[index]);
} else {
printf("下标不合法\n");
}
} else if (id == 302) {
searchElement(arr, size);
} else if (id == 401) {
reviseElement(arr, size);
} else if (id == 999) {
free(arr); // 释放动态内存
exit(0); // 正常退出程序
} else {
printf("输入不合法,请重新输入!\n");
}
// 打印当前数组状态
printf("现有的元素:");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n当前元素总数:%d,数组容量:%d\n", size, capacity);
}
free(arr);
return 0;
}
实现思路:
- 初始化 :通过
malloc
动态分配初始内存(容量为len=100
),用预设数组initArr
初始化前 8个元素。 - 交互循环 :通过
while(1)
实现死循环菜单,用户输入功能编号后执行对应函数,操作后即时打印数组状态(元素、个数、容量)。 - 内存释放 :程序退出前用
free(arr)
释放动态内存,避免内存泄漏。
关键要点:
- 初始状态:
size=8
(元素个数)与capacity=100
(容量)分离,体现动态数组 "逻辑长度" 与 "实际长度" 的区别。 - 边界控制:所有操作均检查下标或容量合法性,避免越界访问。
用户界面:

三、核心设计思路总结
- 动态内存管理 :通过
malloc
分配初始内存,realloc
实现扩容,free
释放内存,解决静态数组容量固定的问题。 - 容量与大小分离 :
capacity(实际容量)
和size
(逻辑元素个数)独立管理,扩容仅改变capacity
,不影响元素数据。 - 元素移动策略:插入时 "后移" 腾位置,删除时 "前移" 覆盖,方向相反但均避免数据覆盖。
- 用户交互友好:通过菜单循环和即时状态打印,提升操作直观性。
四、项目受阻:

关键错误分析:
如上,在写代码过程中,编译遇到如图报错,一开始以为是define格式出现问题,后经过查资料,发现定义并未出错。后再仔细检查搜索反思,发现关键错误原因在于#define len 100
是宏定义(预处理时会被替换为常量 100
),而 addByIndex(arr, &size, &len);
中传递 &len
是非法的 ------ 常量没有 "地址",编译器会报 "lvalue required as unary '&' operand" (需要左值作为 &
操作数)。
解决方式:
- 定义变量**
capacity
** 管理数组容量,初始值为宏len
(即100
)。 - 修改
addByIndex
的参数,将int *len
改为int *capacity
,传递capacity
的地址以支持动态扩容。 - 调整数组分配、扩容、容量判断的逻辑,统一使用
capacity
变量。 同时,让capacity(实际容量)
和size
(逻辑元素个数)独立管理,扩容仅改变capacity
,不影响元素数据,实现容量与大小分离
五、注意事项
- 内存泄漏风险 :动态分配的内存必须用
free
释放,否则会导致内存泄漏。 - 扩容指针同步 :
addByIndex
中arr = newarr
仅更新函数内指针,若realloc
返回新地址,主函数指针可能未同步(AI分析指导),AI提到可通过二级指针优化。 - 边界检查 :所有涉及下标的操作必须验证范围,避免越界访问(如
removeElement
中的index >= s
检查)。