Функции и структура программ☛Язык программирования C ✎ |
Функции разбивают большие вычислительные задачи на меньшие, и позволяют программистам строить на основе того, что написали другие, вместо начинать все с нуля. Хорошие функции прячут детали своей работы от частей программы, которые не должны об этом знать, таким образом проясняя весь код, и облегчая изменения.
C задумана, чтобы сделать функции эффективными и легкими в использовании; программы на C, как правило, состоят из многих малых функций, вместо нескольких больших. Сама программа может находиться в одном или нескольких исходных файлах. Исходники можно компилировать отдельно и загрузить вместе, рядом с предварительно откомпилированных функциями библиотеки. Мы не будем углубляться в этот процесс здесь, поскольку подробности могут отличаться в различных операционных системах.
Объявления и определения функций - это именно та область, где стандарт ANSI осуществил наибольшие изменения в языке C. Как мы уже видели ранее, появилась возможность описания типа аргументов при объявлении функций. Синтаксис определения функции также изменился, поэтому объявления и определения совпадают. Это позволяет теперь компилятору уловить гораздо больше ошибок, чем раньше. Более того, когда аргументы объявлен должным образом, соответствующие поправки типов осуществляются автоматически.
Стандарт проясняет правила области действия имен, в частности он требует, чтобы существовало только одно определение для каждого внешнего объекта. Инициализация стала более общей: теперь можно начинать автоматические массивы и структуры.
Препроцессор C также усовершенствован. Новые средства препроцессора теперь включают полный набор условных Комплекты директив, способ создания Закавычено цепочек из аргументов макроса, и улучшенное управление над процессом раскрытия макросов.
Основные знания о функциях
Для начала, спланируем и напишем программу вывода каждой строки ввода, который содержит определенный "образец" или цепочка знаков. (Своеобразную имитацию программы grep UNIX) Так, например, поиск образца, состоящий из букв "ould" в наборе строк
Ah Love! could you and I with Fate conspire
To grasp this sorry Scheme of Things entire,
Would not we shatter it to bits - and then
Re-mould it nearer to the Heart's Desire!
выдал бы нам
Ah Love! could you and I with Fate conspire
Would not we shatter it to bits - and then
Re-mould it nearer to the Heart's Desire!
Эту работу можно аккуратно разбить на три части:
while (есть еще строка)
if (строка содержит образец)
вывести строку
Безусловно, мы могли бы поместить весь код такой программы в main, но лучшим выходом будет использовать эту струкруру в свою пользу, разбив каждую ее часть на отдельные функции. С малыми частями гораздо легче справиться, чем с одним большим, поскольку детали, не относящиеся к делу, можно спрятать внутри функций, и возможность нежелательных взаимодействий будет сведено на нет. Также, части могут оказаться полезными для других программ.
"Еще есть строка" - это getline - функция, которую мы написали в главе 1 и "вывести строку" - это printf, которую кто создал уже для нас. Это означает, что нам осталось написать функцию, которая решала бы, строка содержит цепочку, совпадающий с образцом.
Мы можем решить эту задачу путем написания функции strindex (s, t), которая возвращает положение, или индекс в цепочке s, где начинается цепочка t, или -1, если s не содержит t. Поскольку массивы в C начинаются с позиции 0, их индексы могут быть либо нулевыми, либо положительными, поэтому отрицательное число, как вот -1 - удобное для сигнализации неудачи. Если нам позже нужно будет более изящное сравнение с образцом, мы можем заменить только функцию strindex, тогда как остальные кода может остаться неизменной. (Стандартная библиотека предусматривает функцию strstr, аналогичную strindex, за исключением того, что она возвращает указатель вместо индекса)
Имея все спланированным, заполнение деталей программы - достаточно прямолинейное. Ниже приведены весь код, поэтому вы можете увидеть, как части взаимодействуют вместе. Пока, вроде, по которому осуществляется поиск, состоит из буквенного цепочки, не является универсальным механизмом. Впоследствии, мы дойдем до обсуждения того, как инициировать символьные массивы, а в разделе 5 мы продемонстрируем, как сделать из образца параметр, который можно задать при обращении программы. Эта версия getline несколько отличается от использованной в Разделе 1; возможно будет поучительным, если вы сравните их.
# Include
# Define MAXLINE 1000 / * максимальная длина строки * /
int getline (char line [] int max);
int strindex (char source [] char searchfor []);
char pattern [] = "ould"; / * образец искаться * /
/ * Находит все строки, совпадающие с образцом * /
main ()
{
char line [MAXLINE];
int found = 0;
while (getline (line, MAXLINE)> 0)
if (strindex (line, pattern)> = 0) {
printf ("% s", line);
found + +;
}
return found;
}
/ * Getline: размещает строку в s, возвращает длину * /
int getline (char s [], int lim)
{
int c, i;
i = 0;
while (- lim> 0 & & (c = getchar ()! = EOF & & c! = '\ n')
s [i + +] = c;
if (c == '\ n')
s [i + +] = c;
s [i] = '\ 0';
return i;
}
/ * Strindex: возвращает индекс t в s, или -1, если t не найдено * /
int strindex (char s [], char t [])
{
int i, j, k;
for (i = 0; s [i]! = '\ 0'; i + +) {
for (j = i, k = 0; t [k]! = '\ 0' & & s [j] == t [k]; j + +, k + +)
;
if (k> 0 & & t [k] == '\ 0')
return i;
}
return 1;
}
Каждое определение функции имеет форму
тип_повернення назва_функции (объявление аргументов)
{
объявления и утверждения
}
Отдельные части могут отсутствовать. Минимальной функцией является
dummy () {}
которая не выполняет никаких действий и не возвращает никакого значения. Такие бездействующие функции времени полезны в качестве заполнителя при разработке программы. Если тип возврата опущен, предполагается int.
Программа - это лишь набор определений переменных и функций. Коммуникация между функциями происходит через аргументы и значения, возвращенные функциями, а также через внешние переменные. Функции могут находиться в любой последовательности в исходном тексте, а сам исходный код программы можно разделить на многочисленные файлы при условии, что ни одна функция не разделена.
Утверждение return является механизмом возврата значения вызванной функцией тому, кто ее вызвал. По return может следовать любое выражение:
return выражение;
Выражение будет преобразовано к типу возврата функции, если нужно. Вокруг выражения часто употребляются скобки, но они не обязательны.
Викликова функция имеет право игнорировать значение, возвращенное вызванной. Более того, выражение после return вообще может отсутствовать, в случае чего викликовий функций никакого значения возвращено не будет. Управление над выполнением программы также возвращается викликовий без никакого значения, когда выполнение "приходит с конца" функции, достигнув крайней фигурной скобки. Это не запрещено, но вероятно является проявлением неисправности, если функция возвращает значение в одном месте, и ни одного - в другом. В любом случае, если функции не удалось вернуть значение, то ее "значение" наверняка состоит из хлама.
Наша программа поиска образца возвращает из main статус - число найденных совпадений. Это значение становится доступным для использования средой, которое вызвало программу.
Механизм компиляции и загрузки программы на C, разбитой на многочисленные файлы, отличается в разных системах. В системе UNIX, например, эту задачу может выполнить команда cc, упомянутая в Главе 1. Предположим, что три функции сохранены в трех разных файлах под названием main.c, getline.c и strindex.c. В таком случае, команда
cc main.c getline.c strindex.c
сборки эти три файла, размещая объектный код, полученный в результате, в main.o, getline.o и strindex.o, после чего загружает их всех в исполнительный файл под названием a.out. Если возникла проблема, скажем в main.c, этот файл можно перекомпилировать отдельно, а результат скачать с предыдущими объектными файлами командой
cc main.c getline.o strindex.o
Команда cc пользуется условными названиями ". C" противовес ". O" для того, чтобы различить исходный файл от объектного.
Функции, которые возвращают целых
До сих пор, наши примеры функций или не возвращали никакого значения (void), либо возвращали int. А что, как функция должна вернуть какой-то другой тип? Много математических функций, таких как sqrt, sin или cos возвращают double; другие специализированные функции возвращают другие типы. Чтобы проиллюстрировать, как справиться с этой задачей, напишем и испытаем функцию atof (s), которая преобразует цепочку s в ее эквивалент в виде числа с плавающей точкой двойной точности. Функция atof - это расширение atoi версии которой мы рассмотрели в главе 2 и 3. Последнее обрабатывала возможен знак и десятичную точку, так же как недостаток или наличие целого или дробной части. Наша версия не является высококачественной функцией преобразования ввода; это заняло бы больше места, чем мы хотели бы использовать здесь. Стандартная библиотека включает atof; в заголовке
Прежде всего, сама atof должен объявить тип значения, которое она возвращает, поскольку это - не int. Название типа стоять перед названием функции:
# Include
/ * Atof: превращает s в число двойной точности * /
double atof (char s [])
{
double val, power;
int i, sign;
for (i = 0; isspace (s [i]); i + +) / * пропустить пробелы * /
;
sign = (s [i] == '-')? -1: 1;
if (s [i] == '+' | | s [i] == '-')
i + +;
for (val = 0.0; isdigit (s [i]); i + +)
val = 10.0 * val + (s [i] - '0 ');
if (s [i] == '.')
i + +;
for (power = 1.0; isdigit (s [i]); i + +) {
val = 10.0 * val + (s [i] - '0 ');
power *= 10.0;
}
return sign * val / power;
}
Во-вторых, так же важно, чтобы вызывающая функция знала, что atof возвращает не-int значение. Один из способов достичь этого - это явно объявить atof в викликовий функции. Объявления, показано в следующей примитивной программке-калькуляторе (достаточной разве что для збалансовування чековой книжки), которая читает по одному числу на строку, со знаком впереди, и добавляет их, выводя текущую сумму после каждого ввода:
# Include
# Define MAXLINE 100
/ * Простенький калькулятор * /
main ()
{
double sum, atof (char []);
char line [MAXLINE];
int getline (char line [] int max);
sum = 0;
while (getline (line, MAXLINE)> 0)
printf ("\ t% g \ n", sum + = atof (line));
return 0;
}
Объявления
double sum, atof (char []);
указывает на то, что sum является переменной типа double и, что atof - это функция, которая примет один аргумент char [] и вернет число типа double.
Другие материалы по теме:
- Внешние переменные и область действия- Функции и структура программ
- Типы, операторы и выражения
- Введение в c++
- Язык программирования c в игровой индустрии: движки и производительность
