2016-10-18 3 views
-6

так что я баловаться с функциями чтения fgets и зсапЕ и с функциями печати, записи и Printf со следующим кодом:Чтение и запись в C

#include <stdio.h> 
#include <stdlib.h> 

int main(int argc,char *argv[]) 
{ 
    printf("Enter an integer: "); 
    int n = 0; scanf("%d",&n); 
    printf("The input number is: %d\n", n); 
    printf("Please enter a string now: "); 
    char buffer[200]; 
    read(0,buffer,200); 
    printf("The input string is: %s", buffer); 
    printf("which is: %s\n", buffer); 
    printf("Now please enter another message: "); 
    fgets(buffer,200,stdin); 
    write(1,buffer,200); 

    return 0; 
} 

Я хотел бы получить эти ошибки:

1 -После первого scanf, он не просто покажет мне сообщение для ввода строки.

2-Что я пишу сейчас, это то, что он будет сохранен в строке.

3-он пропустит последний fgets ...

пример вывода: enter image description here

Который не имеет никакого смысла вообще; Я хотел бы получить такой вывод:

Enter an integer: 15 
The input number is: 15 
Please enter a string now: This is the message1 
The input string is: This is the message1 which is: This is the message1 
Now please enter another message: This is the message2 
This is the message2 

Спасибо за помощь!

+3

'read' не добавляет нулевой терминатор к вашему' buffer' – LPs

+1

и 'write' вывод всего' buffer', также не инициализированы пунктам. – LPs

+0

Не размещайте изображения текста. Текст в виде текста! – Olaf

ответ

0
read(0,buffer,200); 

считывает до 200 символов, но не добавляет завершающий нулевой символ в buffer. Следовательно, следующий вызов printf приводит к неопределенному поведению.

Вам нужно добавить код для захвата возвращаемого значения функции и убедиться, что значение null завершено.

int n = read(0, buffer, 199); // Leave one for the terminating null character 
if (n == -1) 
{ 
    // Deal with the error. 
} 
else 
{ 
    // null terminate the string. 
    buffer[n] = '\0'; 
} 
+0

Не так; 'read (0, buffer, 200);' в системах Unix, где вход поступает с терминала, вернет количество байтов, доступных во входном буфере, до предела 200. Если было несколько строк в очереди, то несколько строк будут возвращены; если есть одна строка с только новой строкой, то один символ будет возвращен; если еще нет доступных символов, он будет ждать, пока символы не станут доступными. Вы правы, это не приведет к завершению строки. Поэтому важно зафиксировать возвращаемое значение, чтобы вы знали об ошибках ('-1'), EOF (' 0') или фактической длине данных ('> 0'). –

+0

@JonathanLeffler, спасибо за указание ошибки. –

3

Интересный вопрос. Смешивание стандартного ввода-вывода (scanf(), fgets()) и ввода-вывода дескриптора файла (read()) в одном и том же базовом файловом дескрипторе (0 aka standard input; stdin в качестве потока файлов) в лучшем случае проблематично. Вы получите эффекты нечетного шара.

На уровне потока файлов существует некоторая синхронизация между stdin и stdout, когда вход поступает с терминала; ожидающий выход на stdout часто очищается библиотекой. Когда вы используете read(), такой синхронизации не существует. Вот почему приглашение не появляется до тех пор, пока вы не нажмете return.

Когда вы вводите 1 для номера, вы также предоставляете новую строку. Стандартный ввод-вывод буферизует новую строку; он хранится так, чтобы следующая операция потока файлов могла его прочитать. Затем вы читаете строку с read(). Это не знает о стандартном буфере ввода-вывода, поэтому он ожидает ввода новой строки с терминала. Вам нужно зафиксировать, сколько данных было прочитано, потому что вход не был завершен нулем; это услуга, предоставляемая стандартной библиотекой ввода-вывода, а не низкоуровневая функция read().

Когда вы звоните fgets(), он считывает новую строку, которая была буферизована (не обрабатывается scanf() при чтении целого числа) и возвращается с пустой строкой.

Обратите внимание, что если у вас какой-либо буферизованный выход ожидания на стандартном выводе (например, вы использовали printf("Beginning of line: ");, без перевода строки), то на выходе из write() появится до сведения забуференного на stdout.

Использование fread() и fwrite() даст вам прямой двоичный ввод/вывод (не нулевое окончание, например), но будет использовать те же буферы ввода/вывода, как функции, такие как printf() и fgets(). Вы получаете гибридное поведение при их использовании - обычно лучше использовать либо fread()/fwrite(), либо текстовые функции ввода-вывода в одном потоке файлов, а не оба, но смешивание их допустимо, относительно просто для понимания и иногда полезно.

Итак, все, что вы видите, объяснимо, но это трудная работа, объясняющая. Это также четкое указание на то, почему вы не должны, в общем, смешивать поток файлов и файловый дескриптор ввода-вывода с одним и тем же базовым файловым дескриптором - особенно не стандартным вводом.

+0

Хороший ответ. Возможно, упомянуть использование 'fread' на' stdin'? Хотя 'fread' не будет обнулять нулевой буфер, по крайней мере, он будет синхронизирован с другим чтением материала из' stdin'. –

+0

@IanAbbott: Хорошая идея; Я добавил абзац на эту тему. Благодарю. –

0

Почему бы не использовать scanf с некоторым лучше форматированием:

#include <stdio.h> 
#include <stdlib.h> 

int main(int argc,char *argv[]) { 
    int n, i; 
    char buffer[200], ch; 

    printf("Enter an integer: "); 
    scanf("%d",&n); 

    printf("The input number is: %d\n", n); 

    printf("Please enter a string now: "); 
    scanf(" %[^\t\n]s",buffer); 

    printf("The input string is: %s", buffer); 
    printf("which is: %s\n", buffer); 

    printf("Now please enter another message: "); 
    scanf(" %[^\t\n]s",buffer); 

    printf("%s", buffer); 

    return 0; 
} 
Смежные вопросы