Язык Си - руководство для начинающих
Шрифт:
Используйте эти идеи, и ваша программа будет более надежной и менее подверженной аварийным ситуациям. Вы получаете тело функции, которое можете применять в других программах. Программирование в таком случае потребует меньше времени. Вообще все это похоже на хороший рецепт здорового программирования.
Не забывайте о классах памяти. Переменные можно определять вне функции; в этом случае их называют внешними (или глобальными) и они доступны более чем для одной функции. Переменные, определенные внутри функции, являются локальными для нее и не известны другим функциям. Если можно, используйте автоматическую
ЧТО ВЫ ДОЛЖНЫ БЫЛИ УЗНАТЬ В ЭТОЙ ГЛАВЕ
Как представлять функцию: черный ящик с информационным потоком.
Что такое "проверка ошибок" и почему эта процедура хороша.
Алгоритм сортировки.
Как заставить функцию изменять массив: function(array).
Как преобразовать строку цифр в число.
Классы памяти: auto, extern, static и register.
Область действия каждого класса памяти.
Какой класс памяти использовать: обычно auto.
ВОПРОСЫ И ОТВЕТЫ
Вопросы
1. Что может сделать наш алгоритм сортировки неэффективным?
2. Как следует изменить нашу программу сортировки, чтобы она сортировала и по рядке возрастания, а не убывания?
3. Измените функцию print таким образом, чтобы она печатала по 5 чисел в строке.
4. Как следует изменить функцию stoi, чтобы обрабатывать строки, представляющие восьмеричные числа?
5. Какие функции "знают" каждую переменную из описанных ниже? Есть ли здесь какие-нибудь ошибки?
/* файл1 */
int daisy;
main
{
int lily;
}
petal {
extern int daisy, lily;
}
/* файл2 */
static int lily;
int rose;
stem {
int rose;
}
root
{
extern int daisy;
}
Ответы
1. Предположим, что вы сортируете 20 чисел. Программа производит 19 сравнений, чтобы найти одно самое большое число. Затем делается 18 сравнений, чтобы найти следующее самое большое. Вся информация, полученная во время первого поиска "забывается" за исключением самого большого числа, поставленного на первое место. Второе самое большое число можно временно поместить на место с номером 1, а затем при сортировке опустить вниз. Много сравнений, выполнявшихся в первый раз, повторяется второй, третий раз и т. д.
2. Замените array[search] > array[top] на array[search] < array[top]
3.
/* печать массива */
print(array, limit)
int array[ ], limit);
{
int index;
for(index = 0; index < limit; index++)
{ printf("%10d", array[index]);
if(index % 5 == 4) primf("\n" );
} printf("\n");
}
4.
Во-первых, обеспечьте, чтобы разрешенные символы были только цифрами от 0 до 7. Во-вторых, умножайте на 8 вместо 10 каждый раз, когда обнаружите новую цифру.5. daisy известна функции main по умолчанию и функциям petal и rоо1 благодаря extern-описанию. Она не известна функции stem, потому что они находятся в разных файлах.
Первая lily локальна для main: ссылка на lily в petal является ошибочной, потому что в каждом из этих файлов нет внешней lily.
Есть внешняя статическая lity, но она известна только функциям второго файла. Первая, внешняя rose, известна функции root, а функция stem отменила ее своей собственной локальной rose.
УПРАЖНЕНИЯ
1. Некоторые пользователи, возможно испугаются, если их попросить ввести символ EOF.
а. Модифицируйте getarray и вызываемые ею функции так, чтобы использовать символ # вместо EOF.
б. Модифицируйте затем их так, чтобы можно было использовать либо EOF, либо #.
2. Создайте программу, которая сортирует числа типа float.
3. Создайте программу, превращающую смешанный текст из прописных и строчных букв в текст, состоящий только из прописных букв.
4. Создайте программу, которая удваивает пробелы в тексте с одиночными пробелами.
11. Препроцессор языка Си
ДИРЕКТИВЫ ПРЕПРОЦЕССОРА СИМВОЛЬНЫЕ КОНСТАНТЫ МАКРООПРЕДЕЛЕНИЯ И "МАКРОФУНКЦИИ" ПОБОЧНЫЕ ЭФФЕКТЫ МАКРООПРЕДЕЛЕНИИ ВКЛЮЧЕНИЕ ФАЙЛОВ УСЛОВНАЯ КОМПИЛЯЦИЯ
ДИРЕКТИВЫ ПРЕПРОЦЕССОРА #define, #include, #undef, #if, #ifdef, #ifndef, #else, #endif
Язык Си был разработан в помощь работающим программистам, а им нравится его препроцессор. Этот полезный помощник просматривает программу до компилятора (отсюда и термин "препроцессор") и заменяет символические аббревиатуры в программе на соответствующие директивы. Он отыскивает другие файлы, необходимые вам, и может также изменить условия компиляции. Однако эти слова не отражают истинную пользу и значение препроцессора, поэтому обратимся к примерам. Конечно, до сих пор мы снабжали все примеры директивами #define и #include, но теперь мы можем подытожить все, что изучили, и развить тему дальше.
СИМВОЛИЧЕСКИЕ КОНСТАНТЫ: #define
Директива #define, подобно всем директивам препроцессора, начинается с символа # в самой левой позиции. Она может появиться в любом месте исходного файла, а даваемое ею определение имеет силу от места появления до конца файла. Мы активно используем эту директиву для определения символических констант в наших программах, однако она имеет более широкое применение; что мы и покажем дальше. Вот пример, иллюстрирующий некоторые возможности и свойства директивы #define: