该的printf函数写一个格式化字符串到标准输出.格式化字符串是将占位符替换为其值的结果.这听起来有点复杂,但通过一个例子会变得非常清楚:
printf("Hello, my name is %s and I am %d years old.", "Andreas", 22);
Run Code Online (Sandbox Code Playgroud)
这里%s和%d是占位符,用第一个和第二个参数替换.您应该在手册页(上面链接)上阅读占位符列表及其选项,但最常遇到的是%d(数字)和%s(字符串).
确保占位符参数与其类型匹配非常重要.例如,以下代码将导致未定义的行为(意味着任何事情都可能发生:程序可能崩溃,它可能会工作,它可能会损坏数据等):
printf("Hello, I'm %s years old.", 22);
Run Code Online (Sandbox Code Playgroud)
不幸的是,在C中没有办法避免这些相对常见的错误.
所述获取功能被用于完全不同的目的的:它读取来自标准输入的字符串.
例如:
char name[512];
printf("What's your name? ");
gets(name);
Run Code Online (Sandbox Code Playgroud)
这个简单的程序会询问用户名称并保存他或她输入的内容name.
但是,永远不应该使用gets().它将打开您的应用程序及其运行的系统以防止安全漏洞.
引用手册页:
永远不要使用gets().因为在不事先知道数据的情况下无法判断get()将读取多少个字符,并且因为gets()将继续存储超出缓冲区末尾的字符,所以使用它是非常危险的.它已被用来打破计算机安全.请改用fgets().
以一种更简单的方式解释问题是,如果你给出的变量得到(name在这种情况下)不足以容纳用户输入的内容,那么缓冲区将发生溢出,也就是说,gets将写入变量的末尾.这是未定义的行为,在某些系统上,它将允许攻击者执行任意代码.
由于变量必须具有有限的静态大小,并且您无法设置用户可以键入的字符数量限制作为输入,gets()因此永远不会安全且永远不应使用.它仅出于历史原因而存在.
如手册所示,您应该使用fgets代替.它具有相同的目的,gets但有一个size参数指定变量的大小:
char *fgets(char *s, int size, FILE *stream);
Run Code Online (Sandbox Code Playgroud)
所以,上面的程序将成为:
char name[512];
printf("What's your name? ");
fgets(name, sizeof(name) /* 512 */, stdin /* The standard input */);
Run Code Online (Sandbox Code Playgroud)