Как заменить getchar();?

#include <stdio.h>

int main (void)
{
int n;

printf("Give the number of words you want to input.");
scanf("%d",&n);

int letters[n],i,j,count,key,k;
char str[100];
 //Scans each word, counts it's letters and stores it in the next available 
 //position in "letters" array.
 for (i=0;i<n;i++)
    {
        j=0;
        printf("Give the next word.");
        do{
            str[j] = getchar();
            j++;
        }while (str[j-1]!='\n');
        str[j-1] = '\0';

        letters[i] = j;
    }

//Compacts the data by figuring out which cells have the same number of letters 
for (i=0;i<n;i++)
    {
        key = letters[i];
        count = 0;
        for (j=i+1;j<=n;j++)
            {
                if (key==letters[j])
                    {   
                        count += 1;
                        letters[j] = 0;
                    }
            }
        letters[i] = count;
    }

//creates a histogram
i=0;
do{
    printf("%d|",i);
    for (j=1;j<=letters[i];j++)
    {
        printf("*");
    }
    printf("\n");
    i++;
}while ((i<=n));

return 0;

}

Я понимаю, что getchar(); читает, первый ввод (\n) пользователь нажимает, чтобы указать количество слов, которые он хочет ввести, и, таким образом, ожидает на одно слово меньше.

Кроме того, я получаю бесконечный цикл по какой-то причине в конце. Любая помощь и идеи будут оценены. Заранее спасибо.


person Mechanic45    schedule 21.01.2014    source источник
comment
Ваш код сохраняется непосредственно в символы, при этом теряется информация о EOF, которую вы в любом случае не тестируете. Это то, что приводит к неприятностям. Помните: getchar() возвращает int, которое является либо значением char (обрабатывается как беззнаковое), либо отрицательным значением (условно -1), указывающим EOF. Это на одно значение больше, чем может поместиться в char, поэтому возвращаемый тип — int. Я не смотрел, что еще не так.   -  person Jonathan Leffler    schedule 22.01.2014


Ответы (3)


Измените первый блок вашего кода, чтобы он выглядел следующим образом:
(проверьте вывод getchar и продолжите, только если не EOF)

for (i=0;i<n;i++)
{
    j=0;
    printf("Give the next word.");
    do{
        a = getchar();
        if(a >= 0) 
        {
            str[j] = a;
            j++;
        }
        else break;
    }while (str[j-1]!='\n');
    str[j-1] = '\0';

    letters[i] = j;
}

Но что касается вашего вопроса: Как я могу заменить getchar();? Рассматривали ли вы возможность использования scanf()?

ИЗМЕНИТЬ
Вот простой пример использования scanf() и printf() для запроса ввода и последующего отображения ввода. Это позволит пользователю вводить целые слова или предложения (до 80 символов), пока не будет введено «q». Не совсем то, что вы делаете, но вы сможете адаптировать его к своему коду... (запустите это)

int main(void)
{
    char buf[80]={""};
    while(  strcmp(buf, "q") != 0)  //enter a 'q' to quit
    {
        buf[0]=0;
        printf("enter string:\n");
        scanf("%s", buf);
        printf("%s\n", buf);
    }

}
person ryyker    schedule 21.01.2014
comment
Это не помогло. Я изменил это. Потом запустил. Он получил первый printf правильно. затем я дал номер 5. затем он напечатал Дайте следующее слово. Дайте следующее слово. а потом принял всего 4 слова вместо 5, как я ожидал. и после того, как я ввел 4-е слово, он начал печатать * повсюду. - person Mechanic45; 22.01.2014
comment
Как я могу использовать scanf() в этом случае, так как я хочу, чтобы пользователь мог вводить целые слова? - person Mechanic45; 22.01.2014
comment
Хорошо, я отредактирую свой ответ, используя комбинацию printf и scanf... (scanf() идеально подходит для ввода целых слов) - person ryyker; 22.01.2014
comment
хорошо, я адаптировал то, что вы предложили, но вместо «q» (предположим, что «q» может быть допустимым словом для ввода пользователем), как я могу остановить его, например, когда пользователь нажимает esc? - person Mechanic45; 22.01.2014
comment
Проверьте EOF; см. stackoverflow.com /вопросы/1782080/ - person Ruud Helderman; 22.01.2014
comment
@ Mechanic45 - Да, вы можете заменить «q» любым символом или строкой, которую захотите. Совершенно произвольно. Поиграйте с объявлением buf как char * также. Затем используйте [mc]alloc()/free() для выделения/освобождения памяти. Снимает ограничения на размер строки. - person ryyker; 22.01.2014

Не проще ли обновить количество букв в первом цикле?

memset(letters, 0, n);
for (i=0;i<n;i++)
{
    char* s = str;
    int j=0;
    printf("Give the next word.");
    do{
        *s = getchar();
        ++j;
    }while (*(s++)!='\n');
    s[-1] = '\0';

    letters[j-1]++;
}

В результате второй цикл станет ненужным.

person bb94    schedule 21.01.2014
comment
Я считаю, что это неправильно: s[-1]. Кроме этого, я действительно не понимаю, почему это отличается от того, что я сделал, и почему это делает второй цикл бесполезным. - person Mechanic45; 22.01.2014
comment
*s = '\0', вероятно, вы имели в виду? (s[-1] имеет отрицательный индекс массива, что недопустимо) - person ryyker; 22.01.2014
comment
@Mechanic45: Изучая чужой код и пытаясь понять, как он работает и почему он работает, вы станете лучшим программистом. Просто верить, что это неправильно, не будет. - person Ruud Helderman; 22.01.2014
comment
s будет через один байт после символа новой строки, и отрицательные индексы допускаются, насколько мне известно. - person bb94; 22.01.2014

Следующие две строки имеют неправильное конечное условие; должно быть <n, а не <=n. В настоящее время они извлекают неинициализированный элемент массива. Поскольку вы объявили str как локальную переменную, этот элемент обычно заполняется мусором, то есть очень большим случайным числом. Это может объяснить, почему для завершения последнего цикла требуется очень много времени (но, возможно, не навсегда).

for (j=i+1;j<=n;j++)

}while ((i<=n));

Кроме того, я предполагаю, что строка n гистограммы должна содержать количество слов, содержащих n букв? Это не то, чем ты сейчас занимаешься.

letters[i] = count;

Эта строка должна была быть:

letters[key] = count;

Но чтобы это работало, вы не должны не перезаписывать один и тот же массив letters; вы должны объявить новый массив для вашей гистограммы, иначе второй цикл уничтожит свой собственный ввод.

Кстати, str кажется совершенно излишним. Это там для целей отладки?

person Ruud Helderman    schedule 21.01.2014
comment
насчет За и пока вы правы. что касается гистограммы, она должна отображать, сколько раз слово из n букв встречается со звездочками (*). нет связи между количеством букв и количеством строк гистограммы. - person Mechanic45; 22.01.2014
comment
@Mechanic45: я имел в виду номер строки, а не количество строк. О, но теперь, когда вы упомянули об этом: с количеством строк тоже что-то не так. Но не волнуйтесь, теперь, когда бесконечный цикл убран, вы узнаете об этом достаточно скоро. Небольшой совет: начните учиться пользоваться отладчиком, это поможет вам освоить собственную программу. - person Ruud Helderman; 22.01.2014
comment
Хм... действительно, я имел в виду: ...количество букв и номер отдельной линии гистограммы. (не общее количество строк) спасибо за совет. - person Mechanic45; 22.01.2014