fgets函数在C语言中的应用

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); 假设我的输入

我的一项任务是编写自己的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);
假设我的输入是“退出”。斯特伦说字符串是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