为什么我不需要在打印之前取消引用C中的字符指针?
为什么这段代码有效? 我希望我需要取消引用ptr
, printf("%s\n", *ptr);
在我打印之前,如果我尝试这样做,我会得到一个Segmentation Fault
。
#include int main(int argc, char *argv[]) { char name[] = "Jordan"; char *ptr = name; printf("%s\n", ptr); }
希望你们能给我一些见解。
打印字符串时我们需要字符串的起始地址。
printf("%s\n", ptr); ^ address with %s
它打印字符直到\0
nul遭遇。
而打印聊天 int ..我们需要值变量 :
printf("%c\n", *ptr); ^ * with %c print first char
在scanf()
你总是需要给出一个字符串 :
scanf("%s", ptr); ^ string address
对于int scanf()
一个char
scanf("%c", ptr); ^ read at first location char address
注意: Scanf()
需要使用%c
地址将扫描值存储在内存中。
小心你的ptr
指向一个常量字符串,所以你不能在scanf中使用 。
为什么Segmentation会出现以下代码?
printf("%s\n", *ptr);
当你这样做时,因为%s
printf将*ptr
解释为一个地址,但它实际上不是一个地址,如果你将它视为地址,它指向一个为你的程序读取保护的位置(进程)所以它会导致分段故障。
您的ptr
通过name
指向内存中的一些常量字符串(“Jordan”),如下图所示:
name 2002 ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ │ 'J' │ 'o' │ 'r' │ 'd' │ 'a' │ 'n' │'\0' │ ........ └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ ^ | ptr = name ==> ptr = 2002 *ptr = 'J'
在printf("%s\n", *ptr);
*ptr = 'J'
和*ptr = 'J'
ASCII值是74
但74
地址不在您的过程控制之下,并且您正在尝试从该内存位置读取并且发生内存冲突和分段错误。
如果编译包含printf("%s\n", *ptr);
代码printf("%s\n", *ptr);
然后用适当的选项说-Wall
和GCC
你会收到如下警告:
warning: format '%s' expects argument of type 'char *', but argument 2 has type 'int'
说%s
需要(期望)一个char*
类型的地址,但你正在投入价值
注意:
printf("%s\n", *ptr); ^ ^ argument-2 argument-1
这是因为传递给printf
的格式字符串中的%s
格式说明符意味着相应的参数应该是字符串,而不是单个字符。 在C中,字符串是指向一个字符块开头的指针,该字符块在结尾处具有空字符(值为0的字节)。
基本上,这是有效的,因为你正在做你应该打印的字符串。
格式说明符%s
告诉printf
期望指向以null结尾的char数组的指针。 这是什么name
和ptr
。
*name
和*ptr
不是。 如果你取消引用它们,你将得到一个char
,它基本上是对printf
– 导致未定义的行为。
printf的%s
格式化程序需要一个“字符串”,它实际上是一个指向以null结尾的字符数组的指针。
也就是说,printf 希望你将指针传递给它。 取消引用指针时,它取字母J,其值在ascii中为74(十进制),并尝试将其视为指向数组的指针。 这是一个无法访问的内存区域,因此您会遇到分段违规。
*ptr
本质上是对单个char
的引用,而不是对char
的字符串的引用。 由于这个char *
和char[]
基本上是一回事
当您声明char prt = name时,您将解除引用它。 “ ”这里不是变量的一部分,只是表明你想要变量所指向的方式。 如果你要将* prt再次放入printf中,那么你要做两次。 name是一个字符数组,* ptr是一个指向这些字符的解引用指针。
希望解释有帮助:-)