Почему следующий код C пропускает системный вызов read() для выполнения следующего системного вызова write()?

Мой вопрос касается системного программирования Linux, в частности, API чтения и записи.

Я пишу программу, которая копирует оболочку. Он принимает строковый аргумент и маркирует его пробелом. В зависимости от команды первого токена, он выполняет операцию, используя оставшиеся токены в качестве параметров. До сих пор я реализовал это только для команды "add". Код выполняется в цикле, пока пользователь не введет "n" для "продолжить"? [Г / л]". Тем не менее, после первой итерации моя программа пропускает read() после первого вызова write() для ввода команды и в результате получает "continue?" написать () вызов. Почему он пропускает вызов read() сразу после первой записи ()?

int main (int argc, char *argv[]) {
int true=0;
while (true==0) {
    char buff1[]="Please enter your command\n";
    int count1= strlen(buff1);
    write (STDOUT_FILENO, buff1, count1);
    char buff2[100];
    int count2=read (STDIN_FILENO, buff2, 100);
    buff2[count2-1]='\0';
    char *list[30]; //This creates an array of character pointers (strings)
    /*
    * Begin tokenization and entering tokens in list
    */
    const char delim[]=" ";
    char *token;
    token=strtok(buff2, delim);
    const char newline[]="\n";
    int i=0;
    while (token!= NULL) {
        write (STDOUT_FILENO, newline, strlen(newline));
        list[i]=token;
        write (STDOUT_FILENO, list[i], strlen(list[i]));
        i++;
        token=strtok(NULL,delim);
    }
    /*
    * End tokenization
    */

    /*
    * Begin Addition operation
    */
    const char add[]="add";
    if (strcmp(list[0], add)==0) {
        int result=0;
        for (int j=1; j<i; j++) {
            result+=atoi(list[j]);
        }
        char sum[50];
        int sumcount=sprintf(sum, "%d", result);
        write (STDOUT_FILENO, newline, strlen(newline));
        write (STDOUT_FILENO, sum, sumcount);
    }
    /*
    * End Addition operation
    */


    char *truefalse;
    char endmessage[]="Continue: [y/n]\n";
    write (STDOUT_FILENO, endmessage, strlen(endmessage));
    read (STDIN_FILENO, truefalse, 1);
    if (*truefalse=='n') {
        true=1;
    }

}
return 0;
}

Как видно из этого выходного изображения, во второй итерации, после того, как я попросил ввести команду, код переходит к запросу продолжить, а не читать мою команду

1 ответ

Решение

Ваша программа имеет неопределенное поведение.

Вы используете указатель, который не был инициализирован, чтобы указать на что-либо допустимое.

Линия

char *truefalse;

объявляет указатель, но он не был инициализирован, чтобы указывать на что-либо действительное. Вы продолжаете использовать его в линии

read (STDIN_FILENO, truefalse, 1);

Вместо

char *truefalse;
char endmessage[]="Continue: [y/n]\n";
write (STDOUT_FILENO, endmessage, strlen(endmessage));
read (STDIN_FILENO, truefalse, 1);

использование

char truefalse; // Make it an object instead of a pointer.
char endmessage[]="Continue: [y/n]\n";
write (STDOUT_FILENO, endmessage, strlen(endmessage));
read (STDIN_FILENO, &truefalse, 1); // Use the address of the variable.

Обновить

Причина, по которой ваш код не ждет от вас ввода чего-либо во второй итерации, заключается в том, что символ новой строки все еще остается во входном потоке. Второй вызов просто читает символ новой строки.

Вам понадобится код, чтобы пропустить оставшуюся часть строки после прочтения ответа на вопрос.

Простейшим способом было бы использовать:

int c;
while ((c = fgetc(stdin)) != EOF && c != '\n');
Другие вопросы по тегам