2015-02-02 2 views
0

В настоящее время я создаю простую оболочку для домашней работы, и у меня возникла проблема. Вот фрагмент кода с фрагментами, относящимися к проблеме (возможно, я забыл некоторые фрагменты, пожалуйста, скажите мне, если вы видите что-то не хватает):fgets и chdir действуют странно вместе в C

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, (например, кошки, LS, и т.д.), когда я использую компакт-диск, он работает, как и ожидалось, за исключением того, когда я пытаюсь выйти из оболочки, для того, чтобы фактически выйти, требуется несколько вызовов выхода. (как оказалось, количество вызовов выхода в точности равно числу раз, когда я вызываю 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; 
} 
+0

Вы получаете какие-либо дополнительные/отсутствующие подсказки 'cmd:'? И попробуйте использовать отладчик. Он сразу укажет на вашу проблему. –

+0

и что говорит gdb: heppening – pm100

+0

Вы не показываете 'wrdCount' или' eatWrd'. Я определенно буду с подозрением относиться к этим в этот момент. – lurker

ответ

0

Это вариация на код работает для меня:

#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().

+0

Хорошо спасибо, это было очень проницательно, я бы поднял ваш ответ, но у меня нет достаточной репутации, чтобы проголосовать – quigs

+0

@quigs, если я адекватно ответил на ваш вопрос, тогда обычной задачей было бы принять ответ (нажав галочку рядом с ним). Вы не нуждаетесь в репутации для этого. –

Смежные вопросы