2015-03-26 2 views
1

Итак, я занимаюсь упражнениями на языке программирования C 2nd Edition от Ritchie/Kernighan. Специально выполняйте 1.9. «Напишите программу для копирования ее ввода на вывод, заменяя каждую строку на еще одну пробел одним пробелом».Выходы Путчара и Getchar каждый раз, когда я нажимаю enter

Я считаю, что мое решение правильно, но каждый раз, когда я нахожусь, появляется экран, выводящий мою линию вместо ожидания EOF. Это ожидаемое поведение? Я использую только те функции и ключевые слова, которые он прочитал в книге.

Если у меня несколько строк новой строки, как заставить его ждать, пока я не войду в eof, прежде чем я получу выход? Путчар просто обрабатывает его по одному персонажу за раз, поэтому, возможно, это невозможно.

И что такое backspace? Он ссылается на просто пробел с помощью пробела?

/* 
Copys its input to its output, replacing each string with multiple blanks with one. 
Input - "I am running." 
Output - "I am running." 

*/ 
#include "stdafx.h" 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    for (int c = getchar(); c != EOF;){ 

     while (c == ' '){ 
      c = getchar(); 


      if (c != ' '){ 
       putchar(' '); 
      } 
     } 

     putchar(c); 
     c = getchar(); 
    } 

    return 0; 
} 

Улучшенная verision:

int _tmain(int argc, _TCHAR* argv[]) 
{ 

    int c; 

    while ((c = getchar()) != EOF){ 

     while (c == ' '){ 
      c = getchar(); 
       if (c == EOF){ 
       break; 
      } 

      if (c != ' '){ 
       putchar(' '); 
      } 
     } 

     putchar(c); 
    } 

    return 0; 
} 
+0

Логика у вас есть вид грязный, и я не имею в виду, что, как оскорбление. Когда вы учитесь, легко попасть в выражения 'while', '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' Возможно, подумайте о том, как вы могли бы реорганизовать свой цикл, когда получите персонажа и проверите его, пока не достигнете 'EOF'. – DigitalNinja

+0

Пожалуйста, покажите мне, как. – runners3431

+0

Я думаю, что ваша улучшенная версия лучше. Это более читаемо и использует меньше кода. – DigitalNinja

ответ

0

Ваша программа не правильно за сбор всех входных до конца файла, а затем повторяя все его обратно сразу. Строго говоря, это даже не правильно для сбора и повторения ввода по строкам - вы получаете этот результат только потому, что ваш стандартный ввод буферизируется по строке, что является общим, но не обязательным. Что это на самом деле делает является характерным символом эха.

Вместо этого вам необходимо записать входные символы в какое-то пространство для удержания, пока не увидите EOF, а затем откликните все содержимое этого пространства. Без каких-либо ограничений на форму или размер ввода, самым простым способом его реализации, вероятно, будет буферизация ввода во временном файле до тех пор, пока время не вернется к нему. Вы также можете буферизовать данные в памяти, но тогда вам нужно быть осторожным при резервировании достаточной памяти и/или динамическом увеличении размера необходимого буфера.

«Backspace» - это код, сгенерированный ключом backspace (а не пробелом), который обычно интерпретируется как сигнал для удаления символа, непосредственно предшествующего позиции ввода. В ASCII это символ 8 (десятичный).

+0

Спасибо, но он даже не переместил буферы, массивы или указатели.Мне просто интересно, правилен ли код в соответствии с тем, где я нахожусь в книге, которая похожа на страницу 17. – runners3431

+0

Как я уже сказал, нет, это неправильно для описанной проблемы. –

+0

Описанная проблема, похоже, не требует, чтобы все входные данные были буферизованы перед выходом. Это казалось просто дополнительным вопросом @ runners3431. Если вы еще не написали буферы, кажется, что этот код отлично подходит. Он копирует все входные данные и удаляет лишние пробелы. – Matt

1

Посмотрите на theory-behind-getchar-and-putchar-functions. Это объясняет, почему вы получаете выход после каждой строки.

Чтобы заставить программу ждать EOF, прежде чем outputing, вам нужно будет использовать буфер какого-то, посмотри на print-multiple-lines-by-getchar-and-putchar

+0

Я просмотрел 2-ую ссылку, но автор еще не перешел на fgets или массивы. Я не думаю, что автор имел в виду для нас использовать их в реализации программы. Возможно, я просто прошу что-то, что мне нужно подождать. Если вы посмотрите на копию файла 1.5.1, его реализация копии файла очень проста. – runners3431

+0

@ runners3431, да, вы должны узнать о массивах, прежде чем пытаться сделать буферизацию. –

+0

@ runners3431, да, если вы не перешли массивы, то вам, вероятно, не нужно делать что-либо вроде того, что они сделали во второй ссылке. Учитывая то, что вы уже рассмотрели, ваше решение, вероятно, прекрасно. – Matt

0

забоя является характер, производится с помощью клавиатуры (обычно есть ключ что говорят «backspace»)

при использовании «приготовленного» ввода, обратное пространство очень удобно для редактирования входной строки перед передачей ее в программу. (он попадает в программу при входе/карете. Возврат удаляется.)

Обычно, когда текст вводится с клавиатуры, EOF никогда не произойдет. Тем не менее, EOF может быть принудительно с клавиатуры (в зависимости от ОС) либо ctrl-z, либо ctrl-d

1

