1.8. Аргументы - вызов по значению.
Один аспект в “C” может оказаться непривычным для прог-
раммистов, которые использовали другие языки, в частности,
фортран и PL/1. в языке “C” все аргументы функций передаются
“по значению”. это означает, что вызванная функция получает
значения своих аргументов с помощью временных переменных
/фактически через стек/, а не их адреса. Это приводит к не-
которым особенностям, отличным от тех, с которыми мы сталки-
вались в языках типа фортрана и PL/1, использующих “вызов по
ссылке “, где вызванная процедура работает с адресом аргу-
мента, а не с его значением.
Главное отличие состоит в том, что в “C” вызванная функ-
ция не может изменить переменную из вызывающей функции; она
может менять только свою собственную временную копию.
Вызов по значению, однако, не помеха, а весьма ценное
качество. Оно обычно приводит к более компактным программам,
содержащим меньше не относящихся к делу переменных, потому
что с аргументами можно обращаться как с удобно инициализи-
рованными локальными перемнными вызванной процедуры. Вот,
например, вариант функции POWER использующей это обстоятель-
ство
POWER(X,N) /* RAISE X N-TH POWER; N > 0;
VERSION 2 */
INT X,N;
{
INT P;
FOR (P = 1; N > 0; --N)
P = P * X;
RETURN (P);
}
Аргумент N используется как временная переменная; из не-
го вычитается единица до тех пор, пока он не станет нулем.
Переменная I здесь больше не нужна. чтобы ни происходило с N
внутри POWER это никак не влияет на аргумент, с которым пер-
воначально обратились к функции POWER.
При необходимости все же можно добиться, чтобы функция
изменила переменную из вызывающей программы. Эта программа
должна обеспечить установление адреса переменной /техничес-
ки, через указатель на переменную/, а в вызываемой функции
надо описать соответствующий аргумент как указатель и ссы-
латься к фактической переменной косвенно через него. Мы рас-
смотрим это подробно в главе 5.
Когда в качестве аргумента выступает имя массива, то
фактическим значением, передаваемым функции, является адрес
начала массива. /Здесь нет никакого копирования элементов
массива/. С помощью индексации и адреса начала функция может
найти и изменить любой элемент массива. Это - тема следующе-
го раздела.
· 32 -
1.9. Массивы символов.
По-видимому самым общим типом массива в “C” является
массив символов. Чтобы проиллюстрировать использование мас-
сивов символов и обрабатывающих их функций, давайте напишем
программу, которая читает набор строк и печатает самую длин-
ную из них. Основная схема программы достаточно проста:
WHILE (имеется еще строка)
IF (эта строка длиннее самой длинной из
предыдущих)
запомнить эту строку и ее длину
напечатать самую длинную строку
По этой схеме ясно, что программа естественным образом
распадается на несколько частей. Одна часть читает новую
строку, другая проверяет ее, третья запоминает, а остальные
части программы управляют этим процессом.
Поскольку все так прекрасно делится, было бы хорошо и
написать программу соответсвующим образом. Давайте сначала
напишем отдельную функцию GETLINE, которая будет извлекать
следующую строку из файла ввода; это - обобщение функции
GETCHAR. мы попытаемся сделать эту функцию по возможности
более гибкой, чтобы она была полезной и в других ситуациях.
Как минимум GETLINE должна передавать сигнал о возможном по-
явлении конца файла; более общий полезный вариант мог бы пе-
редавать длину строки или нуль, если встретится конец файла.
нуль не может быть длиной строки, так как каждая строка со-
держит по крайней мере один символ; даже строка, содержащая
только символ новой строки, имеет длину 1.
Когда мы находим строку, которая длиннее самой длинной
из предыдущих, то ее надо где-то запомнить. Это наводит на
мысль о другой функции, COPY , которая будет копировать но-
вую строку в место хранения.
Наконец, нам нужна основная программа для управления
функциями GETLINE и COPY . Вот результат :
#DEFINE MAXLINE 1000 /* MAXIMUM INPUT
LINE SIZE */
MAIN() /* FIND LONGEST LINE */
{
INT LEN; /* CURRENT LINE LENGTH */
INT MAX; /* MAXIMUM LENGTH SEEN SO FAR */
CHAR LINE[MAXLINE]; /* CURRENT INPUT LINE */
CHAR SAVE[MAXLINE]; /* LONGEST LINE, SAVED */
MAX = 0;
WHILE ((LEN = GETLINE(LINE, MAXLINE)) > 0)
IF (LEN > MAX) {
MAX = LEN;
COPY(LINE, SAVE);
}
IF (MAX > 0) /* THERE WAS A LINE */
PRINTF(“%S”, SAVE);
}
· 33 -
GETLINE(S,LIM) /* GET LINE INTO S,RETURN LENGTH */
CHAR S[];
INT LIM;
{
INT C, I;
FOR(I=0;I<LIM-1 && (C=GETCHAR())!=EOF && C!='\N';++I)
S[I] = C;
IF (C == '\N') {
S[I] = C;
++I;
}
S[I] = '\0';
RETURN(I);
}
COPY(S1, S2) /* COPY S1 TO S2;
ASSUME S2 BIG ENOUGH */
CHAR S1[], S2[];
{
INT I;
I = 0;
WHILE ((S2[I] = S1[I] != '\0')
++I;
}
Функция MAIN и GETLINE общаются как через пару аргумен-
тов, так и через возвращаемое значение. аргументы GETLINE
описаны в строках
CHAR S[];
INT LIM;
которые указывают, что первый аргумент является массивом, а
второй - целым.
Длина массива S не указана, так как она определена в
MAIN . функция GETLINE использует оператор RETURN для пере-
дачи значения назад в вызывающую программу точно так же, как
это делала функция POWER. Одни функции возвращают некоторое
нужное значение; другие, подобно COPY, используются из-за их
действия и не возвращают никакого значения.
Чтобы пометить конец строки символов, функция GETLINE
помещает в конец создаваемого ей массива символ \0 /нулевой
символ, значение которого равно нулю/. Это соглашение ис-
пользуется также компилятором с языка “C”: когда в “C” -
программе встречается строчная константа типа
“HELLO\N”
·
34 -
то компилятор создает массив символов, содержащий символы
этой строки, и заканчивает его символом \0, с тем чтобы фун-
кции, подобные PRINTF, могли зафиксировать конец массива:
! H ! E ! L ! L ! O ! \N ! \0 !
Спецификация формата %S указывает, что PRINTF ожидает стро-
ку, представленную в такой форме. Проанализировав функцию
COPY, вы обнаружите, что и она опирается на тот факт, что ее
входной аргумент оканчивается символом \0, и копирует этот
символ в выходной аргумент S2. /Все это подразумевает, что
символ \0 не является частью нормального текста/.
Между прочим, стоит отметить, что даже в такой маленькой
программе, как эта, возникает несколько неприятных организа-
ционных проблем. Например, что должна делать MAIN, если она
встретит строку, превышающую ее максимально возможный раз-
мер? Функция GETLINE поступает разумно: при заполнении мас-
сива она прекращает дальнейшее извлечение символов, даже ес-
ли не встречает символа новой строки. Проверив полученную
длину и последний символ, функция MAIN может установить, не
была ли эта строка слишком длинной, и поступить затем, как
она сочтет нужным. Ради краткости мы опустили эту проблему.
Пользователь функции GETLINE никак не может заранее уз-
нать, насколько длинной окажется вводимая строка. Поэтому в
GETLINE включен контроль переполнения. в то же время пользо-
ватель функции COPY уже знает /или может узнать/, каков раз-
мер строк, так что мы предпочли не включать в эту функцию
дополнительный контроль.
Упражнение 1-14.
Переделайте ведущую часть программы поиска самой длинной
строки таким образом, чтобы она правильно печатала длины
сколь угодно длинных вводимых строк и возможно больший
текст.
Упржнение 1-15.
Напишите программу печати всех строк длиннее 80 симво-
лов.
Упражнение 1-16.
Напишите программу, которая будет удалять из каждой
строки стоящие в конце пробелы и табуляции, а также строки,
целиком состоящие из пробелов.
Упражнение 1-17.
Напишите функцию REVERSE(S), которая распологает сим-
вольную строку S в обратном порядке. С ее помощью напишите
программу, которая обратит каждую строку из файла ввода.
·
35 -
... основаниям. При этом философская абстракция языка оказывается неразрывно связана с основными темами и движениями философии в целом. Более конкретно, на ранние стадии традиционно рассматриваемого в рамках АФ анализа обыденного языка глубокое влияние оказала философия Дж. Э. Мура, особенно его учение о здравом смысле, согласно которому такие понятия, как «человек», «мир», «я», «внешний мир», « ...
... и других странах СНГ, а также облегчение доступа к русской и мировой культуре и науке. Таким образом, судя по данным наших исследований, востребованность русского языка осталась в республике достаточно высокой. Многие представители современной молдавской молодежи продолжают, как их отцы и деды, тянуться к русской культуре, научным и техническим достижениям России. Русский язык остается языком ...
... рисуночное словесно-слоговое письмо). Памятники среднеэламского периода (14—12 вв. до н.э.) выполнены аккадской клинописью. Памятники новоэламского периода относятся к 8—6 вв. до н.э. Был официальным языком в персидском государстве Ахеменидов в 6—4 вв. предполагается, что он, подвергшись влиянию древнеперсидского, сохранился до раннего средневековья. 7. Бурушаски язык Язык бурушаски ( ...
... /диалект), скифский, согдийский, среднеперсидский, таджикский, таджриши (язык/диалект), талышский, татский, хорезмийский, хотаносакский, шугнано-рушанская группа языков, ягнобский, язгулямский и др. Они относятся к индоиранской ветви индоевропейских языков. Области распространения: Иран, Афганистан, Таджикистан, некоторые районы Ирака, Турции, Пакистана, Индии, Грузии, Российской Федерации. Общее ...
0 комментариев