为什么读入带 Scanf 的字符串缓冲区既可以使用与号(&) ,也可以不使用与号(&) ?

我有点疑惑。在我的印象中,用 scanf()读取 C 字符串的正确方法是

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

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

不过,下面的方法似乎也行得通,

scanf( "%s" , &string );

这只是我的编译器(gcc) ,纯粹的运气,或其他什么?

640787 次浏览

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

然后,scanf在处理其参数列表的尾部时,将尝试提取一个 char *。当你在 string或者 &string[0]中传递时,这是正确的事情,但是当你在 &string中传递时,你依赖于一些语言标准不能保证的东西,即指针 &string&string[0]——指向不同类型和大小的对象的指针从同一个地方开始——是以相同的方式表示的。

我相信我从来没有遇到过这样的系统,实际上你可能是安全的。尽管如此,这是错误的,在某些平台上可能会失败。(假设的例子: 一个“调试”实现,其中包含每个指针的类型信息。我 好好想想的 C 实现在符号“ Lisp 机器”上做了类似的事情。)

我认为下面的内容是准确的,可能会有所帮助。 如果你发现任何错误,请随意更正。我是 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. 在阵列 str处的 strPtr
  3. strPtr是一个变量,在内存中有自己的地址
  4. strPtr是一个变量,它存储地址 &str[0]的值
  5. strPtr自己在内存中的地址不同于它存储的内存地址(内存中的数组地址 a.k.a & str [0])
  6. &strPtr表示 strPtr 本身的地址

我认为你可以把一个指向指针的指针声明为:

char **vPtr = &strPtr;

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

或者你可以一分为二:

char **vPtr;
*vPtr = &strPtr
  1. 在 strPtr 指针上的 *vPtr
  2. *vPtr是一个变量,在内存中有自己的地址
  3. *vPtr是一个存储 address & strPtr 值的变量
  4. 最后注释: 你不能做 str++str地址是 const,但 你可以做 strPtr++