关于C语言中char**与char*[]声明语义变化的技术问询
C语言中
char** p与char* p[]的语义差异解析 问题1:断言二者曾语义完全相同是否错误?若自1978年起就存在差异,具体差异是什么,如何检测?
这个断言是错误的——从1978年的K&R C(最早的C标准)开始,char** p和char* p[]的语义就不完全一致,仅在函数参数声明的场景下会被等价处理,其他场景差异明显:
核心差异
char** p:是一个指向指针的指针变量,本身是可修改的左值,可以被多次赋值(比如案例2中重新赋值为defaultlist的操作合法)。char* p[]:是一个数组类型的变量,数组名在表达式中会隐式转换为指向首元素的指针,但数组变量本身是不可修改的左值——你不能给数组变量整体赋值,就像不能直接修改const指针的指向一样。
检测方法
用一段代码验证差异:
#include <stdio.h> int main() { char* arr[] = {"a", "b"}; char** ptr = arr; // 尝试修改数组变量,编译报错:expression must be a modifiable lvalue arr = ptr; // 修改指针变量,编译正常 ptr = arr; return 0; }
问题2:当前char* p[]是否在某些场景被视为char* (* const p),该变化是否源于C标准修订?
当char* p[]作为**普通变量(局部/全局)**声明时,它的行为确实和char* (* const p)非常相似——都不能被重新赋值指向其他内存地址,但二者并非完全等价:
char* p[]是数组类型,编译器会保留它的大小信息(比如用sizeof(arr)能得到数组总字节数);char* (* const p)是常量指针,sizeof(ptr)得到的是指针本身的字节数,和数组大小无关。
这个特性不是标准修订带来的变化,从K&R C时代开始,数组变量的不可修改性就是C语言的基础规则,只是你之前可能混淆了函数参数场景的特殊处理:在函数参数中,char* p[]会被编译器自动调整为char** p,这时候二者语义才完全一致。
问题3:若存在标准变化,该变化是何时发生的?
不存在这样的标准变化——char** p和char* p[]的语义差异从C语言诞生之初就存在,从未因为标准修订而改变。你之前的误解,大概率是把函数参数场景下的等价处理,错误延伸到了普通变量声明场景。
补充:案例1报错的原因
案例1中的两行错误代码:
char* list[] = getlist();:C语言中数组变量只能用初始化列表(比如{"a", "b"})初始化,不能直接用指针赋值,这本身就是非法语法;list = defaultlist;:list是数组变量,属于不可修改的左值,无法被整体赋值,因此触发expression must be a modifiable lvalue错误。
案例2中将list声明为char**指针变量,既可以用指针返回值初始化,也能被重新赋值,所以编译正常。
内容的提问来源于stack exchange,提问作者periblepsis
相关产品推荐
相关产品推荐

