C语言中按值传递的结构体数组被函数修改的问题排查
问题分析与解决方案
问题根源
- 在C语言中,数组作为函数参数传递时,本质是传递数组首元素的指针,并非按值传递整个数组副本。所以你在
Opartenza函数里修改c[j]、c[j+1]的操作,直接作用于主函数中的原数组corse。 - 代码中
c[d] = c[j]属于数组越界访问,数组下标范围是0到d-1,访问c[d]会触发未定义行为,可能导致程序崩溃或数据错乱。
修正方案
要实现“不修改原数组,仅通过索引数组排序”的需求,核心是只操作索引数组,完全不改动原结构体数组。比较时通过索引访问原数组元素,交换的只是索引数组中的值。
修正后的函数代码:
void Opartenza(struct Corse c[], int d, int **O) { int temp = 0; // 分配索引数组内存,先检查分配是否成功 *O = (int *)malloc(d * sizeof(int)); if (*O == NULL) { return; } // 初始化索引数组,对应原数组的下标 for(int i = 0; i < d; i++) (*O)[i] = i; // 冒泡排序,仅操作索引数组 for(int i = 0; i < d; i++) { // 优化冒泡排序,减少不必要的循环次数 for(int j = 0; j < d - 1 - i; j++) { // 通过索引访问原数组元素进行比较 if(strcmp(c[(*O)[j]].partenza, c[(*O)[j+1]].partenza) > 0) { // 仅交换索引数组中的值 temp = (*O)[j]; (*O)[j] = (*O)[j + 1]; (*O)[j + 1] = temp; } } } }
使用示例
调用后,需通过索引数组访问原数组来输出排序结果,而非直接遍历原数组:
case r_o_partenza: Opartenza(corse, dim, &Ordinamento); // 通过索引数组输出排序后的内容 for(int i = 0; i < dim; i++) printf("%s\n", corse[Ordinamento[i]].partenza); // 用完后释放内存,避免泄漏 free(Ordinamento); Ordinamento = NULL; break;
注意事项
- 内存分配后必须检查是否成功,避免空指针访问。
- 索引数组使用完毕后要调用
free释放内存,防止内存泄漏。 - 可给冒泡排序添加“是否已排序”的标志,提前终止循环,提升效率。
内容的提问来源于stack exchange,提问作者th3 wolf
相关产品推荐
相关产品推荐

