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

为何char**与char*[]的解引用行为存在差异?

为什么char**初始化后解引用会触发段错误?

核心问题出在**char** sa = { s };的初始化方式完全错误**,和char* arr[] = { s }的内存结构天差地别,下面逐一拆解:

1. 两种定义的本质区别

  • char* arr[] = { s }:这是定义了一个char*类型的数组,数组第一个元素被赋值为s(即字符串"test"的指针)。数组在内存中是连续空间,arr作为数组名,会隐式转换为指向数组首元素的指针(类型为char**)。所以*arr或arr[0]都能正确取到s,用%s打印自然能输出字符串。
  • char** sa = { s }:这是试图用初始化列表给单个指针变量赋值。C标准中,指针只能用单个表达式(或NULL)初始化,这里的大括号毫无意义,编译器会直接把s的值(字符串"test"的地址)赋值给sa本身,而不是让sa指向一个存放s的内存位置。也就是说,sa现在不是指向char*的指针,而是直接变成了字符串的指针。

2. 逐个分析测试用例的异常原因

Test 1

sa的值被设置为s的值(字符串"test"的地址),所以打印sa的地址和s完全一致,这是错误初始化带来的结果。

Test 2

*sa是解引用sa指向的地址——也就是字符串"test"的首地址,这里的内容是字符t(ASCII值0x74)。因为用%p打印,64位系统会从该地址读取8字节数据当作指针值,而字符串的字节序列是0x74 0x65 0x73 0x74 0x00 ...,小端字节序下会被拼接成0x65540a0074736574,这显然不是一个有效的内存地址。

Test 3

printf("sa:\t%s\n", sa);能输出test纯属巧合:因为sa的值刚好是字符串的首地址,%s会从该地址开始打印字符,直到遇到\0。但这完全不是char**的正确用法。

Test 5

printf("sa:\t%s\n\n", *sa);会触发段错误:*sa是前面提到的无效指针值,用%s去解引用这个不属于进程的内存地址,操作系统直接抛出段错误终止程序。

3. 正确的char**用法

如果要让char**指向一个char*变量,需要先有一个存放char*的内存空间,比如:

char* s = "test";
// 方式1:指向栈上的char*变量
char* temp = s;
char** sa = &temp;
// 方式2:用动态内存分配
char** sa = malloc(sizeof(char*));
*sa = s;

或者直接让char**指向char*数组的首元素:

char* arr[] = { s };
char** sa = arr;

此时*sa就能正确拿到s,用%s打印也不会有问题。

内容的提问来源于stack exchange,提问作者Ryan Pereira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 16:15:42