You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言通用swap函数可交换字符串,交换数组触发核心转储问题

为什么通用swap函数能交换字符串指针却无法交换数组?

你的问题核心在于混淆了字符串指针和数组名的本质差异,下面拆解问题原因并给出解决方案:

1. 字符串指针交换能正常工作的原因

你定义的char *h = "hell"和char *w = "world"中,h和w是指针变量——它们在栈上拥有自己的存储空间,存储的是字符串常量的首地址。

当你调用swap((void **)&h, (void **)&w)时:

  • &h是指针变量h的地址,类型为char **,强制转为void **后传入swap函数是合法的
  • swap函数内部交换的是*a和*b,也就是两个指针变量中存储的地址值,本质是修改指针变量的内容,完全符合内存规则,所以能正常运行。

2. 数组交换触发栈崩溃的原因

而char c[5]和char d[3]中的c和d是数组名,它不是可修改的变量,而是一个编译期的常量标识符,代表数组首元素的地址。

当你执行swap((void **)&c, (void **)&d)时:

  • &c的实际类型是char (*)[5](指向长度为5的char数组的指针),你强行将其转为void **是类型不匹配的错误转换
  • swap函数内部的*a = tmp操作,本质是试图给数组名c赋值——但数组名是固定的常量,它的地址对应栈上的固定区域,修改这个区域会直接破坏栈结构,触发栈溢出检测(stack smashing detected),最终导致程序崩溃。

简单说:数组名不是指针变量,你不能给它赋值,自然无法通过交换指针的方式"交换数组"。

3. 正确的数组交换方案

如果你想实现类似"交换数组"的效果,有两种可行方式:

方式一:用指针变量存储数组地址,交换指针变量

把数组的首地址存入指针变量,再交换指针变量,这样和字符串指针的逻辑一致:

int main() {
    // ... 字符串交换部分不变 ...

    char c[5] = { 'a', 'e', 'i', 'o', 'u' };
    char d[3] = { '1', '2', '3' };
    // 定义指针变量存储数组首地址
    char *pc = c;
    char *pd = d;

    print_array(pc, 5);
    print_array(pd, 3);
    swap((void **)&pc, (void **)&pd);
    // 交换后pc指向d的首地址,pd指向c的首地址
    print_array(pc, 3); // 输出:1 2 3 
    print_array(pd, 5); // 输出:a e i o u 

    return 0;
}

方式二:真正交换数组的内容(而非指针)

如果需要交换两个数组的实际元素,需要编写一个基于内存拷贝的通用交换函数,传入元素大小和数组长度:

#include "stdio.h"
#include "string.h"

// 交换两个数组的内容
void swap_arrays(void *a, void *b, size_t elem_size, size_t count) {
    size_t total_size = elem_size * count;
    // 临时缓冲区存储数据
    unsigned char tmp[total_size];
    memcpy(tmp, a, total_size);
    memcpy(a, b, total_size);
    memcpy(b, tmp, total_size);
}

void print_array(char *c, int size) {
    for (int i = 0; i < size; ++i) {
        printf("%c ", c[i]);
    }
    printf("\n");
}

int main() {
    char c[5] = { 'a', 'e', 'i', 'o', 'u' };
    char d[5] = { '1', '2', '3', '4', '5' }; // 注意数组长度要一致,或取较小的长度
    print_array(c, 5);
    print_array(d, 5);
    // 交换前3个元素
    swap_arrays(c, d, sizeof(char), 3);
    print_array(c, 5); // 输出:1 2 3 o u 
    print_array(d, 5); // 输出:a e i 4 5 

    return 0;
}

关键总结

  • 字符串指针是可修改的变量,存储的是字符串的地址,交换的是地址值。
  • 数组名是编译期常量,不是变量,它仅代表数组首元素的地址,无法被赋值。
  • 强行将数组指针转为void **修改会触发未定义行为,导致栈崩溃。

内容的提问来源于stack exchange,提问作者Der Fänger im Roggen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 10:43:25