Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015

Тут можно читать онлайн Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - бесплатно полную версию книги (целиком) без сокращений. Жанр: Прочая старинная литература, издательство Вильямс, год 0101. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.

Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - описание и краткое содержание, автор Стивен Прата, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать книгу онлайн бесплатно, автор Стивен Прата
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

*(zippo+2) <-третий элемент, представляющий собой массив из двух int,

следовательно, это адрес его первого элемента, т.е. значения int *(zippo+2) + 1 <-адрес второго элемента в массиве из двух int, также значение int *(*(zippo+2) +1)<-значение второго int в третьей строке (zippo[2] [1] )

Смысл этой причудливой формы с указателями заключается вовсе не в том, что ее можно применять вместо более простой записи zippo [2] [1]. Смысл в том, что при наличии указателя на двумерный массив и необходимости извлечь значение можно использовать более прос тую форму записи в виде массива, а не форму с указателями.

На рис 10.5 показано еще одно представление отношений между адресами массива, содержимым массива и указателями.

400 Глава 10

Рис 105 Массив из массивов Указатели на многомерные массивы Как бы вы - фото 308

Рис. 10.5. Массив из массивов

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

Как бы вы объявили переменную pz типа указателя, которая может указывать на двумерный массив, такой как zippo? Указатель подобного рода мог бы применяться, например, при написании функции, которая имеет дело с массивами вроде zippo. Достаточно ли будет типа указателя на int? Нет. Такой тип совместим с zippo [0], который указывает на одиночное значение int. Но zippo — это адрес его первого элемента, который сам является массивом из двух значений int. Отсюда следует, что pz должен указывать на массив с двумя элементами int, а не на одиночное значение int. Вот как можно поступить:

int (* pz)[2]; // pz указывает на массив из 2 значений int

Приведенный оператор определяет, что pz представляет собой указатель на массив из двух значений типа int. Для чего здесь нужны круглые скобки? Дело в том, что скобки[] имеют более высокий приоритет, чем *. Это значит, что в объявлении вида

int * рах [2]; // рах - массив из двух указателей на int

сначала используются квадратные скобки, делая рах массивом с какими-то двумя элементами. Затем применяется операция *, превращая рах в массив из двух указателей. Наконец, использование int делает рах массивом из двух указателей на int. Приведенное объявление создает Дед указателя на одиночные значения int, но в пер воначальной версии круглые скобки обеспечивают применение операции * первой, создавая один указатель на массив из двух значений int. В листинге 10.16 показано, что такой указатель можно использовать подобно исходному массиву.

Листинг 10.16. Программа zippo2.c

Массивы и указатели 401 Вот новый вывод pz 0x0064fd38 pz 1 - фото 309

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

Вот новый вывод pz 0x0064fd38 pz 1 0x0064fd40 pz0 0x0064fd38 pz - фото 310

Вот новый вывод:

pz = 0x0064fd38, pz + 1 = 0x0064fd40 pz[0] = 0x0064fd38, pz [0] + 1 = 0x0064fd3c *pz = 0x0064fd38, *pz + 1 = 0x0064fd3c pz[0][0] = 2 *pz[0] = 2 **pz = 2 pz [2] [1] = 3 *(*(pz+2) + 1) = 3

И снова в своей системе вы можете получить другие адреса, но взаимосвязи останутся такими же. Как и было обещано, форму записи наподобие pz [2] [1] можно применять, даже если pz является указателем, а не именем массива. Говоря в общем, вы можете представлять отдельные элементы, используя форму записи с участием массива или указателей либо с именем массива, либо с указателем:

zippofm][n] == *(*(zippo + m) + n) pz [m] [n] == * (* (pz + m) + n)

Совместимость указателей

Правила прнсванвання одного указателя другому строже таких правил для числовых типов. Например, вы можете присвоить значение int nеременной double, не используя преобразование типа, но нельзя сделать то же самое для указателей на эти два типа:

int n = 5; double х; int * pl = &n; double * pd = &х;

х = n; // неявное преобразование типа

pd = pl; // ошибка на этапе компиляции

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

int * pt; int (*ра) [3]; int ar1[2] [3]; int ar2[3] [2];

int **р2; // указатель на указатель

Взгляните на показанный далее код:

pt = &ar1 [0][0]; // оба - указатели на int

pt = &ar1 [0]; // оба - указатели на int

pt = arl; // недопустимо

pa = arl; // оба - указатели на int[3]

картинка 311 картинка 312

// недопустимо // оба - указатели на int // оба - указатели на int // недопустимо

Обратите внимание, что во всех недопустимых случаях присваивания вовлечены два указателя, которые не указывают на один и тот же тип. Например, pt указывает на одиночное значение int, но arl — на массив из трех значений int. Аналогично, ра указывает на массив из двух значений int, следовательно, он совместим с arl, но не с ar2, который указывает на массив из двух значений int.

Два последних примера немного запутаны. Переменная р2 представляет собой указатель на указатель на тип int, в то время как ar2 — это указатель на массив из двух значений int (или, выражаясь короче, указатель на массив int [2]). Таким образом, р2 и ar2 — разные типы, и вы не можете присвоить ar2 указателю р2. Но *р2 имеет тип указателя на int, что обеспечивает его совместимость с ar2 [0]. Вспомните, что ar2 [0] является указателем на свой первый элемент, ar2 [0] [0], что делает ar2 [0] также и типом указателя на int.

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

int х = 20; const int у = 23; int * p1 = &х; const int * р2 = &у; const int ** рр2;

p1 = р2; // небезопасно — присваивание константного значения неконстантному

р2 = p1; // допустимо -- присваивание константного значения константному рр2 = &р1; // небезопасно -- присваивание вложенных типов указателей

Как вы видели ранее, присваивание указателя const указателю, отличному от const, не является безопасным, т.к. новый указатель мог бы применяться для изменения данных типа const. Хотя код и скомпилируется, возможно, с выдачей предупреждения, результат его выполнения не определен. Но присваивание указателя не const указателю const допустимо при условии, что вы имеете дело только с одним уровнем косвенности:

р2 = p1; // допустимо -- присваивание неконстантного значения константному

Тем не менее, такие присваивания перестают быть безопасными, когда вы переходите к двум уровням косвенности. Например, вы могли бы написать такой код:

const int **рр2; int *р1;

const int n = 13;

рр2 = &р1; // разрешено, но квалификатор const игнорируется

*рр2 = &n; // допустимо, оба const, но p1 устанавливается указывающим на п

*р1 =10; // допустимо, но производится попытка изменить константу п

Что происходит? Как упоминалось ранее, в стандарте говорится, что результат изменения константных данных с использованием указателя, отличного от const, не определен. Например, компиляция короткой программы с этим кодом с помощью gcc в среде Terminal (интерфейс OS X для доступа к лежащей в основе системе Unix) приводит к тому, что n получает значение 13, но применение компилятора clang в той же среде обеспечивает для n значение 10. При этом оба компилятора предупреждают о несовместимых типах указателей. Разумеется, предупреждения можно игнорировать, но лучше не доверять результатам выполнения этой программы.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Стивен Прата читать все книги автора по порядку

Стивен Прата - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Язык программирования C. Лекции и упражнения (6-е изд.) 2015 отзывы


Отзывы читателей о книге Язык программирования C. Лекции и упражнения (6-е изд.) 2015, автор: Стивен Прата. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x