Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование / WORD / Лекции по ЯП (часть 3).doc
Скачиваний:
135
Добавлен:
15.04.2015
Размер:
1.34 Mб
Скачать

Массивы указателей

Массив — это совокупность элементов данных одного типа под единым именем. Указатели тоже являются элементами данных определенных типов, поэтому их также можно организовывать в массивы. В,, некоторых ситуациях такие программные конструкции могут оказаться очень мощными и полезными.

Пожалуй, самым распространенным применением массивов указателей следует считать массивы символьных строк. Объявив и инициализировав массив указателей типа char, можно манипулировать сразу большим количеством строк с помощью этого массива. Каждый элемент массива указывает на отдельную строку, поэтому их перебор, например, в цикле дает доступ ко всем строкам по очереди.

Массивы указателей типа char

Следующий оператор объявляет массив из десяти указателей типа char:

char *message[10];

Каждый элемент массива message является указателем типа char. Объявление можно совместить с инициализацией и выделением памяти для строк:

char *message[10] = { "Один", "Два", "Три" };

Этот оператор выполняет следующие действия.

Размешает в памяти массив из десяти элементов с именем message; каждый элемент массива message является указателем типа char.

Выделяет пространство в памяти (неважно, где именно — это забота компилятора) и размещает в нем три заданные строки, завершая каждую нулевым символом.

Инициализирует указатель message[0] адресом первого символа строки "Один", message[1] — адресом первого символа "Два", message[ 2 ] — первого символа "Три".

Инициализация и использование массива указателей типа char:

int count;

char *message[3] = { "Один", "Два", "Три" };

for (count = 0; count < 3; count++)

printf("%s ", message[count]);

Передача массива указателей в функцию:

void print_strings(char *p[], int n);

i:

main()

{

char *message[3] = { "Один", "Два", "Три" };

print_strings(message, 3);

}

void print_strings(char *p[], int n)

{

int count;

for (count = 0; count < n; count++)

printf("%s ", p[count]);

}

Функция print_strings() принимает два аргумента. Один из них — это массив указателей типа char, а второй — количество элементов в массиве. Таким образом, функция print strings () может использоваться для вывода на экран строк из массива указателей.

Указатели на функции

Указатели на функции — это дополнительное гибкое средство вызова функций.

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

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

Объявление указателя на функцию

Общая форма этого объявления:

тип (*ptr to_func)писок_параметров);

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

int (*func1)(int x); объявляется указатель funcl на функцию, принимающую один аргумент типа int и возвращающую значение того же типа.

void (*func2)(double y, double z); объявляется указатель func2 на функцию с двумя аргументами типа double и возвращаемым значением типа void.

char (*func3)(char *p[]);объявляется указатель func3 на функцию, которая принимает массив указателей типа char и возвращает значение типа char.

void (*func4)(); переменная func4 объявлена как указатель на функцию без аргументов и с пустым типом (void) возвращаемого значения.

Зачем нужны скобки вокруг имени указателя? Почему бы не записать, например, следующее:

int *funcl(int x);

Получим функцию, возвращающую указатель.

Инициализация и использование указателя функцию

Единственное, что должно строго соблюдаться при инициализации — это соответствие возвращаемого типа и списка параметров функции. Например, в следующем фрагменте объявляется и определяется функция, а также указатель на эту функцию:

float sq(float x); // Прототип функции.

float (*ptr)(float x); // Объявление указателя.

float sq(float x) // Определение функции.

{

return x*x;

}

Поскольку^функция sq() и указатель ptr имеют совпадающие списки параметров и возвращаемых значений, ptr можно инициализировать следующим образом:

ptr = sq;

Затем можно вызвать функцию с использованием указателя:

f = ptr(x);

sq() можно вызвать двумя способами: sq(6.6) и ptr(6.6).

Итак, имя функции без скобок является указателем на функцию. (Проведите аналогию с массивом, имя которого без скобок — тоже указатель.) Так зачем же нужно объявлять отдельный указатель на ту же самую функцию? Дело в том, что имя функции само по себе — указатель-константа, которую нельзя изменить. (Снова напрашивается параллель с массивами) В противоположность этому указатель является переменной, и ее значение можно изменять, как угодно. В частности, в разные моменты времени такая переменная может указывать на разные функции, если в этом возникнет необходимость.