【问题标题】:fgets and chdir acting strangely together in Cfgets 和 chdir 在 C 中一起奇怪地表现
【发布时间】:2015-02-02 18:01:57
【问题描述】:

我目前正在为家庭作业创建一个简单的外壳,但遇到了问题。这是一段与问题有关的代码片段(我可能忘记了一些片段,如果您发现有任何遗漏,请告诉我):

eatWrd 从字符串中返回第一个单词,并将该单词从字符串中取出。

wrdCount 隐含地返回字符串中的单词数。

如果这些代码中的任何一个对于回复来说是必需的,我可以发布它们,请告诉我,我几乎 100% 肯定它们不是问题的原因。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100

int main(void)
{
  char input[MAX];
  char *argm[MAX];
  memset(input, 0, sizeof(input));
  memset(argm, 0, sizeof(argm));

  while(1){
    printf("cmd:\n");
    fgets(input, MAX-1, stdin);

    for(i=0;i < wrdCount(input); i++){
      argm[i] = eatWrd(input);
    }
    argm[i] = NULL;

    if (!strncmp(argm[0],"cd" , 2)){
      chdir(argm[1]);
    }

    if (!strncmp(argm[0],"exit", 4)){
      exit(0);
    }

    memset(input, 0, sizeof(input));
    memset(argm, 0, sizeof(argm));
  }
}

无论如何,这个循环适用于许多使用 execvp 的其他命令(例如 cat、ls 等),当我使用 cd 时,它按预期工作,除非我尝试退出 shell 时,它需要多次退出呼吁真正离开。 (事实证明,退出调用的次数正好等于我调用 cd 的次数)。当我在会话期间不使用 cd 时,它只需要一个退出调用。我不太确定发生了什么,感谢任何帮助,谢谢。

这里是eatWrd:

char* eatWrd(char * cmd)
{
  int i = 0;            // i keeps track of position in cmd
  int count = 0;        // count keeps track of position of second word
  char rest[MAX_LINE];  // rest will hold cmd without the first word

  char * word = (char *) malloc(MAX_LINE);   //word will hold the first word
  sscanf(cmd, "%s", word);                   //scan the first word into word

  // iterate through white spaces, then first word, then the following white spaces
  while(cmd[i] == ' ' || cmd[i] == '\t'){
    i++;
    count++;
  }

  while(cmd[i] != ' ' && cmd[i] != '\t' && cmd[i] != '\n' && cmd[i] != '\0'){
    i++;
    count++;
  }

  while(cmd[i] == ' ' || cmd[i] == '\t'){
    i++;
    count++;
  }

  // copy the rest of cmd into rest
  while(cmd[i] != '\n' && cmd[i] != '\0'){
    rest[i-count] = cmd[i];
    i++;
  }
  rest[i-count] = '\0';

  memset(cmd, 0, MAX_LINE);
  strcpy(cmd, rest);        //move rest into cmd
  return word;              //return word
}

这里是 wrdCount:

int wrdCount(char *sent)
{
  char *i = sent;
  int words = 0;

  //keep iterating through the string, 
  //increasing the count if a word and white spaces are passed,
  // until the string is finished.
  while(1){
    while(*i == ' ' || *i == '\t') i++;

    if(*i == '\n' || *i == '\0') break;

    words++;

    while(*i != ' ' && *i != '\t' && *i != '\n' && *i != '\0') i++;
  }
  return words;
}

【问题讨论】:

  • 您是否收到任何额外/缺失的cmd: 提示?并尝试使用调试器。它会立即指出您的问题。
  • 而 gdb 说的是正在发生的事情
  • 您没有显示wrdCounteatWrd。在这一点上,我当然会怀疑这些。
  • 我有一种感觉,遗漏的函数会弄乱输入指针。所以是的,也给他们看
  • 当您可以依赖两个输入以空终止时,使用strncmp() 来识别内置函数是很奇怪的。考虑到所有这些都将被上述代码视为等效:cdcd1cdoopscd...NOT!

标签: c shell fgets chdir


【解决方案1】:

您的代码的这种变体对我有用:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#define MAX 100

char *eatWrd(char **line) {
    char *next_c = *line;
    char *word_start = NULL;

    while (isspace(*next_c)) next_c += 1;

    if (*next_c) {
        word_start = next_c;
        do {
            next_c += 1;
        } while (*next_c && ! isspace(*next_c));
        *next_c = '\0';
        *line = next_c + 1;
    }

    return word_start;
}

int main(void)
{
    char input[MAX];
    char *argm[MAX];

    while(1) {
        int word_count = 0;
        char *next_input = input;

        printf("cmd:\n");
        fgets(input, MAX, stdin);

        do {
              argm[word_count] = eatWrd(&next_input);
        } while (argm[word_count++]);
        /* The above always overcounts by one */
        word_count -= 1;

        if (!strcmp(argm[0], "cd")){
            chdir(argm[1]);
        } else if (!strcmp(argm[0], "exit")) {
            exit(0);
        }
    }
}

注意我对eatWrd() 的变体,它不需要移动任何数据,也不需要预先解析字符串来确定预期的字数。我想你的实现会更复杂,以便处理引用或类似的事情,但它绝对可以遵循相同的一般方法。

还要注意,我对命令匹配条件的更正,使用!strcmp() 而不是strncmp()

【讨论】:

  • 好的,非常感谢,这很有见地,我会赞成你的回答,但我还没有足够的声誉来投票
  • @quigs,如果我已经充分回答了您的问题,那么通常的做法是接受答案(通过单击旁边的复选标记)。你不需要代表。
猜你喜欢
  • 1970-01-01
  • 2016-07-15
  • 1970-01-01
  • 2020-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-30
相关资源
最近更新 更多