用scanf读取字符串


147

我对某些事情感到困惑。我的印象是,使用读取C字符串的正确方法scanf()遵循

(不要介意可能的缓冲区溢出,这只是一个简单的示例)

char string[256];
scanf( "%s" , string );

但是,以下似乎也可以工作,

scanf( "%s" , &string );

这仅仅是我的编译器(gcc),纯粹的运气还是其他?


在第二种情况下,实际上根本没有可能的缓冲区溢出,因为您根本没有使用该缓冲区。要么,要么您可以说任何大于3个字符的字符串都将溢出您的“缓冲区”。
TED

我指的是第一个例子。另外,其他人已经指出了这里发生的事情。
阿贝尔

对。尝试了一下,加雷斯(Gareth)是对的。奇怪的。
TED

由于此问题是通过搜索“如何使用scanf读取字符串”返回的,因此可能应该指出,该问题是关于将指针传递到的缓冲区的scanf,并且问题和接受的答案都集中在,并省略了在实际代码中应使用的对最大输入长度的至关重要的限制(但此问题不重要)。
Arkku '18年

Answers:


141

数组“衰减”到指向其第一个元素的指针中,因此scanf("%s", string)等效于scanf("%s", &string[0])。另一方面,scanf("%s", &string)传递指向的指针char[256],但它指向同一位置。

然后scanf,在处理其参数列表的尾部时,将尝试拉出一个char *。当您传入string或时&string[0],这是正确的选择,但是传入时,&string您所依赖的是语言标准所不能保证的,即,指向不同类型和大小的对象的指针&string&string[0]-指针从相同的地方开始-用相同的方式表示。

我不相信我曾遇到过无法正常运行的系统,实际上您可能很安全。但是,这是错误的,并且在某些平台上可能会失败。(一个假想的示例:一个“调试”实现,其中包含每个指针的类型信息。我认为 Symbolics“ Lisp Machines”上的C实现做了类似的事情。)


5
+1。验证数组衰减导致的&string工作方式相同string(而不是导致随机存储器损坏,因为其他答案未正确断言)也很简单:printf("%x\n%x\n", string, &string);
Josh Kelley

@Josh Kelley有趣,我会认为通过malloc()分配的字符串的指针不是这种情况吗?
阿贝尔

4
@abeln:正确。对于通过malloc()分配的字符串,它string是一个指针,并且&string是该指针的地址,因此两者不可互换。作为加雷思介绍,即使阵列衰减的情况下,string并且&string在技术上是不一样的类型(即使它们恰巧是最架构互换),如果你打开GCC会给你的第二个例子警告-Wall
Josh Kelley

@Josh Kelley:谢谢,我很高兴我能就此澄清我的想法。
abeln 2011年

1
@JCooper str和&str [0]都表示相同的东西(数组的开头),尽管不一定(&str)也是相同的内存地址。现在,strPtr指向str,因此strPtr内部存储的内存地址与str相同,也就是12fe60。最后,&strPtr是变量strPtr的地址,这不是存储在strptr中的值,而是strPtr的实际内存地址。由于strptr是一个与所有其他变量不同的变量,因此它也具有不同的内存地址,在本例中为12fe54
Juan Besa

-9

我认为以下内容是正确的,可能会有所帮助。如果发现任何错误,请随时进行纠正。我是C新手。

char str[]  
  1. char类型的值的数组,在内存中有自己的地址
  2. char类型值的数组,其在内存中的自身地址与数组中的元素一样多的连续地址
  3. 包括终止空字符'\0' &str&str[0]并且str,所有三个代表存储器中的相同位置这是所述阵列的所述第一元件的地址str

    char * strPtr =&str [0]; //声明和初始化

或者,您可以将其分为两部分:

char *strPtr; strPtr = &str[0];
  1. strPtr 是指向 char
  2. strPtr 指向数组 str
  3. strPtr 是一个在内存中有自己地址的变量
  4. strPtr 是存储地址值的变量 &str[0]
  5. strPtr 内存中自己的地址与其存储的内存地址不同(数组在内存中的地址又称为&str [0])
  6. &strPtr 代表strPtr本身的地址

我认为您可以将指针声明为:

char **vPtr = &strPtr;  

使用strPtr指针的地址声明和初始化

或者,您可以分成两部分:

char **vPtr;
*vPtr = &strPtr
  1. *vPtr 指向strPtr指针
  2. *vPtr 是一个在内存中有自己地址的变量
  3. *vPtr 是存储地址&strPtr的值的变量
  4. 最后评论:您不能做str++str地址是const,但是您可以做strPtr++
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.