char *a[]与char **a的区别及初始化异常问题咨询
指针数组与二级指针的本质区别及初始化差异
一、两种定义的核心差异
1. char *s[] = {"hallo", "12345"}:指针数组
这是一个固定大小的数组,每个元素类型为char*:
- 编译器会根据初始化列表的元素数量自动确定数组长度(此处为2)。
- 初始化时,每个字符串字面量的首地址会被依次存入数组的对应位置。数组本身占用连续内存,存储的是两个合法指针,分别指向"hallo"和"12345"的起始地址。
- 因此
s[0][4]是合法的:s[0]取第一个指针(指向"hallo"),[4]取该字符串的第5个字符(索引从0开始)。
2. char **s = {"hallo", "12345"}:二级指针变量
这是一个单一的指针变量,仅能存储一个char*类型的地址:
- 用包含两个元素的初始化列表赋值属于错误:第一个字符串的地址会被存入
s,但第二个元素没有对应的存储位置,编译器会直接抛出「near initialization for ‘s’」的警告。 - 即便忽略警告,
s此时指向的是"hallo"的首地址(而非指针数组的首地址)。访问s[1]时,会将s的地址偏移sizeof(char*),把该位置的内存(实际是"hallo"字符串的内容,比如'a')当作指针来解引用,这属于非法内存访问,必然触发段错误。
二、为什么main函数中char *argv[]与char **argv等价?
这是C语言的函数参数特殊规则:当数组类型作为函数参数时,会被编译器自动转换为指向数组元素类型的指针。因此char *argv[]作为main的参数时,会被隐式转换为char** argv,两者语义完全一致。
但注意:这个转换仅适用于函数参数上下文,普通变量定义时,数组就是数组,指针就是指针,不存在自动转换。
三、用二级指针访问多个字符串的正确方式
如果要通过二级指针访问多个字符串,需要先创建指针数组,再将数组的地址赋值给二级指针:
char *arr[] = {"hallo", "12345"}; char **s = arr; // arr作为数组名,会转换为指向第一个元素的指针(char**类型) printf("%c und %c", s[0][4], s[1][2]); // 正常输出o 和 3
内容的提问来源于stack exchange,提问作者phl92
相关产品推荐
相关产品推荐

