Брайан Керниган - Язык программирования Си. Издание 3-е, исправленное
- Название:Язык программирования Си. Издание 3-е, исправленное
- Автор:
- Жанр:
- Издательство:Невский Диалект
- Год:2001
- Город:Санкт-Петербург
- ISBN:0-13-110362-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Брайан Керниган - Язык программирования Си. Издание 3-е, исправленное краткое содержание
Книга широко известных авторов, разработчиков языка Си, переработанная и дополненная с учетом стандарта ANSI для языка Си, 2-е английское издание которой вышло в 1988 году, давно стала классикой для всех изучающих и/или использующих как Си, так и Си++. Русский перевод этой книги впервые был выпущен изд- вом "Финансы и статистика" в 1992 г. и с тех пор пользуется неизменным спросом читателей.
Для настоящего третьего русского издания перевод заново сверен с оригиналом, в него внесены некоторые поправки, учитывающие устоявшиеся за прошедшие годы изменения в терминологии, а так же учтены замечания, размещенные автором на странице http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html.
Для программистов, преподавателей и студентов.
Издание подготовлено при участии издательства "Финансы и статистика"
Язык программирования Си. Издание 3-е, исправленное - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Последний оператор Си - это " ," (запятая), которую чаще всего используют в инструкции for. Пара выражений, разделенных запятой, вычисляется слева направо. Типом и значением результата являются тип и значение правого выражения, что позволяет в инструкции forв каждой из трех компонент иметь по несколько выражений, например вести два индекса параллельно. Продемонстрируем это на примере функции reverse(s), которая "переворачивает" строку s, оставляя результат в той же строке s:
#include ‹string.h›
/* reverse: переворачивает строку s (результат в s) */
void reverse(char s[])
{
int с, i, j;
for (i = 0, j = strlen(s)-1; i ‹ j; i++, j--) {
с = s[i];
s[i] = s[j];
s[j] = c;
}
}
Запятые, разделяющие аргументы функции, переменные в объявлениях и пр. не являются операторами-запятыми и не обеспечивают вычислений слева направо.
Запятыми как операторами следует пользоваться умеренно. Более всего они уместны в конструкциях, которые тесно связаны друг с другом (как в for-цикле программы reverse), а также в макросах, в которых многоступенчатые вычисления должны быть выражены одним выражением. Запятой-оператором в программе reverse можно было бы воспользоваться и при обмене символами в проверяемых парах элементов строки, мысля этот обмен как одну отдельную операцию:
for (i = 0, j = strlen(s)-1; i ‹ j; i++, j--)
с = s[i], s[i] = s[j], s[j] = c;
Упражнение 3.3. Напишите функцию expand(s1,s2), заменяющую сокращенную запись наподобие a-z в строке s1 эквивалентной полной записью аbс…хуz в s2. В s1 допускаются буквы (прописные и строчные) и цифры. Следует уметь справляться с такими случаями, как a-b-c, a-z0-9 и -a-b. Считайте знак - в начале или в конце s1 обычным символом минус.
3.6 Цикл do-while
Как мы говорили в главе 1, в циклах whileи forпроверка условия окончания цикла выполняется наверху. В Си имеется еще один вид цикла, do-while, в котором эта проверка в отличие от whileи forделается внизу после каждого прохождения тела цикла, т. е. после того, как тело выполнится хотя бы один раз. Цикл do-whileимеет следующий синтаксис:
do
инструкция
while ( выражение );
Сначала выполняется инструкция , затем вычисляется выражение . Если оно истинно, то инструкция выполняется снова и т. д. Когда выражение становится ложным, цикл заканчивает работу. Цикл do-whileэквивалентен циклу repeat-untilв Паскале с той лишь разницей, что в первом случае указывается условие продолжения цикла, а во втором - условие его окончания.
Опыт показывает, что цикл do-whileиспользуется гораздо реже, чем whileи for. Тем не менее потребность в нем время от времени возникает, как, например, в функции itoa (обратной по отношению к atoi ), преобразующей число в строку символов. Выполнить такое преобразование оказалось несколько более сложным делом, чем ожидалось, поскольку простые алгоритмы генерируют цифры в обратном порядке. Мы остановились на варианте, в котором сначала формируется обратная последовательность цифр, а затем она реверсируется.
/* itoa: преобразование n в строку s */
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) ‹ 0) /* сохраняем знак */
n =-n; /* делаем n положительным */
i = 0;
do {/* генерируем цифры в обратном порядке */
s[i++] = n %10 + '0'; /* следующая цифра */
} while ((n /= 10) › 0); /* исключить ее */
if (sign ‹ 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
Конструкция do-whileздесь необходима или по крайней мере удобна, поскольку в s посылается хотя бы один символ, даже если n равно нулю. В теле цикла одну инструкцию мы выделили фигурными скобками (хотя они и избыточны), чтобы неискушенный читатель не принял по ошибке слово whileза начало цикла while.
Упражнение 3.4. При условии, что для представления чисел используется дополнительный код, наша версия itoa не справляется с самым большим по модулю отрицательным числом, значение которого равняется -(2 n-1), где n - размер слова. Объясните, чем это вызвано. Модифицируйте программу таким образом, чтобы она давала правильное значение указанного числа независимо от машины, на которой выполняется.
Упражнение 3.5. Напишите функцию itob(n,s,b), которая переводит целое n в строку s, представляющую число по основанию b. В частности, itob(n, s, 16) помещает в s текст числа n в шестнадцатеричном виде.
Упражнение 3.6. Напишите версию itoa с дополнительным третьим аргументом, задающим минимальную ширину поля. При необходимости преобразованное число должно слева дополняться пробелами.
3.7 Инструкции break и continue
Иногда бывает удобно выйти из цикла не по результату проверки, осуществляемой в начале или в конце цикла, а каким-то другим способом. Такую возможность для циклов for, whileи do-while, а также для переключателя switchпредоставляет инструкция break. Эта инструкция вызывает немедленный выход из самого внутреннего из объемлющих ее циклов или переключателей.
Следующая функция, trim , удаляет из строки завершающие пробелы, табуляции, символы новой строки; breakиспользуется в ней для выхода из цикла по первому обнаруженному справа символу, отличному от названных.
/* trim: удаляет завершающие пробелы, табуляции и новые строки */
int trim(char s[])
{
int n;
for (n = strlen(s)-1; n ›= 0, n--)
if (s[n]!= ' '&& s[n]!= '\t'&& s[n]!= '\n')
break;
s[n+1] = '\0';
return n;
}
С помощью функции strlen можно получить длину строки. Цикл forпросматривает его в обратном порядке, начиная с конца, до тех пор, пока не встретится символ, отличный от пробела, табуляции и новой строки. Цикл прерывается, как только такой символ обнаружится или n станет отрицательным (т. е. вся строка будет просмотрена). Убедитесь, что функция ведет себя правильно и в случаях, когда строка пуста или состоит только из символов-разделителей.
Инструкция continueв чем-то похожа на break, но применяется гораздо реже. Она вынуждает ближайший объемлющий ее цикл ( for, whileили do-while) начать следующий шаг итерации. Для whileи do-whileэто означает немедленный переход к проверке условия, а для for- к приращению шага. Инструкцию continueможно применять только к циклам, но не к switch. Внутри переключателя switch, расположенного в цикле, она вызовет переход к следующей итерации этого цикла.
Вот фрагмент программы, обрабатывающий только неотрицательные элементы массива a (отрицательные пропускаются).
Читать дальшеИнтервал:
Закладка: