scanf(),Linux的shellinput处理方式不同,为什么?

我得到了以下。

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 
  • 为什么在这两种方式的input是不同的处理? 有什么不同?
  • 什么是正确的方式来使用scanf()能够以相同的方式处理这两种情况?

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文件末尾加一个行尾字符?

干杯。 基思。

这一行:

 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。

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

就像我尝试的那样,我无法像你一样重现同样的问题。 我甚至手动从credentials.data文件中删除行字节的结尾,它仍然正常工作(因为它应该)。 你正在运行什么版本的Linux或shell?