scanf(),Linux shell输入处理方式不同,为什么?

时间:2011-10-25 05:08:56

标签: c linux shell scanf

我得到了以下内容。

my-app.c档案:

char username[USERNAME_MAX_LEN] = "\0";
char password[PASSWORD_MAX_LEN] = "\0";
scanf("%s %s", username, password);
printf("username-len: %ld, password-len: %ld\n", strlen(username), strlen(password));

credentials.data档案:

jdons f4$dsef35fs

所以:

$ ./my-app < credentials.data
username-len: 0, password-len: 0

$ cat credentials.data | ./my-app
username-len: 5, password-len: 10
  • 为什么输入处理的方式不同?有什么不同呢?
  • 使用scanf()以同样的方式处理这两种情况的正确方法是什么?

4 个答案:

答案 0 :(得分:3)

这一行:

scanf("%s %s", username, password);

本质上是不安全的(除非您完全控制程序标准输入中显示的内容)。 "%s"格式表示读取任意长的非空白字符序列。无论目标数组多长,一个足够长的单词(比如由你的猫坐在键盘上引起)都会溢出它。

您可以使用长度修改器来限制输入的大小。例如(未经测试):

scanf("%36s %36s", username, password);

或者,更好:

scanf("%*s, %*s", USERNAME_MAX_LEN, username, PASSWORD_MAX_LEN, password);

但最好一次使用fgets()来读取整行,然后使用sscanf()来处理读取后的行。

您的printf电话可能存在问题:

printf("username-len: %ld, password-len: %ld\n",
       strlen(username),
       strlen(password));

strlen()会返回size_t类型的结果,但"%ld"需要类型为long int的参数。如果您的系统支持它,您可以使用"%zu"打印size_t类型的值,但这不是100%可移植的。或者,您可以将size_t值转换为unsigned long:

printf("username-len: %lu, password-len: %lu\n",
       (unsigned long)strlen(username),
       (unsigned long)strlen(password));

可能(但不太可能)可能导致非零size_t值显示为0.

答案 1 :(得分:2)

Barankin,

嗯......这是一个有趣的行为。

标准输入间接技术对我来说都是有用的(如预期的那样)......

landkrc@lasun175:/home/user/landkrc/crap
$ cat lg.c
#include <stdio.h>
#include <strings.h>

#define USERNAME_MAX_LEN 36
#define PASSWORD_MAX_LEN 36

int main(int argc, char *argv[])
{
        printf("Hello, world\n");
        char username[USERNAME_MAX_LEN]; 
        char password[PASSWORD_MAX_LEN]; 
        *username = 0;
        *password = 0;
        scanf("%s %s", username, password); 
        printf("username-len: %ld, password-len: %ld\n", strlen(username), strlen(password)); 
        return 0;
}

landkrc@lasun175:/home/user/landkrc/crap
$ cc -V       
cc: Sun C 5.8 2005/10/13
usage: cc [ options] files.  Use 'cc -flags' for details

landkrc@lasun175:/home/user/landkrc/crap
$ cc -o lg lg.c

landkrc@lasun175:/home/user/landkrc/crap
$ echo '12345678 1234567890
> ' >data.txt

landkrc@lasun175:/home/user/landkrc/crap
$ lg <data.txt
username-len: 8, password-len: 10

landkrc@lasun175:/home/user/landkrc/crap
$ cat data.txt | lg
username-len: 8, password-len: 10

也许您只需要在credentials.data文件的末尾添加行尾字符?

干杯。基思。

答案 2 :(得分:0)

检查您的credentials.data末尾是否包含换行符? cat命令会自动将它附加到文件的最后一行之后。

答案 3 :(得分:0)

尽我所能,我无法像你一样重现同样的问题。我甚至手动从credentials.data文件中删除了行结束字节,它仍然可以正常工作(应该如此)。你在运行什么版本的Linux或shell?