fgets函数在C语言中的应用
我的一项任务是编写自己的unixshell。为了接收用户的输入,我使用fgets将输入捕获为字符串,但我不确定它是如何工作的。当我跑步时:fgets函数在C语言中的应用,c,shell,unix,fgets,strlen,C,Shell,Unix,Fgets,Strlen,我的一项任务是编写自己的unixshell。为了接收用户的输入,我使用fgets将输入捕获为字符串,但我不确定它是如何工作的。当我跑步时: char command[50]; fgets(command, sizeof(command), stdin); printf("Your Command: %s", &command); int length = strlen(command); printf("Length of String: %d\n", length); 假设我的输入
char command[50];
fgets(command, sizeof(command), stdin);
printf("Your Command: %s", &command);
int length = strlen(command);
printf("Length of String: %d\n", length);
假设我的输入是“退出”。斯特伦说字符串是5个字符,而不是4个字符。我想这样做:
if( (strcmp(command, "exit")) == 0 ){
doSomething();
}
但命令永远不会等于我想要的字符串;它好像有一个我不确定的未知特征。是结尾的空字符吗?如何更改if语句以检查fgets捕获的用户输入是否等于“exit”?谢谢
fgets
将行终止符视为有效字符。这是你收到的额外字符
只需执行类似于
command[strlen(command)-1]='\0'代码>以删除行终止符。然后您可以自由地执行所有的strcmp。fgets
也可以捕获换行符
请注意,您可以通过几种方法克服此问题,其中一种方法可能是使用strncmp
:
if((strncmp(command, "exit", 4)) == 0)
它将检查命令的前4个字符是否匹配(尽管这可能不是适合您的选项)
另一种策略是检查断线是否到位:
if((strcmp(command, "exit\n")) == 0)
字符串的末尾仍然有换行符。您可以与“exit\n”
进行比较,或者使用类似strncmp(命令,“exit”,4)
。请注意,这将接受以“退出”开头的任何内容,并忽略其余内容。从手册页面:
fgets()从流和存储中最多读取一个小于大小的字符
将它们放入s指向的缓冲区。EOF或换行符后,读取停止。
如果新行被读取,它将被存储到缓冲区中。“\0”存储在
缓冲区中的最后一个字符
底线:进行比较时,字符串末尾有一个额外的换行符。fgets
将始终在输入字符串中包含行终止字符。通过执行以下操作,可以从“命令”末尾删除任何空格,包括换行符:
char command[50];
fgets(command, sizeof(command), stdin);
size_t length = strlen(command);
// Trim off trailing "spaces" including newline characters
while ((length > 0) && isspace(command[length-1]))
command[--length] = '\0';
printf("Your Command: %s\n", &command); // Include newline now...
// This is computed above...
// int length = strlen(command);
// Continue as before
如前所述,fgets
(3)为您提供尾随“\n”。如果使用获取
(3),则不会获取尾随的换行符。没有比一致性更好的了,特区一号
Perl有一个hand chomp()函数,它可以修剪尾随的换行符(如果它出现的话)-你可以做得比滚动自己的换行符更糟糕:
#define NUL ((char)0)
void chomp( char *s )
{
if ( s != null )
{
int len = strlen(s) ;
if ( len >= 1 && s[len-1] == "\n" )
{
s[len-1] = NUL ;
}
}
return ;
}
可能最简单的处理方法是切换到使用scanf
读取输入:
char command[51];
scanf("%50[^\n]", command);
if (0 == strcmp(command, "exit"))
do_something();
这个奇怪的角色是回车还是换行?(IIRC,0xA或0xD?)您可以尝试类似于echo$command | od-a
,它将吐出变量中的单个字符。如果在行的末尾有一些奇怪的东西,它就会显示出来。@Mehrdad-如果它是OxD,我会有点惊讶,因为stdin
不应该以二进制读取模式打开。@Chris:说得好,没有想到那一部分。:)@马克:也许不是,因为这是C,不是sh。我确信有一种比在循环中调用strlen
3次更快的方法来转储空白字符(假设strlen
将迭代整个字符串)@Mark:更好?考虑到这些字符串的长度,以及他正在等待用户输入的事实,我并不真正担心优化的程度。。。现在它只有一个strlen(已经在他的原始代码中了)@Mark-你甚至可以只做一个赋值,不管你有多少尾随空间。(有人可能会说这是不安全的,但它只会给不安全的代码带来问题。)几乎更好。具有113k rep的人应该更了解如何在签名类型中存储字符串长度<代码>尺寸
<代码>尺寸
<代码>尺寸!你说得对,我认为优化对这个任务来说不是什么大不了的事。如果((strncmp(command,“exit”,4))==0)可以工作,但是我将使用这个while循环,所以键入“exitasdjhsd”不会退出shell,尽管这不是最初的预期用途,strtok
可以很好地工作:strtok(s,“\n”)
事实上,这是我唯一使用的strtok
。gets
不应被视为修复程序,因为它不能防止缓冲区溢出。您的函数有一些问题。a) 我更喜欢将nul字符表示为'\0'
,这显然是一个字符文字,尽管您也可以使用0
。调用它NUL
很容易与空指针混淆。其中,b)称为NULL
,而不是NULL
。c) strlen
返回一个size\u t
,它既不能保证与int
大小相同,也不能被签名。不要使用int
存储对象大小或数组索引,也不要使用无符号整数类型。使用size\u t
。这就是它的目的。d) 我更喜欢if(s==NULL)返回
减少整体缩进。@Ben Voigt:你说得没错--gets
是一个问题,而不是修复方法。@Chris Lutz:使用NUL
的原因是它是代码点0x00处控制字符的ASCII名称。名称NUL
已经使用了40多年(可以追溯到1968年由ANSI X3.2产生的ASCII标准。下面是该标准代码表的扫描图像:(1963年版本的ASCII标准只是使用了描述性的措辞,0x00当时是NULL
。C编程语言宏NULL
是这里的新手。在所有答案中,这是最简单的一个,而且很有效。谢谢!!谢谢你的回答。我相信你的答案在范围和成功方面都是合适的。)inct.And:它可以工作,但没有任何意义。这看起来不像是一个有效的格式字符串。它使用的是什么编译器(或者更确切地说,是libc实现?@Ben Voigt:除非我输入了一个我看不见的拼写错误,否则它是一个vali