C语言中使用scanf_s函数输入字符串

7
我是一个有用的助手,可以为您翻译文本。
我一直在尝试自己寻找答案,但是我找不到。 我想插入一部分编程代码,可以读取像“Hello”这样的字符串,并在需要时存储并显示它,以便printf(“%s”,blah);产生Hello
以下是使我困扰的代码部分。
char name[64];
scanf_s("%s", name);
printf("Your name is %s", name);

我知道printf不是问题所在,程序在提示后输入后会崩溃。请帮忙?

8
“secure”版的scanf需要您提供缓冲区的长度。 - user3386109
4
可以使用scanf()代替scanf_s()。或者更好的选择是使用fgets() - Crowman
1
你有同样的堆栈跟踪吗?如果有,请发布它。 - sarath
如果使用 scanf 函数,必须指定长度以避免缓冲区溢出:scanf("%63s", name); - M.M
这对我有用:http://stackoverflow.com/a/17067317/830514,我正在使用VS 2013,C程序。 - Dom045
7个回答

7

从ISO/IEC 9899:2011标准的附录K.3.5.3.2中fscanf_s()的规范可以得知:

fscanf_s函数等效于fscanf函数,但cs[转换说明符适用于一对参数(除非通过*指示抑制赋值)。这些参数中的第一个与fscanf相同。该参数紧随在参数列表中的第二个参数后面,其类型为rsize_t,并给出了由该对参数的第一个参数指向的数组中元素的数量。如果第一个参数指向标量对象,则将其视为具有一个元素的数组。

还有:

scanf_s函数等效于在scanf_s的参数之前插入stdin参数的fscanf_s函数。

MSDN表示类似的事情(scanf_s()fscanf_s())。

你的代码没有提供长度参数,因此使用其他数字。它找到的值不确定,所以代码会出现异常行为。你需要像下面这样做一些更多的东西,其中换行符有助于确保实际看到输出。

char name[64];
if (scanf_s("%s", name, sizeof(name)) == 1)
    printf("Your name is %s\n", name);

scanf_s的第三个参数不应该被强制转换为(unsigned int)吗?因为sizeof返回的是size_t类型的值。 - Spikatrix
@CoolGuy:如果你要进行强制类型转换,应该将其转换为rsize_t(请参见答案中的引用),但是K.3.3 常见定义 <stddef.h> 表示(完整内容如下): 头文件 <stddef.h> 定义了一种类型。该类型是 rsize_t 它是类型 size_t. 并引用脚注 385,其中说:请参阅 <stdint.h>RSIZE_MAX 宏的描述。RSIZE_MAX 的讨论更加广泛,但意图通常应小于 SIZE_MAX,建议大小为 SIZE_MAX >> 1 - Jonathan Leffler

5

我在大学课程中经常使用这个,所以在Visual Studio中应该可以很好地工作(已在VS2013中测试):

char name[64]; // the null-terminated string to be read
scanf_s("%63s", name, 64);
// 63 = the max number of symbols EXCLUDING '\0'
// 64 = the size of the string; you can also use _countof(name) instead of that number
// calling scanf_s() that way will read up to 63 symbols (even if you write more) from the console and it will automatically set name[63] = '\0'
// if the number of the actually read symbols is < 63 then '\0' will be stored in the next free position in the string
// Please note that unlike gets(), scanf() stops reading when it reaches ' ' (interval, spacebar key) not just newline terminator (the enter key)
// Also consider calling "fflush(stdin);" before the (eventual) next scanf()

参考:https://msdn.microsoft.com/zh-cn/library/w40768et.aspx 这是微软官方的文档,介绍了如何使用.NET Framework中的System.IO命名空间来操作文件和目录。其中包括创建、复制、移动、删除文件或目录等基本操作,以及读取和写入文件内容的方法。如果你正在进行IT技术方面的开发工作,这篇文档对你会有很大帮助。

0

scanf_s函数与scanf函数相同,只是%c%s%[转换说明符各需要两个参数(通常的指针和一个类型为rsize_t的值,表示接收数组的大小,当使用%c读取单个字符时,大小可能为1)。

您的代码没有提供接收数组的大小,而变量name是指向数组第一个字符的指针,因此它包含name[0]的地址。因此,在scanf_s中,您的第一个参数name是正确的,因为name是一个指针,还要注意的是,对于第二个参数,您不能插入指针的大小,如sizeof(name),因为它始终相同。您需要指定您的char数组的大小(name[64]),因此,对于第二个参数,您应该插入sizeof(name[64])64*sizeof(char)

您可以按以下方式更正您的代码:

char name[64];
if (scanf_s("%s", name, sizeof(name[64])) == 1)
    printf("Your name is %s\n", name);

sizeof(name[64]) should be sizeof(name) - yes

0

虽然看起来不太便携。 - undefined

-1

你应该这样做:scanf ("%63s", name);

更新:

以下代码对我有效:

#include <stdio.h> 
int main(void) { 
    char name[64]; 
    scanf ("%63s", name); 
    printf("Your name is %s", name); 
    return 0; 
}

如果您正在使用Visual Studio,

请前往项目属性 -> 配置属性 -> C/C++-> 预处理器 -> 预处理器定义,点击编辑并添加_CRT_SECURE_NO_WARNINGS,然后点击确定,应用设置并重新运行。

注意:这仅适用于做作业或类似情况,不建议在生产环境中使用。


还是不行,虽然不会崩溃了,但 printf 仍然无法显示结果。 - user3587529
我尝试了这个,它有效。#include <stdio.h>int main(void) { char name[64]; scanf ("%63s", name); printf("你的名字是 %s", name); return 0; } - M-N
我正在使用Visual Studio,它不允许我使用scanf,只能用scanf_s,但即使使用缓冲区,它也无法正常工作,在printf后面的%s跳过了。 - user3587529
你开始了一个Visual C++项目? - M-N
是的,我假设那就是问题所在...但具体是什么? - user3587529
1
进入项目属性->配置属性->C/C++->预处理器->预处理器定义,点击编辑并添加_CRT_SECURE_NO_WARNINGS,点击确定,应用设置并运行项目。 - M-N

-1
    #include<stdio.h>

    int main()
    {
      char name[64];

      printf("Enter your name: ");
      scanf("%s", name);
      printf("Your name is %s\n", name);

     return 0;
    }

2
不是这样的:scanf("%s", name);(没有'&')吗? - someone_ smiley
1
这里不需要'&',数组名本身将给出数组的地址。 - sarath
1
&name 上的 & 没有任何影响,但是也不是必需的。可以省略它,因为你理解数组和指针之间的关系。如果你理解这个关系,请先阅读相关资料,然后省略掉额外的 & - dmckee --- ex-moderator kitten
2
嗯...也许指针转换方面有误。如果这样的话,一个假想的编译器将指向数组的指针与其他指针存储方式不同,可能会表现出不同的行为。 - dmckee --- ex-moderator kitten
1
@dmckee:在问题的上下文中(char name[64];),符号&name生成一个char (*)[64]%s格式期望一个char *,而简单地引用name会产生一个char *。正如您所看到的,这两种类型是非常不同的。不幸的是,作为void *查看的&name的值与作为void *查看的name的值相同。这使得scanf("%63s", &name)可以“工作”,但并不能阻止它是不正确的事实。 - Jonathan Leffler
显示剩余6条评论

-1
#include<stdio.h>

int main()
{
  char name[64];
  printf("Enter your name: ");
  gets(name);
  printf("Your name is %s\n", name);
 return 0;
}

欢迎来到 Stack Overflow!虽然这段代码可能回答了问题,但提供有关它是如何解决问题的附加上下文,将会提高答案的长期价值。同时指出为什么这个答案比其他答案更合适也不会有坏处。 - Dev-iL
啊,是的。一个没有上下文的代码片段,也没有回答问题。太棒了。 - Aashishkebab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接