用scanf读取字符串

用scanf读取字符串,c,scanf,C,Scanf,我有点困惑。我的印象是,使用scanf()读取C字符串的正确方法是 (不要介意可能的缓冲区溢出,这只是一个简单的例子) 但是,下面的方法似乎也能奏效 scanf( "%s" , &string ); 这仅仅是我的编译器(gcc)、纯粹的运气还是别的什么?数组“衰减”为指向其第一个元素的指针,因此scanf(“%s”,string)相当于scanf(“%s”,&string[0])。另一方面,scanf(“%s”,&string)传递一个指向-char[256]的指针,但它指向相同的位置

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

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

但是,下面的方法似乎也能奏效

scanf( "%s" , &string );
这仅仅是我的编译器(gcc)、纯粹的运气还是别的什么?

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

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


我不相信我曾经遇到过一个系统,在这个系统上不工作,实际上你可能是安全的。尽管如此,这是错误的,它可能会在某些平台上失败。(假设的例子:一个“调试”实现,它包含每个指针的类型信息。我认为符号“Lisp机器”上的C实现是这样做的。)

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

char str[]  
  • char类型的值数组,在内存中有自己的地址
  • char类型的值数组,在内存中有自己的地址 与阵列中的元素一样多的连续地址
  • 包括终止空字符
    '\0'
    &str
    &str[0]
    str
    ,这三个字符都表示内存中相同的位置,即数组
    str
    的第一个元素的地址

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

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

    char *strPtr; strPtr = &str[0];
    
  • strPtr
    是指向
    char
  • strprprtr
    指向数组
    str
  • strPtr
    是一个在内存中有自己地址的变量
  • strprprtr
    是一个存储地址值的变量
    &str[0]
  • strprpr
    内存中自己的地址与它存储的内存地址不同(内存中数组的地址a.k.a&str[0])
  • &strPtr
    表示strPtr本身的地址
  • 我认为可以将指向指针的指针声明为:

    char **vPtr = &strPtr;  
    
    声明并用strprtr指针的地址初始化

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

    char **vPtr;
    *vPtr = &strPtr
    
  • *vPtr
    指向strPtr指针
  • *vPtr
    是一个在内存中有自己地址的变量
  • *vPtr
    是一个存储地址和strprtr值的变量
  • 最后的评论:你不能做
    str++
    str
    地址是一个
    const
    ,但是 您可以执行
    strPtr++

  • 在第二种情况下,实际上没有可能的缓冲区溢出,因为您根本没有使用该缓冲区。或者你可以说任何大于3个字符的字符串都会溢出你的“缓冲区”。另外,其他人已经指出了这里发生的事情。试过了,加雷斯是对的。奇怪。因为这个问题是通过搜索“如何使用scanf读取字符串”返回的,所以应该指出,这个问题是关于如何将指向缓冲区的指针传递到
    scanf
    ,问题和公认的答案都集中在这一点上,并且省略了在实际代码中应该使用的最大输入长度的重要限制(但这些限制不是这个问题的重点)。
    char **vPtr;
    *vPtr = &strPtr