如果char* 数组至少定义了一个值,则第一个值可以通过“arr[0]”索引,并使用格式说明符“%s”成功打印。但是,如果定义了char**,则在尝试使用printf或类似函数(使用字符串格式说明符)打印第一个元素时,将出现segfault。
下面是演示其工作原理的代码块:
char* s = "test";
char** sa = { s };
char* arr[] = { s };
// Prints pointers of each variable
puts("\nTest 1:");
puts("----------------------------------------");
printf("s:\t%p\n", s);
printf("sa:\t%p\n\n", sa);
// Dereferences pointers, prints as pointers (even though *s is a char)
puts("Test 2:");
puts("----------------------------------------");
printf("s:\t%p\n", *s);
printf("sa:\t%p\n\n", *sa);
// Prints strings of each variable
puts("Test 3:");
puts("----------------------------------------");
printf("s:\t%s\n", s);
printf("sa:\t%s\n\n", sa);
// Prints first element of array (works unlike *(char**), which I would think are the same)
puts("Test 4:");
puts("----------------------------------------");
printf("arr:\t%s\n", arr[0]);
printf("arr:\t%s\n\n", *arr);
// Prints strings of dereferenced pointers (segfault for sa)
puts("Test 5:");
puts("----------------------------------------");
printf("s:\t%s\n", *s);
printf("sa:\t%s\n\n", *sa);
以下是潜在输出:
Test 1:
----------------------------------------
s: 0x10013bf2c
sa: 0x10013bf2c
Test 2:
----------------------------------------
s: 0x74
sa: 0x65540a0074736574
Test 3:
----------------------------------------
s: test
sa: test
Test 4:
----------------------------------------
arr: test
arr: test
Test 5:
----------------------------------------
zsh: segmentation fault ./test2
我知道解引用变量 s 返回第一个字符的ASCII值,在本例中是“t”。但是,我不明白为什么变量 sa 不解引用数组中的第一个字符串?解引用双精度指针不应该返回指向 s 的指针吗?
我尝试过从指针 sa 返回字符串,但它只返回segfaults,这意味着Test 2下的 sa 指针没有意义,也与绑定到 s 的字符串没有关联。
2条答案
按热度按时间j8yoct9x1#
对于初学者来说,您没有数组。在此声明中
你声明了一个
char **
类型的指针,它由char *
类型的变量s
的值初始化。编译器应该发出一条消息,说明这两种指针类型之间没有隐式转换。
这两个输出之间的差值
在第一种情况下,表达式
*s
的类型char
被提升为类型int
,也就是说,只有字符串字面量的第一个字节被读取为值。在第二种情况下,表达式
*sa
被认为是指针类型char *
的表达式,因此函数读取表达式所占用的内存,作为存储大小为4
或8
字节的指针的内存,这取决于所使用的系统,而没有第一种情况下的任何提升。至于你对我的回答的评论
此外,当试图使用格式说明符“%s”将sa的char* 版本(当sa被解除引用时)打印为字符串时,会发生segfault。
当指针
sa
被解引用时,它的值是由存储在字符串常量中的字符组成的值,并且当使用转换说明符%s
时,该值被解释为指针。查看问题中显示的代码的输出
输出值
74736574
的这一部分表示以相反顺序"tset"
写入的字“test”。你可以写信代替
然后
在这种情况下,指针
sa
将包含声明的指针s
的地址,表达式*sa
产生存储在指针s
中的值,该值是字符串文字量"test"
的第一个字符的地址。mklgxw1f2#
问题是
char **
和char *
类型不兼容--正如您可以清楚地看到的那样,为了检索原始的char
对象,需要应用更多的间接寻址。在C中,你可以使用初始化语法(
{
和}
)来赋值给非数组类型,所以char** sa = { s };
等价于=
的简单赋值。然后你通过执行
sa
来访问s
指针,然后sa
被*sa
间接定向,这里我们有潜在的UB,因为*sa
产生了一个对象,不能保证它有有效的位置。这是因为(例如在32位架构中)
*sa
阅读s
字符串的4个字节,并将它们解释为地址(取决于字节序)。两者的区别:
在第一种情况下
{
和}
是多余的,并不意味着什么,而在第二种情况下,它们指的是我们正在初始化数组的嵌套元素(即char *
与s
,也是char *
)。这将创建(对于第二种情况)一个具有单个元素的数组。数组和指针是有区别的。