C_Kurs_Lekt / C_II_семестр / 11-2_ФУНКЦИИ_2
.pdfЛысый Д.А. Основы программирования. Функции часть2 |
1 |
ФУНКЦИИ
Передача параметров
Существуют два способа передачи параметров функции — по значению и по ссылке. Все вызовы функций в С являются вызовами по значению.
При передаче параметров по значению (в функцию передается копия значения параметра) любые изменения, выполняемые в функции над значением параметра, существуют только внутри самой функции. Когда функция завершается, значение переменной, переданной по значению, оказывается неизменным.
При передаче параметров в функцию их значения размещаются в стеке и любые изменения, выполняемые в функции над значениями параметров, в действительности изменяют значения ячеек стека. При завершении выполнения функции стек освобождается, а следовательно, пропадают и изменения, сделанные функцией в ячейках стека.
Многих случаях нужно иметь возможность изменять одну или несколько переменных в вызывающей функции или передавать функции указатель на большой объект данных, чтобы избежать издержек, связанных с передачей параметра по значению (так как в этом случае создается и потом передается копия объекта). Для этих целей в С существует возможность вызова функции по ссылке, используюя указатели и операцию косвенной адресации.
Ñпомощью указателя в вызываемую функцию можно передать адрес любого объекта из вызывающей программы. Обычно для этой цели применяется операция взятия адреса (&) к переменной, значение которой будет изменяться.
Ñпомощью выполняемого в тексте функции разыменования указателя (операция косвенной ад-
ресации * ) мы получаем доступ к адресуемому указателем объекту из вызывающей программы. Рассмотрим программы использующие вызовы по значению и по ссылке.
/ * Вычисление êóба числа с использованием вызова по значению * / #include <stdio.h>
int cube (int); main () {
int number = 5;
printf("The original value of number is %d\n", number); number = cube(number);
printf("The new value of number is %d\n", number); return 0;
}
int cube(int n) {
return n * n * n; /* возводим в êóб лоêальнóю переменнóю n */
}
The original value of number is 5
The new value of number is 125
Вычисление êóба переменной с вызовом по значению /* Вычисление êóба переменной при помощи вызова по ссылêе */ #include <stdio.h>
void cube(int *); main () {
int number = 5;
printf ("The original value of number is %d\n", number); cube(&number) ;
printf("The new value of number is %d\n", number); return 0;
}
void cube(int *nPtr) {
*nPtr = *nPtr * *nPtr * *nPtr; /* вычисление êóба переменной number фóнêции main */
}
The original value of number is 5 The new value of number is 125
Лысый Д.А. Основы программирования. Функции часть2 |
2 |
Последовательность выполнения вызова по значению |
Последовательность выполнения вызова по ссылке |
Использование модификатора const с указателями
Модификатор const дает возможность программисту сообщить компилятору о том, что значение указанной переменной не должно изменяться.
Существует шесть вариантов использования (или не использования) модификатора const с параметрами функции — две при передаче параметра по значению и четыре при передаче параметра по ссылке.
Если передаваемое функции значение не изменяется (или не должно быть изменено) в теле функции, оно должно объявляться с модификатором const, чтобы гарантировать невозможность даже случайного изменения.
Если происходит попытка изменить значение, которое было объявлено с модификатором const, компилятор перехватывает эту попытку и выдает либо предупреждение, либо сообщение об ошибке, в зависимости от того, какой .компилятор вы используете.
Существует четыре способа передать функции указатель: изменяемый указатель на изменяемые данные, неизменяемый указатель на изменяемые данные, изменяемый указатель на неизменяемые данные и неизменяемый указатель на неизменяемые данные. Каждая из четырех комбинаций обеспечивает различный уровень привилегий доступа к данным.
Самый высокий уровень доступа предоставляется не-константным указателем на не-константные данные. В этом случае данные могут изменяться через разыменование указателя, а сам указатель может изменяться и ссылаться на другие элементы данных. Объявление указателя — не константы на не константные данные не содержит ключевого слова const. Такой указатель (char *) мог бы использоваться, например, при передаче строки как параметра функции, в которой используются арифметические операции над указателем при обработке или изменении каждого отдельного символа в строке.
Пример:
/* Преобразование символов нижнеãо реãистра в символы верхнеãо */ /* реãистра с использованием óêазателя - не êонстанты на данные, */ /* êоторые моãóт модифицироваться */
#include <stdio.h>
void convertToUppercase(char *); main (){
char string[] = "characters";
printf("The string before conversion is: %s\n", stnng); convertToUppercase(string);
printf("The string after conversion is: %s\n", stnng); return 0;
}
void convertToUppercase(char *s) { while (*s != '\0' ) {
Лысый Д.А. Основы программирования. Функции часть2 |
3 |
if (*s >= 'a' && *s <= 'z')
*s -= 32; /* преобразование ê верхнемó реãистрó */
++s; /* óвеличение s для перехода ê следóющемó символó */
}
}
The string before conversion is: characters The string after conversion is: CHARACTERS
Указатель — не константа на данные-константы (const char *) — это указатель, который может изменяться и ссылаться на любой объект данных соответствующего типа, но элемент данных, на которые он указывает, не может изменяться. Такой указатель мог бы использоваться для передачи массива в ка- честве аргумента функции, которая обрабатывает каждый элемент массива и при этом не изменяет данные. Пример1:
/* Посимвольный вывод строêи, использóющий */
/* не-êонстантный óêазатель на êонстантные данные * / #include <stdio.h>
void printCharacters(const char *); main () {
char string[] = "print characters of а string"; printf("The string is:\n"); printCharacters(string);
putchar('\n'); return 0;
}
void printCharacters(const char *s) {
for ( ; *s != '\0'; s++) /* циêл не инициализирóется */ putchar (*s);
}
The string is:
print characters of à string
Пример2:
/* Попытêа изменения данных при помощи */ /* неêонстантноãо óêазателя на данные-êонстанты */
#include <stdio.h> |
|
void f(const int *); |
|
main ( ) { |
|
int ó; |
|
f(&y); |
/* фóнêция f пытается выполнить изменение данных */ |
return 0; } |
|
void f(const int *x) {
*x = 100; /* нельз модифицировать объеêт данных типа const */
}
Compiling FIG7_12.C:
Error FIG7_12.C 17: Cannot modify à const object Warning FIG7_12.C 18: Parameter 'x' is never used
Указатель-константа на не-константные данные (int * const) — указатель, который всегда указывает на одно и то же место в памяти, а расположенные там данные могут изменяться. Такой указатель назначается по умолчанию для имени массива. Имя массива является указателем-константой на начало массива. Ко всем элементам массива можно обращаться и изменять их, используя имя массива и индекс. Константный указатель на не-константные данные может использоваться для передачи массива как параметра функции, которая обращается к его элементам, используя только индекс массива. Указатели, которые объявляются с модификатором const, должны быть инициализированы при объявлении (если такой указатель является параметром функции, он инициализируется переданным функции значе- нием).
/* |
Попытêа изменения óêазателя-êонстанты на */ |
|||||
/* |
не-êонстантные данные |
|
*/ |
I |
||
#include |
<stdio.h> |
|
|
|
||
main() { |
|
|
|
|
||
|
int |
x, ó; |
|
|
|
|
|
int * const ptr = &x; |
|
|
|
||
|
ptr |
= |
&y; |
|
|
|
|
return |
0; |
|
|
|
|
} |
|
|
|
|
|
|
|
Compiling FIG7_13.Ñ: |
|
|
|
||
|
Error FIG7_13.C 10: Cannot modify à const object |
|||||
|
Warning FIG7_13.C 12: |
'ptr' |
is |
assigned à value that is |
||
|
never used Warning FIG7_13.C |
12: |
,'y' is declared but never used |
Лысый Д.А. Основы программирования. Функции часть2 |
4 |
Минимальные права доступа предоставляет указатель-константа на константные данные. Такой указатель всегда указывает на то же самое место в памяти, а расположенные по этому адресу данные не могут модифицироваться. Этому варианту соответствует передача массива функции, которая только просматривает массив при помощи индекса и не изменяет его элементы. Пример, переменная-указатель ptr типа const int * const. Объявление читается справа налево и звучит так: «ptr — указатель-константа на целую константу».
/* Попытêа модифиêации óêазателя-êонстанты на */ /* данные-êонстанты */
#include <stdio.h> main () {
int x = 5, ó;
const int * const ptr = &x; *ptr = 7;
ptr = &y; return 0;
}
Compiling FIG7_14.C:
Error FIG7_14.C 10: Cannot modify à const object Error FIG7_14.C 11: Cannot modify à const object Warning FIG7_14.C 13: 'ptr' is assigned à value that is
never used Warning FIG7_14.C 13: ' y ' is declared but never used