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

发布于 2024-12-11 21:05:24 字数 683 浏览 0 评论 0原文

我得到以下内容。

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() 能够以相同的方式处理这两种情况的正确方法是什么?

I got the following.

my-app.c file:

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 file:

jdons f4$dsef35fs

So:

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

and:

$ cat credentials.data | ./my-app
username-len: 5, password-len: 10
  • Why in the both ways the input is handled differently? What is the difference to be so?
  • What is the right way to use scanf() to be able to handle both cases in the same way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

病女 2024-12-18 21:05:25

此行:

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"< /code> 需要一个 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 。

This line:

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

is inherently unsafe (unless you have complete control over what will appear on your program's standard input). The "%s" format says to read an arbitrarily long sequence of non-whitespace characters. However long the target array is, a sufficiently long word (say, caused by your cat sitting on the keyboard) will overflow it.

You can use a length modifier to limit the size of the input. For example (untested):

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

or, better:

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

But it's probably better to use fgets() to read an entire line at a time, and then use, say, sscanf() to process the line after you've read it.

And there's a possible problem in your printf call:

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

strlen() returns a result of type size_t, but "%ld" requires an argument of type long int. If your system supports it, you can use "%zu" to print a value of type size_t, but that's not 100% portable. Or you can convert the size_t value to, say, unsigned long:

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

It's possible, but not very likely, that that could cause non-zero size_t values to be displayed as 0.

带刺的爱情 2024-12-18 21:05:25

巴兰金,

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

两种标准输入间接技术都对我有效(如预期)...

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

干杯。基思.

Barankin,

Hmmm... that's an interesting behavior.

Both standard input indirection techniques work (as expected) for me...

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

Maybe you just need an end-of-line-character on the end of your credentials.data file?

Cheers. Keith.

酷炫老祖宗 2024-12-18 21:05:25

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

Check if your credentials.data contains a a newline character at the end? cat command appends it after the last line of file automatically.

最偏执的依靠 2024-12-18 21:05:25

尽管我尽力了,但我无法重现与您相同的问题。我什至手动从credentials.data文件中删除了行尾字节,它仍然可以正常工作(正如它应该的那样)。您正在运行什么版本的 Linux 或 shell?

As much as I try, I can't manage to reproduce the same problem as you. I even manually removed the end of line byte from the credentials.data file and it still works fine (as it should). What version of Linux or the shell are you running?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文