2013-05-22 2 views
0

Я сам изучал C и перерабатывал программу из книги C Primer. Я надеялся, что свежий набор глаз может определить тот самый вопрос, который у меня есть. Как вы можете видеть по моему результату и ожидаемому результату, я бы хотел избавиться от строки «0 - это число». Я считаю, что проблема с циклом while является проблемой, но я не могу избавиться от нее, несмотря на те вариации, которые я пробовал.Целочисленный результат проверки

Выход:

Enter some integers. Enter 0 to end. 
    1 two 3 0 4 
    1 is a number. 
    two is not an integer 
    3 is a number. 
    0 is a number. 

Ожидаемый результат:

Enter some integers. Enter 0 to end. 
    1 two 3 0 4 
    1 is a number. 
    two is not an integer 
    3 is a number. 
#include <stdio.h> 
#include <ctype.h> 

int get_int(void); //validate that input is an integer 

int main(void) 
{ 
    int integers; 

    printf("Enter some integers. Enter 0 to end.\n"); 
    while (integers != 0) 
    { 
     integers = get_int(); 
     printf("%d is a number\n", integers); 
    } 
    return(0); 

} // end main 

int get_int(void) 
{ 
    int input; 
    char ch; 

    while (scanf("%d", &input) != 1) 
    { 
     while (!isspace(ch = getchar())) 
      putchar(ch); //dispose of bad input 
     printf(" is not an integer\n"); 
    }  
    return input; 
}// end get_int 
+3

Обратите внимание, что ваша петля, записанная в настоящее время, не может быть выполнена вообще. Возможно, что «целые числа» будут содержать 0 до того, как цикл будет выполнен. Использование неинициализированных переменных приводит к ошибкам. Если вы скомпилируете с оптимизацией и предупреждениями, GCC сообщит, что ('gcc -O3 -Wall' должен это сделать, я использую' -Wextra' слишком регулярно). Кстати, IIRC, в Solaris, стек в основном обнуляется, так что будет неплохой шанс, что «целые числа» равны нулю при входе в программу. –

ответ

6

Что я хотел бы сделать, это переместить вызов get_int в состояние время цикла:

int main(void) 
{ 
    int integers; 

    printf("Enter some integers. Enter 0 to end.\n"); 
    while ((integers = get_int()) != 0) 
    { 
     printf("%d is a number\n", integers); 
    } 
    return(0); 

} // end main 

Проблема с вашим существующим кодом заключается в том, что между вызовом get_int() и печатью значения вы не проверяете, вернул ли ваш дозор 0.

Другой вариант заключается в том, чтобы добавить if (integers == 0) { break; } состояние между , но, на мой взгляд, назначение в состоянии является более чистым.

+0

Я знаю, что сам пишу этот цикл сам, но если начальная обработка и условие более сложны, чем это, я думаю, что внутренний оператор «break» более ясен. Один случай, который появляется много, - 'for (;;) {c = getchar(); if (c == EOF || c == terminator) break; ...} '- вы * можете * записать это полностью внутри некоторого условия, но только путем назначения-и-тестирования' c' в левой части '&&' и проверки его снова справа, что похоже на путать людей. – zwol

2

Вы правы, подозреваете, что вам нужно переделать петлю while. Вы попробовали что-то вроде этого?

for (;;) 
{ 
    integers = get_int(); 
    if (integers == 0) break; 
    printf("%d is a number\n", integers); 
} 

Кроме того, ваш get_int будет лучше написана с fgets (или getline если таковые имеются) и strtol. scanf соблазнительно удобен, но почти всегда больше проблем, чем того стоит.

+1

Это одна из конструкций «петли-и-половины» Кнута, о которой вы можете найти больше в поиске Google на «Кнут-полтора». –

1

Рассмотрим ядро ​​вашего цикла:

integers = get_int(); 
printf("%d is a number\n", integers); 

Независимо от того, что get_int() возвращается, то printf линия будет выполнена. Эта линия должна отдельный if:

integers = get_int(); 
if (integers != 0) printf("%d is a number\n", integers); 
+0

Но повторение условия цикла в теле цикла является уродливым. То, что вы сделали, работает, но это уродливо! –

+0

@JonathanLeffler У меня было достаточно мысли, прежде чем я отправил ответ. Существуют различные способы решения этой проблемы: использование break (в соответствии с Zack) - добавляет строку, добавляет условный, использует break (так сложнее следить за потоком imho); добавьте условный (по мне) уродливый, как вы говорите, с точки зрения пуриста кода, но легко для кого-то, кто изучает язык для изучения или из решения Джона Ледбеттера (идеально с точки зрения пуриста кода, но вносит много функциональности в один которая может быть сложнее для ученика). Пусть покупатель будет бдителен! –

+0

http://www-cs-faculty.stanford.edu/~eroberts//papers/SIGCSE-1995/LoopExits.pdf делает действительно убедительный аргумент IMNSHO для взлома в середине, который легче понять, чем любой из альтернативы. – zwol

2

Самый простой способ это поставить ваше состояние и назначение в то время как петли. Прямо сейчас ваш код полагается на integer, который устанавливается в цикле, а затем петли снова, чтобы проверить, равен ли он нулю.

while((integer = get_int()) != 0) 

Позволяет вам проверять одновременно с назначением целого числа. Не забудьте скобки, или ваше целочисленное значение будет результатом integer = (get_int != 0), потому что != имеет более высокий приоритет, чем = в C и C++.

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