为什么这段代码有效?我希望在打印之前我需要取消引用ptr
,printf("%s\n", *ptr);
,但如果我尝试这样做,我会得到Segmentation Fault
。
#include <stdio.h>
int main(int argc, char *argv[])
{
char name[] = "Jordan";
char *ptr = name;
printf("%s\n", ptr);
}
希望你们能给我一些见解。
答案 0 :(得分:21)
当您打印字符串时,我们需要字符串的起始地址。
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()
字符
scanf("%c", ptr);
^ read at first location char address
注意: Scanf()
需要使用%c
的地址将扫描值存储在内存中。
小心您的ptr
指向一个常量字符串,因此您无法在scanf中使用。
为什么细分错误以下代码?
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'
和char'J'的ASCII值为74
,但74
地址不在您的过程控制之下,而您正试图从中读取内存位置及其发生内存冲突和分段错误。
如果您为包含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
答案 1 :(得分:5)
这是因为传递给%s
的格式字符串中的printf
格式说明符意味着相应的参数应该是字符串,而不是单个字符。在C中,字符串是指向一个字符块开头的指针,该字符块在结尾处具有空字符(字节值为0)。
基本上,这是有效的,因为你正在按照你想要的那样打印字符串。
答案 2 :(得分:1)
格式说明符%s
告诉printf
期望指向以null结尾的char数组的指针。这是name
和ptr
的内容。
*name
和*ptr
不是。如果您取消引用它们,则会返回一个char
,它基本上位于printf
- 导致未定义的行为。
答案 3 :(得分:1)
printf的%s
格式化程序需要一个“字符串”,它实际上是指向以空字符结尾的字符数组的指针。
也就是说,printf 希望你将指针传递给它。当你取消引用指针时,它取字母J,其在ascii中的值是74(十进制),并尝试将其视为指向数组的指针。这是一个无法访问的内存区域,因此您会受到分段违规。
答案 4 :(得分:0)
*ptr
基本上是对单个char
的引用,而不是char
的字符串。由于此char *
和char[]
基本相同
答案 5 :(得分:0)
当您声明char prt = name时,您将解除引用它。这里的“”不是变量的一部分,只是表明你想要变量指向的方式。如果你要将* prt再次放入printf中,那么你要做两次。 name是一个字符数组,* ptr是一个指向这些字符的解引用指针。
希望解释有助于: - )