【问题标题】:C program stops working with scanf_sC 程序停止使用 scanf_s
【发布时间】:2015-05-03 17:05:23
【问题描述】:

我在编程方面还很陌生,但我在处理一段代码时遇到了麻烦。我正在尝试输入一个单词,但是当我运行程序并输入该单词时它停止工作。

这是代码:

    int main(void){
    char a[]= ""; 

    printf("Enter word:\n");
    scanf_s("%s", a);

    return 0;
}

我尝试将 a[] 的大小设置为 20,并按照另一个问题的建议使用 %19s,但这也不起作用。

编辑 1. 将char a[]= ""; 更改为char a[20]= {0};,但它不起作用。

编辑 2. 添加 sizeof(a) 并且代码有效。此外,我删除了 {0},但我不知道这是否有所作为。

最终代码:

int main(void){

    char a[20]; 

    printf("Enter word:\n");
    scanf_s("%19s", a, sizeof(a));

    return 0;

}

【问题讨论】:

  • 你已经声明了 empty 数组.... char a[50] = {0}; 也许?
  • 无论如何,在它目前的结构中,它显然不会工作。显示大小为20的变体
  • 什么是scanf_s?你的意思是scanf 对吗?
  • M$ 中有一个scanf_s 变体

标签: c tr24731


【解决方案1】:

诊断

代码中有(至少)两个问题:

  1. 您没有提供任何有用的空间来存储字符串。 (定义的原始问题:char a[] = "";,请注意,它是一个长度为 1 的数组,尽管它只能保存一个长度为 0 的字符串。)

  2. 你还没有告诉scanf_s() 字符串有多大。它需要一个字符串指针后的长度参数。

Microsoft 对scanf_s() 的定义指定:

scanfwscanf 不同,scanf_swscanf_s 需要为cCsS 或字符串类型的所有输入参数指定缓冲区大小包含在[] 中的控制集。以字符为单位的缓冲区大小作为附加参数传递,紧跟在指向缓冲区或变量的指针之后。例如,如果您正在读取一个字符串,则该字符串的缓冲区大小按如下方式传递:

char s[10];
scanf_s("%9s", s, _countof(s)); // buffer size is 10, width specification is 9 

缓冲区大小包括终止的空值。您可以使用宽度规范字段来确保读入的令牌适合缓冲区。如果没有使用宽度规范字段,并且读入的令牌太大而无法放入缓冲区,则不会向该缓冲区写入任何内容。

注意

size 参数的类型是unsigned,而不是size_t

_countof() 运算符是 Microsoft 扩展。它大约相当于sizeof(s) / sizeof(s[0]),在这种情况下,它与sizeof(s) 相同,因为根据定义sizeof(char) == 1

请注意,size 参数是 unsigned,而不是您所期望的 size_t。这是 TR 24731-1 函数的 Microsoft 实现与 ISO/IEC 9899:2011 的 Annex K 之间的差异领域之一。标准中指定的大小在技术上是 rsize_t,但它被定义为具有限制范围的 size_t(因此是 r):

类型为rsize_t,即size_t

但脚注(未显示)指的是RSIZE_MAX的定义。

另见Do you use the TR 24731 'safe' functions?

修复问题中的代码

Microsoft 引用中的示例主要展示了如何修复您的代码。你需要:

int main(void)
{
    char a[4096];
    
    printf("Enter word:\n");
    if (scanf_s("%s", a, (unsigned)sizeof(a)) != 1)  // Note cast!
        fprintf(stderr, "scanf_s() failed\n");
    else
        printf("scanf_s() read: <<%s>>\n", a);
    
    return 0;
}

请注意,我检查了scanf_s() 的结果,而不是仅仅假设它有效,并在标准错误上报告了错误。

【讨论】:

  • 大多数情况下 1+,但是请允许我这个问题:你这样做是为了冥想练习吗... ;-)
  • 谢谢。我尝试了这个例子,程序运行了。虽然,我需要研究它,因为我不明白其中的大部分内容。
  • 大部分和你的一样。对scanf_s() 的调用中还有一个额外的参数——这是您代码的关键修复。 *scanf*() 函数返回成功转换的次数,或错误时的 EOF。在这种情况下,这有点迂腐,但最好检查每个输入操作是否成功。如果您没有遇到过fprintf()stderr,那么您可以将fprintf(stderr, …) 视为“用于编写错误消息的printf() 的变体”。 fprintf() 可用于写入任何打开的文件流,也可以通过其他方式写入stderr
  • @alk:我这样做更多是为了避免做我应该做的所有其他事情。
  • @JonathanLeffler: :-)) ... - 所以这个答案肯定证明你是人类!干杯... ;-)
【解决方案2】:

使用

char a[]="";

创建一个足够容纳单个字节的数组。您必须分配足够的空间,例如像这样:

char a[20] = {0}; // Can hold a string length 19 + \0 termination

使用你的方法,你会得到一个溢出,因为scanf_s 将在内存中写入比你分配的更多,从而导致分段错误。

【讨论】:

  • 我只是想给他指出正确的方向。大小为 20 时,它应该适用于长度为 19 的字符串。
  • 数组长1个字节(它包含一个'\0'); C 中没有大小为零的对象。
  • 我已经修正了断言char a[] = ""; 定义一个零大小数组的原始想法。它没有;它指定了一个大小为 1 的数组。C 中没有大小为零的对象。但这并不能解决整个问题。 scanf_s() 函数需要目标字符数组的长度作为该函数的显式额外参数,该参数紧跟在指针参数之后。
猜你喜欢
  • 1970-01-01
  • 2012-08-14
  • 2014-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多