Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Решенные оветы на теорию Си.docx
Скачиваний:
4
Добавлен:
01.03.2025
Размер:
166.91 Кб
Скачать

15. Массивы и указатели. Передача и возврат параметров в функцию.

В Си существует тесная связь между указателями и массивами, так что эти средства лучше рассматривать вместе. Любой доступ к элементу массива, осуществляемый операцией индексирования, может быть выполнен с помощью указателя.

int a[10]; int *pa;

в результате присваивания

pa = &a[0]; - рa будет указывать на 0 элемент a, иначе говоря, pa будет содержать адрес элемента a[0].

Теперь присваивание

x = *pa; - будет копировать содержимое a[0] в x.

Если pa указывает на некоторый элемент массива,то

*(pa+i) - есть содержимое a[i]

После присваивания

pa = &a[0]; ра и a имеют одно и то же значение. Т.к. имя массива является синонимом расположения его начального элемента, то

      • pa=&a[0] <=> pa = a;

      • a[i] <=> *(a+i);

      • pa[i] <=> *(pa+i)

Вывод: элемент массива можно изображать как в виде указателя со смещением, так и в виде имени массива с индексом.

Между именем массива и указателем, выступающим в роли имени массива, существует одно различие. Указатель - это переменная, поэтому можно написать pa=a или pa++. Но имя массива не является переменной, и записи вроде a=pa или a++ не допускаются.

Если имя массива передается функции, то последняя получает в качестве аргумента адрес его начального элемента. Внутри вызываемой функции этот аргумент является локальной переменной, содержащей адрес.

Передача и возврат параметров в функцию

Определяя функцию, мы описываем ее параметры - "формальные" аргументы. Фактически это новые объекты программы, и при вызове функции для них выделяется отдельная область памяти. Такие объекты: переменные, массивы.

При вызове функции в качестве списка параметров выступают "фактические аргументы": константы, переменные и более сложные выражения - их значение вычисляется и присваивается формальным аргументам.

Возвращаемое значение можно присвоить переменной или использовать как часть некоторого выражения.

Оператор return завершает выполнение вызываемой функции и передает управление вызывающей функции (оператору, следующему за вызовом).

Указатели в качестве аргументов

Чтобы с помощью return к вернуть две или более величины,нужно воспользоваться переменными типа указатель.

При вызове функции будет происходить передача адресов при помощи операнда &

Массивы в качестве аргументов

При описании формальных параметров границы одномерных массивов можно опускать. При вызове функции для самого параметра массива память не отводится, передаваемым значением является указатель на первый элемент массива.

Если функции нужно передавать двумерный массив, то описание аргумента в этой функции должно обязательно включать в себя размер строки массива, а размер столбцов не важен, т.к. массив передается с помощью ссылки (указателя).

16. Указатели на функции. Особенности использования.

В языке Си сама функция не может быть значением переменной, но можно определить указатель на функцию. С ним уже можно обращаться как с переменной: передавать его другим функциям, помещать в массивы и т.п.

Код функции в персональном компьютере занимает физическую память. В этой памяти есть точка входа, которая используется для того, чтобы войти в функцию и запустить ее на выполнение. Указатель на функцию как раз и адресует эту точку входа. Это уже будет обычная переменная и с ней можно делать все, что можно делать с переменной.

Через указатель можно войти в функцию, т.е. запустить ее на выполнение. Объявление вида:

int (*f)( );

говорит о том, что f - это указатель на функцию, возвращающую целое значение. Первая пара скобок необходима, без них int *f( ); означало бы, что f - функция, возвращающая указатель на целое значение. После объявления указателя на функцию в программе можно использовать объекты: *f - сама функция; f - указатель на функцию. Для любой функции ее имя (без скобок и аргументов) является указателем на эту функцию.

int (*p)(const char *, const char *); /* указатель на функцию */ p = strcmp; /* присваивает адрес функции strcmp указателю p */

Это объявление сообщает компилятору, что p — это указатель на функцию, имеющую два параметра типа const char * и возвращающую значение типа int. Скобки вокруг p необходимы для правильной интерпретации объявления компилятором. Подобная форма объявления используется также для указателей на любые другие функции, нужно лишь внести изменения в зависимости от возвращаемого типа и параметров функции.

void check(char *a, char *b, int (*cmp)(const char *, const char *)) { printf("Проверка на совпадение.\n"); if(!(*cmp)(a, b)) printf("Равны"); else printf("Не равны"); }

Теперь рассмотрим функцию check(). В ней объявлены три параметра: два указателя на символьный тип (a и b) и указатель на функцию cmp. Обратите внимание на то, что указатель функции cmp объявлен в том же формате, что и p. Поэтому в cmp можно хранить значение указателя на функцию, имеющую два параметра типа const char * и возвращающую значение int. Как и в объявлении p, круглые скобки вокруг *cmp необходимы для правильной интерпретации этого объявления компилятором.

Внутри check() выражение

(*cmp)(a, b)

вызывает функцию strcmp(), на которую указывает cmp, с аргументами a и b. Скобки вокруг *cmp обязательны. Существует и другой, более простой, способ вызова функции с помощью указателя:

cmp(a, b);

Вызов функции check() можно записать, используя непосрественно имя strcmp():

check(s1, s2, strcmp);

В этом случае вводить в программу дополнительный указатель p нет необходимости.