fgets 和 chdir 在 C 语言中表现异常
fgets and chdir acting strangely together in C
我目前正在创建一个简单的 shell 作业,但我 运行 遇到了问题。这是一段代码,其中包含与该问题相关的部分(我可能忘记了一些部分,如果您发现任何遗漏请告诉我):
eatWrd returns 字符串中的第一个单词,并将该单词从字符串中取出。
wrdCount,顾名思义,returns 字符串中的单词数。
如果这些代码中的任何一个是响应所必需的,我可以 post 它们,请告诉我,我几乎 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,需要多次退出调用才能真正退出。 (事实证明,exit 调用的次数恰好等于我调用 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] != '[=11=]'){
i++;
count++;
}
while(cmd[i] == ' ' || cmd[i] == '\t'){
i++;
count++;
}
// copy the rest of cmd into rest
while(cmd[i] != '\n' && cmd[i] != '[=11=]'){
rest[i-count] = cmd[i];
i++;
}
rest[i-count] = '[=11=]';
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 == '[=12=]') break;
words++;
while(*i != ' ' && *i != '\t' && *i != '\n' && *i != '[=12=]') i++;
}
return words;
}
你的代码的这个变体对我有用:
#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 = '[=10=]';
*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()
。
我目前正在创建一个简单的 shell 作业,但我 运行 遇到了问题。这是一段代码,其中包含与该问题相关的部分(我可能忘记了一些部分,如果您发现任何遗漏请告诉我):
eatWrd returns 字符串中的第一个单词,并将该单词从字符串中取出。
wrdCount,顾名思义,returns 字符串中的单词数。
如果这些代码中的任何一个是响应所必需的,我可以 post 它们,请告诉我,我几乎 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,需要多次退出调用才能真正退出。 (事实证明,exit 调用的次数恰好等于我调用 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] != '[=11=]'){
i++;
count++;
}
while(cmd[i] == ' ' || cmd[i] == '\t'){
i++;
count++;
}
// copy the rest of cmd into rest
while(cmd[i] != '\n' && cmd[i] != '[=11=]'){
rest[i-count] = cmd[i];
i++;
}
rest[i-count] = '[=11=]';
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 == '[=12=]') break;
words++;
while(*i != ' ' && *i != '\t' && *i != '\n' && *i != '[=12=]') i++;
}
return words;
}
你的代码的这个变体对我有用:
#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 = '[=10=]';
*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()
。