Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Такой подход может привести к проблемам. Причиной обычной передачи данных по значению является обеспечение целостности данных. Если функция работает с копией исходных данных, она не сможет случайно исказить эти данные. Но поскольку функции обработки массивов работают с исходными данными, они могут модифицировать массив. Временами это желательно. Например, ниже приведена функция, которая добавляет одно и то же значение к каждому элементу массива:
void add_to(double ar[], int n, double val)
{
int i;
for ( i = 0; i < n; i++) ar [i] += val;
}
Следовательно, вызов функции
add_to(prices, 100, 2.50);
приводит к тому, что каждый элемент массива prices заменяется значением, превосходящим прежнее значение на 2.5; эта функция изменяет содержимое массива. Функция может делать это потому, что за счет работы с указателями она имеет дело с исходными данными.
Тем не менее, другие функции не предназначены для модификации данных. Например, показанная далее функция подсчитывает сумму содержимого массива; она
394 Глава 10 не должна изменять массив. Но поскольку ar в действительности представляет собой указатель, ошибка в коде может вызвать повреждение исходных данных. К примеру, здесь выражение ar[i] ++ в результате приводит к увеличению на 1 значения каждого элемента:
int sumlint ar[] , int n) // ошибочный код
{
int i;
int total = 0;
f or ( i = 0; i < n; i + +)
total += ar[i]++; // ошибочное инкрементирование каждого элемента
return total;
}
Использование const с формальными параметрами
В языке K&R С единственный способ избежать ошибки такого рода — быть внимательным. С выходом ANSI С появилась альтернатива. Если функция не задумывалась как изменяющая содержимое массива, применяйте ключевое слово const при объявлении формального параметра в прототипе и в определении функции. Например, прототип и определение функций sum() должны иметь следующий вид:
int sum(const int ar[], int n); /* прототип */
int sum(const int ar[], int n) /* определение */
{
int i;
int total = 0;
for ( i = 0; i
total += ar [i];
return total;
}
Это сообщает компилятору о том, что функция должна трактовать массив, указанный посредством ar, как содержащий константные данные. Если затем вы случайно воспользуетесь выражением, подобным ar [i] ++, компилятор сумеет обнаружить это и сгенерировать сообщение об ошибке, уведомляющее о том, что функция пытается изменить константные данные.
Важно понимать, что такое применение ключевого слова const вовсе не требует, чтобы исходный массив был константным; оно лишь говорит о том, что функция должна трактовать массив так, как если бы он был константным. Использование const в подобной манере предоставляет защиту для массивов, которую обеспечивает фундаментальным типам передача по значению; оно предотвращает модификацию внутри функции данных из вызывающей функции. В общем случае при написании функции, предназначенной для изменения массива, не указывайте const при объявлении параметра тина массива. Если же вы пишете функцию, не предназначенную для модификации массива, применяйте ключевое слово const при объявлении параметра типа массива.
В программе, показанной в листинге 10.14, одна функция отображает массив, а другая умножает каждый элемент массива на заданное значение. Поскольку первая функция не должна изменять массив, в ней используется const. Из-за того, что вторая функция намерена модифицировать массив, ключевое слово const в ней отсутствует.
Массивы и указатели 395
Листинг 10.14. Программа arf .с
Ниже приведен вывод:
Исходный массив dip:
20.000 17.660 8.200 15.300 22.220 Массив dip после вызова функции mult_array() :
50.000 44.150 20.500 38.250 55.550
Обратите внимание, что типом обеих функций является void. Функция mult_ array() предоставляет новые значения массиву dip, но не за счет применения механизма return.
Дополнительные сведения о ключевом слове const
Вы уже знаете, что ключевое слово const можно использовать для создания символических констант:
const double PI = 3.14159;
То же самое можно было бы сделать с помощью директивы #def ine, но ключевое слово const дополнительно позволяет создавать константные массивы, константные указатели и указатели на константы.
396 глава 10
В листинге 10.4 продемонстрировано применение ключевого слова const для защиты массива от модификации:
#define MONTHS 12
const int days [MONTHS] = {31, 28, 31, 30, 31,30, 31,31, 30,31, 30, 31};
Если впоследствии попытаться в коде изменить массив, на этапе компиляции будет сгенерировано сообщение об ошибке:
days[9] =44; /* ошибка на этапе компиляции */
Указатели на константы не могут использоваться для изменения значений. Взгляните на следующий код:
double rates[5] = [88.99, 100.12, 59.45, 183.11, 340.5); const double * pd = rates; // pd указывает на начало массива
Вторая строка кода объявляет, что значение типа double, на которое указывает pd, является const. Это означает, что pd нельзя применять для изменения значений, на которые он указывает:
*pd =29.89; //не разрешено
pd[2] = 222.22; // не разрешено
rates[0] = 99.99; // разрешено, т.к. rates не является const
Независимо от того, какая форма записи используется — с указателем или с массивом, pd не разрешено применять для изменения данных, на которые он указывает. Тем не менее, поскольку массив rates не был объявлен как константа, вы можете по- прежнему использовать rates для изменения значений. Кроме того, обратите внимание, что можно сделать так, чтобы pd указывал на что-нибудь другое:
pd+ +; /* теперь pd указывает на rates [1] -- разрешено */
Указатель иа констан ту обычно передается в виде параметра функции для сообщения о том, что функция не будет его применять в целях изменения данных. Например, функция show_array() из листинга 10.14 могла бы иметь такой прототип:
void show_array(const double *ar, int n);
Существует несколько правил, которые вы должны соблюдать, присваивая указатели и используя ключевое слово const. Прежде всего, указателю на константу допускается присваивание адреса либо константных, либо неконстантных данных:
double rates [5] = {88.99, 100.12, 59.45, 183.11, 340.5}; const double locked[4] = {0.08, 0.075, 0.0725, 0.07}; const double * pc = rates; // допустимо pc = locked; // допустимо
pc = &rates[3]; // допустимо
Тем не менее, обычным указателям могут быть присвоены только адреса неконстантных данных:
double rates[5] = {88.99, 100.12, 59.45, 183.11, 340.5}; const double locked[4] = {0.08, 0.075, 0.0725, 0.07}; double * pnc = rates; // допустимо
pnc = locked; //не допустимо
pnc = &rates[3]; // допустимо
Это обоснованное правило. Иначе указатель можно было бы применять для изменения данных, которые должны быть константными.
Массивы и указатели 397
Практическим следствием этих правил является то, что функция наподобие show array() может принимать в качестве фактических аргументов имена обычных массивов и константных массивов, поскольку каждый из них может быть присвоен указателю на константу:
Читать дальшеИнтервал:
Закладка: