请看一下代码片段:我不明白为什么代码会给出分段错误和垃圾字符。
#include <stdio.h>
int main()
{
char *str[1];
str[0] = "apple";
char **ptr = str;
char *p = str;
printf("%d\n", ptr); //---> 1956347328
printf("%d\n", p); //---> 1956347328
printf("%s \n", *ptr, ); // ---> prints apple
printf("%s\n", *p); // ---> error segmentation fault
printf("%s\n", p); // ---> Garbage characters
}
字符串
4条答案
按热度按时间bvn4nwqk1#
char *p=str;
是一个不兼容的指针类型初始化,因为str
是一个char *[1]
。也许你指的是char *p = *str
?printf("%d\n",ptr)
不是打印指针的方式。在我的系统中,int
(对于%d
)是4字节,指针是8字节。相反,你应该打印printf("%p\n", (void *) ptr)
。printf("%s \n",*ptr,);
是由于缺少参数而导致的语法错误。我想这就是你想要的:
字符串
输出为:
型
sg24os4d2#
下面是发布的代码行为和问题的详细说明:
char *str[1];
定义了一个指向char
的指针数组,其中包含一个元素。str[0] = "apple";
可能会触发警告,因为您将指向字符串文字的指针存储到数组的元素中,该元素包含指向可修改数据的指针。只要您不使用此指针来实际尝试和修改字符串,您就是安全的。char **ptr = str;
定义了另一个对象,一个指向char
的指针,初始化后指向数组str
。这没有问题,但是你只能访问ptr[0]
上的元素。char *p = str;
定义了另一个对象,一个指向char
的指针被初始化为指向数组str
。这是一个类型不匹配,因为str
的类型既不是 *array ofchar
* 也不是 *pointer tochar
*,因此编译器应该发出警告。然而,只要你只使用这个指针来访问组成这个数组的字节,这个数组包含一个指针(指向"apple"
字符串),在64位机器上它由8个字节组成。printf("%d\n", ptr)
具有未定义的行为,因为printf
期望%d
的int
类型的参数,并且您传递了char **
值。在您的体系结构中,整数和指针似乎在同一个寄存器或堆栈区域中传递,因此printf
输出的整数是一部分(低32位)的指针,1956347328
。你应该改为使用printf("%p\n", (void *)ptr);
printf("%d\n", p)
如上所述,输出是相同的,因为两个指针指向相同的地址,但由于它们具有不同的类型,解引用它们会产生不同的东西。printf("%s \n", *ptr, )
是一个语法错误,但没有额外的,
printf
接收*ptr
,这是数组str
的第一个元素,即:char *
指向字符串"apple"
,这是它对%s
的期望。printf
输出字符串apple
,一个空格和一个换行符。printf("%s\n", *p)
:printf
接收*p
,它是str
数组开头的char
。这个字节是指向字符串的指针的第一个字节,它有256个可能的值之一,在CHAR_MIN
到CHAR_MAX
范围内(0..255或-128..127取决于char
类型的符号).printf
需要一个指向char
的指针作为%s
转换的参数。传递char
值具有未定义的行为,并且在您的情况下,printf
使用的值是一个无效的指针:解引用它会导致分段错误。printf("%s\n", p)
:指针p
被传递到printf
进行%s
转换,这很好,但是printf
读取并输出它所指向的字节,直到它读取空字节。这些字节不是字符串apple
的字节,它们是组成存储在str[0]
中的指针的字节,如果printf
在读取空字节时没有找到空字节,那么当阅读超过数组末尾时,它将调用未定义的行为,并可能导致分段错误。考虑这个修改版本:
字符串
我在我的MacBook上得到这个输出:
型
如果我再次运行相同的可执行文件,我会得到不同的输出,因为地址空间随机化,一种用于使黑客更难利用软件漏洞的技术。
输出显示:
p
、ptr
和str
具有8字节的大小。main
参数下面)。p
和ptr
指向str
占用的区域:地址0x3085b8280
以小端顺序存储,即:从最低有效字节到最高有效字节。这看起来像 * 逆序 *,但存储指针字节的顺序(或整数)只是一个约定的问题,就像短语中词性的顺序从一种语言到另一种语言不同一样。61 70 70 6c 65 00
的串"apple"
位于地址0x1023dff58
(恒定数据段)。*p
的值为6b
,它是一个k
,但是,在我的笔记本电脑上,这个值会随着运行的不同而变化,正如上面所解释的。zazmityj3#
在表达式中使用的数组(很少有例外)被隐式转换为指向其第一个元素的指针。
所以数组
str
声明为字符串
在这些声明中用作初始化器
型
被隐式转换为
char **
类型的指针。对于第二个声明,编译器应该发出一条消息,指出使用了不兼容的指针类型:
char *
和char **
。printf
的这些调用型
是无效的,因为使用了不正确的转换说明符
d
,该转换说明符被设计为输出int
类型的对象和指针类型的对象。相反,你应该写型
然而,从输出中可以看出,这两个指针都包含数组
str
的第一个元素的地址。因此,解引用char **
类型的指针,您将获得char *
类型的数组str
的第一个元素,因此可以输出该元素所指向的字符串:型
在这个printf的调用中
型
表达式
*p
的类型为char
。结果,上面显示的地址中只有一个字节被读取,然后被提升为类型int
,并被用作有效地址。结果,发生分段错误。在这个printf的调用中
型
而不是像在这个调用中那样使用数组
str
的第一个元素(指针)的值型
使用第一元素的地址,并且第一元素的存储指针值作为字符串输出。
相反,你可以写例如
型
发出类似于
型
正确输出数组
str
的第一个元素所指向的字符串。ao218c7q4#
你将一个指针赋值给一个字符串数组(str[0] =“apple”;)。然而str被声明为一个指向字符的指针数组。如果你想把它用作一个字符数组,你应该使用char str[] =“apple”;。
char p = str;正在尝试分配一个char*。我想下面的代码会对你有所帮助。
字符串
产出:
型