Ваш putchar() работает так, как вы хотите, потому что stdin - это строка буферизации, которая не является чем-то, что вы должны принять как должное , Вам было бы лучше собирать струны, разбирать их и давать им результат.

Вот что я хотел бы сделать:

#include <stdio.h> 
#include <string.h> 

#define BUFF_SIZE 2048 

int main(void) 
{ 

    char buff[2048]; 
    char *buff_temp = buff; 
    char *buff_ptr = buff; 
    unsigned int len = 0; 

    while (fgets(buff_ptr, sizeof buff, stdin) != NULL) { 
     len += strlen(buff_ptr) + 1; 
     buff_ptr += strlen(buff_ptr); 
    } 
    buff_ptr = buff; 

    while (--len) { 
     while (*buff_ptr == ' ' && buff_ptr[1] == ' ') { 
      --len; 
      ++buff_ptr; 
     } 

     *buff_temp++ = *buff_ptr++; 
    } 
    printf("%s\n", buff); 
} 

Online compiler link

+0

Выглядит хорошо. Только корректировка будет заключаться в том, чтобы зафиксировать слова 'buflen = strlen (buff_ptr);', затем 'len + = buflen + 1; buff_ptr = buflen; ', чтобы избежать дублирования вызовов на' strlen'. –

0

Есть несколько способов подойти к этой проблеме. Как показывают другие, если вы знаете, что ваш ввод не будет превышать определенный размер, вы можете объявить static buffer достаточным для хранения ваших данных. Однако, если вы обнаружите, что в ситуации, когда вы не знаете, сколько данных вам нужно читать, вы можете перейти на dynamically allocating свой буфер, который даст вам возможность расти (или realloc) размер вашего буфера по мере необходимости. Ниже приводится такой подход. (вы можете перенаправить текстовый файл к нему в качестве теста).

Кроме того, было неясно, если вы хотите пропустить все пустые строки или если вы просто не хотите видеть ввод до EOF. Во всяком случае, если вы хотите пропустить пустые строки, вы можете добавить простой тест внутри цикла чтения после назначения p = line;.

/* skip blank lines */ 
if (*p == '\n' || *p == '\r') 
    continue; 

В этом примере используется getline вместо fgets, который обеспечивает 2 преимущества для вас. (1)getline выделит вам буфер строки, если вы инициализируете его до NULL; и (2) возвращает фактическое количество прочитанных символов, исключая необходимость вызова strlen. Дайте мне знать, если у вас есть вопросы:

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

void *realloc_void_on (void *p, size_t o, size_t n, size_t psz); 

int main (void) { 

    char *line = NULL;  /* pointer to use with getline() */ 
    char *p = NULL;   /* pointer to parse getline return */ 
    ssize_t nchr = 0;  /* actual chars read per-line  */ 
    size_t n = 0;   /* max chars to read (0 - no limit) */ 
    char *buff = NULL;  /* buffer to hold all lines read */ 
    char *ep = NULL;  /* end pointer for buff    */ 
    size_t cbuffsz = 0;  /* current buffer size    */ 
    size_t nbuffsz = 0;  /* new buffer size     */ 
    size_t offset = 0;  /* offset to orient end pointer  */ 

    /* read each line from stdin */ 
    while ((nchr = getline (&line, &n, stdin)) != -1) 
    { 
     p = line;   /* assign line address to pointer */ 

     /* set required new buff size, realloc, set end ptr, update cbuffsz */ 
     nbuffsz += nchr + 1; 
     buff = realloc_void_on (buff, cbuffsz, nbuffsz, sizeof *buff); 
     ep = buff + offset; 
     cbuffsz = nbuffsz; 

     while (*p) {       /* for each character in line  */ 
      *ep++ = *p;       /* add char to buff, increment ep */ 
      offset++;       /* increment offset     */ 
      if (*p == '\t' || *p == ' ') {  /* if space, or tab     */ 
       while (*p == '\t' || *p == ' ') /* read/discard following spaces */ 
        p++; 
      } 
      else 
       p++;       /* if not space, increment pointer */ 
     } 
    } 

    /* output complete buffer */ 
#ifdef DEBUG 
    printf ("\nBuffer:\n-----\n%s-----\n\n", buff); 
#else 
    printf ("%s\n", buff); 
#endif 

    /* free allocated memory */ 
    if (line) free (line); 
    if (buff) free (buff); 

    return 0; 
} 

/* reallocate memory for p of type size psz, from o to n. 
* accepts any pointer p, with current allocation o, 
* with the type size psz and reallocates memory to 
* n, intializing the new memory to zero and returning 
* a pointer to the newly allocated block of memory on 
* success, exit otherwise. 
*/ 
void *realloc_void_on (void *p, size_t o, size_t n, size_t psz) 
{ 
    void *tmp = realloc (p, n * psz); 
#ifdef DEBUG 
    printf ("\n reallocating %zu to %zu\n", o, n); 
#endif 
    if (!tmp) { 
     fprintf (stderr, "Error: pointer reallocation failure.\n"); 
     exit (EXIT_FAILURE); 
    } 
    p = tmp; 
    memset (p + o, 0, (n - o) * psz); /* memset new ptrs 0 */ 

    return p; 
} 

Сложение/компилирования

Without перераспределить отладочная информация:

gcc -Wall -Wextra -o buildbuf buildbuf.c 

С перераспределить отладочная информация (в том числе gdb отладочной информации):

gcc -Wall -Wextra -g -DDEBUG -o buildbuf buildbuf.c 

Input

I am running. 

Выход

I am running. 
Смежные вопросы