Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
typedef struct {double х; double у,() rect;
Предположим, что определенный посредством typedef идентификатор применяется так, как показано ниже:
rect г 1 = {3.0, 6.0};
rect г2;
Этот код транслируется в следующие операторы:
struct {double х; double у;} rl = {3.0, 6.0};
struct {double х; double у;} г2;
r2 = r 1;
Если две структуры объявлены без дескриптора, нос идентичными членами (совпадают имена членов и типов), то в С эти две структуры считаются имеющими один и тот же тип, поэтому присваивание rl переменной г2 является допустимой операцией.
Структуры и другие формы данных 611
Вторая причина использования typedef связана с тем, что имена typedef часто применяются для сложных типов. Например, объявление
typedef char (* FRPTC()) [5];
делает FRPTC идентификатором типа, который является функцией, возвращающей указатель на массив из 5 элементов char. (В следующем разделе обсуждаются причудливые объявления.)
При использовании средства typedef имейте в виду, что оно не создает новые типы; вместо этого вы получаете всего лишь удобные метки. Это значит, например, что переменные, применяющие созданный нами тип STRING, могут передаваться в качестве аргументов функциям, которые ожидают тип указателя на char.
Благодаря структурам, объединениям и typedef, язык С предоставляет инструменты для эффективной и переносимой обработки данных.
Причудливые объявления
Язык С позволяет создавать сложные формы данных. Хотя мы придерживаемся простейших форм, все же имеет смысл отметить некоторые из доступных возможностей. Когда вы делаете объявление, имя (или идентификатор) можно изменить, добавив модификатор.
Одновременно в С разрешено указывать несколько модификаторов, что, в свою очередь, позволяет создавать широкое разнообразие типов, как продемонстрировано в следующих примерах:
int board[8] [8]; // массив из массивов значений int
int ** ptr; // указатель на указатель на int
int * risks[10]; // 10-элементный массив указателей на int
int (* rusks)[10]; // указатель на массив из 10 значений int
int * oof[3][4]; // массив размером 3x4 указателей на int
int (* uuf) [3] [4]; // указатель на массив размером 3x4 значений int
int (* uof[3]) [4]; // 3-элементный массив указателей на 4-элементные
// массивы значений int
Трюк по распутыванию таких объявлений заключается в определении порядка, в котором необходимо использовать модификаторы. Описанные ниже правила должны дать вам необходимое представление об этом.
1. Скобки[], которые обозначают массив, и скобки(), обозначающие функцию, имеют одинаковый приоритет. Этот приоритет выше, чем у операции разыменования *, которая означает, что следующее объявление делает risks массивом указателей, а не указателем на массив:
int * risks[10];
2. Скобки[] и() имеют ассоциативность слева направо. Таким образом, приведенное ниже объявление делает goods массивом из 12 массивов, содержащих по 50 значений int, а не массивом из 50 массивов с 12 элементами типа int:
int goods[12] [5 0];
глава 14
3. Скобки[] и() имеют один и тот же приоритет, но из-за их ассоциативности слева направо в следующем объявлении * и rusks группируются вместе перед применением квадратных скобок. Это означает, что объявление делает rusks указателем на массив из 10 значений int: int (* rusks) [10];
Давайте воспользуемся этими правилами для разбора показанного далее объявления:
int * oof[3][4];
Конструкция [3] имеет более высокий приоритет, чем *, и поскольку действуег правило ассоциативности слева направо, она применяется перед [4]. Таким образом, oof — это массив из трех элементов. Следующим по порядку идет [4], поэтому элементами oof являются массивы из четырех элементов. Модификатор * сообщает о том, что эти элементы представляют собой указатели. Картину завершает int: итак, oof представляет собой трехэлементный массив, состоящий из четырехэлементных массивов указателей на int, или для краткости массив 3x4 указателей на int. Память выделяется под 12 указателей.
Теперь взгляните на следующее объявление:
int {* uuf)[3][4];
Круглые скобки приводят к тому, что модификатор * получает первый приоритет, благодаря чему uuf становится указателем на массив 3x4 значений int. Память выделяется только для одного указателя.
Эти правила также позволяют иметь такие типы:
char * fump(int); // функция, возвращающая указатель на char
char (* frump)(int); // указатель на функцию, возвращающую тип char
char (* f1ump[3]) (int); // массив из 3 указателей на функции, которые
// возвращают тип char
Все три функции принимают аргумент int.
Средство typedef можно использовать для построения последовательности связанных друг с другом типов данных:
typedef int arr 5[5]; typedef arr5 * р_arr5; typedef p_arr5 arrрЮ [10];
arr5 togs; // togs - массив из 5 значений int
р_arr5 р2; // р2 - указатель на массив из 5 значений int
arrрЮ ар; //ар - массив, содержащий 10 указателей на массивы из 5 значений int
Когда вы освоитесь с созданием структур подобного рода, возможности для самых причудливых объявлений действительно возрастут. Что же касается их применений, то мы оставляем эти вопросы за более сложными источниками.
Функции и указатели
Как продемонстрировало обсуждение объявлений, допускается объявлять указатели на функции. Возможно, вас интересует, в чем они могут быть полезны. Обычно указатель на функцию используется в качестве аргумента в другой функции, сообщая ей, какую функцию применять. Например, сортировка массива предполагает сравнение двух элементов для выяснения того, какой из них должен следовать первым. В случае числовых элементов можно использовать операцию >. Но в целом элементом может быть строка или структура, что требует вызова специальной функции для выполнения
Структуры и другие формы данных 613
сравнения. Функция qsort() из библиотеки С спроектирована на работу с массивами любого вида при условии, что вы уведомите ее о том, какую функцию применять для сравнения элементов. С этой целью qsort() принимает в одном из своих аргументов указатель на функцию. Затем qsort() использует указанную функцию для сортировки значений определенного типа — будь он целочисленным, строкой или структурой.
Давайте подробнее рассмотрим указатели на функции. Прежде всего, что они означают? Скажем, указатель на int содержит адрес ячейки памяти, в которой может быть сохранено значение int. Функции также имеют адреса, поскольку реализация функции на машинном языке состоит из кода, загружаемого в память. Указатель на функцию может содержать адрес, помечающий начало кода функции.
Далее, когда вы объявляете указатель на данные, то должны объявить тип данных, на которые он указывает. При объявлении указателя на функцию необходимо объявить тип указываемой функции. Чтобы задать тип функции, понадобится указать сигнатуру функции, т.е. возвращаемый тип и типы параметров функции. Например, взгляните на следующий прототип:
Читать дальшеИнтервал:
Закладка: