Язык Си - руководство для начинающих
Шрифт:
while(count++ <= stop) putchar(ch);
Второй цикл while в вышеупомянутом блоке осуществляет задачу вывода на печать символа, начиная с позиции, задаваемой переменной start, и кончая позицией, задаваемой переменной stop. На этот раз мы воспользовались постфиксной формой операции увеличения и операцией <=. Такая комбинация обеспечивает желаемый результат при выводе на печать символа - верхняя граничная позиция входит в поле печати. Для проверки этого факта вы можете воспользоваться логикой или методом проб и ошибок.
putchar(' \n');
Оператор putchar('\n') используется для завершения
Форма данных
При написании программы необходимо понимать, как она будет взаимодействовать с входными данными. Сейчас мы обратимся к этому вопросу.
Вводимые данные должны быть представлены в форме, совместимой с требованиями, которые налагаются функциями ввода, используемыми в программе. Поэтому вся тяжесть приведения данных к правильной форме ложится на пользователя. В более сложных программах основной объем работы по такому преобразованию переносится на саму программу. Наилучшей формой представления вводимых данных является следующая:
Н 10 40
I 9 41
где за символом следуют номера начальной и конечной позиции. Но наша программа допускает также и такую форму данных:
Н
10
40
I
9
41
и такую
H10 40I 9 41
но не
Н 10 40 I 9 41
Почему наличие одних пробелов является необязательным, а других - обязательным? Почему символ "новая строка" может быть помещен между последним целым числом из одного набора данных и первым символом из следующего набора, а пробел нет?
Эти вопросы поднимают проблемы, касающиеся не только данной программы. Рассмотрим работу функций getchar и putchar и найдем ответы на них.
Функция getchar читает первый встретившийся символ независимо от того, является ли он алфавитным символом, пробелом, символом "новая строка" или еще чем-нибудь. Функция scanf делает то же самое, если чтение производится в формате %с (символ). Но, когда scanf осуществляет ввод данных в формате %d (целые), пробелы и символы "новая строка" пропускаются. Поэтому символы "новая строка" или любые пробелы между символом, считываемым функцией getchar, и следующим целым числом, считываемым функцией scanf, игнорируются. Функция scanf читает цифры до тех пор, пока не встретит нецифровой символ - пробел, символ "новая строка" или букву.
Следовательно, между первым и вторым целыми числами необходимо помещать пробел или символ "новая строка", чтобы функция scanf могла распознать где кончается одно и начинается другое. Этим объясняется, почему между символом и следующим целым числом может стоять пробел или символ "новая строка", и почему между двумя целыми числами обязательно должен быть разделитель такого вида. Но почему между целым числом, стоящим в конце набора данных, и следующим символом не может быть пробел? Потому что в следующий раз на очередном шаге выполнения цикла while функция getchar осуществляет ввод символа из той позиции, где "остановилась" функция scanf. Поэтому она прочтет любой следующий символ, стоящий после целого числа, - пробел, символ "новая строка" и т. п. Если бы мы следовали требованиям функции getchar, структуру данных необходимо было бы организовать так:
w10 50a20 60у10 30
где
if(ch != '\n')
чтобы иметь возможность обнаружить, когда значение ch равно символу "новая строка". Вместо этого можно использовать данные, вводимые в виде
w 10 50 а20 60 у10 30
где между числом 50 и а помещен символ "новая строка". Программа читает этот символ, игнорирует его и затем переходит к чтению следующего символа.
Контроль ошибок
Существует широко распространенная проблема, связанная с вводом в машину данных, которые должны использоваться определенным образом. Один из методов ее решения состоит в "контроле ошибок". Это означает, что, перед тем как приступить к обработке данных, программа должна проверить их правильность. В нашей программе мы сделали первую попытку осуществить такой контроль ошибок с помощью операторов:
if(start > stop || start < 1 || stop > MAXLENGTH)
printf(" Введены неправильные граничные значения. \n");
Они входят в структуру if-else, которая определяет, что основная часть программы будет выполняться только в том случае, если ни один из трех if– тестов не окажется истинным.
С какой целью мы принимаем все эти меры предосторожности? Во-первых, совершенно неправильно размещать начальную позицию после конечной, поскольку обычно на терминал данные выводятся слева направо, а не наоборот. Поэтому с помощью выражения start > stop проверяется наличие такой потенциальной ошибки. Во-вторых, при выводе на экран первый столбец имеет номер 1; мы не можем выводить данные левее левого края. Выражение start < 1 служит средством обнаружения такой ошибки. И наконец с помощью выражения stop > MAXLENGTH проверяется, не пытаемся ли мы вывести на печать данные правее правого края.
Существуют ли еще какие-нибудь ошибочные значения, которые мы можем присвоить переменным start и stop? Можно было бы, конечно, попробовать присвоить переменной start значение больше чем MAXLENGTH. Может ли этот вариант успешно пройти тест? Нет, хотя наличие подобной ошибки мы и не проверяем непосредственно.
Предположим, что величина start больше константы MAXLENGTH. Тогда либо значение stop тоже превышает величину MAXLENGTH, что обязательно приведет к обнаружению ошибки, либо stop окажется меньшей или равной MAXLENGTH. Тогда ее значение должно быть меньше величины start, что приведет к обнаружению этой ошибки первым тестом. Другая вероятно ошибка может состоять в том, что значение stop окажется левее 1. Мы оставляем читателям в качeстве самостоятельного упражнения проверку того, что данная ошибка также не останется не замеченной.
В нашей программе контроль ошибок выглядит весьма простым. Если вы проектируете программу для серьезных целей, вы должны обратить на этот больше внимания, чем мы. Например, выводимые сообщения об ошибках могли бы указывать какие величины неверны и почему; кроме того, вы могли бы прибавить в сообщения что-то от себя и придать им большую эмоциональную окраску.
Приведем несколько примеров:
Указаное вами значение stop– 897654 превышает ширину экрана.