C Урок 28. Указатели на структуры

 

 

 

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

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

Начнём потихоньку с этим разбираться. Способов опять же будет несколько.

Для начала создадим обычную классическую структуру

 

struct student

{

   char nm[60];

   unsigned char age;

   unsigned char course;

};

 

Создадим переменные её типа заполним её поля

 

struct student st1;

strcpy(st1.nm, "Иванов Иван Иванович");

st1.age = 18;

st1.course = 2;

 

И теперь объявим классический указатель на структуру, а вернее на переменную её типа

 

struct student *st1_p

 

Здесь всё так же, как и с указателями на любой другой тип.

Также стандартно мы привяжем к этому указателю адрес нашей переменной типа такой структуры

 

st1_p = &st1;

 

А вот дальше уже будет немного интереснее. Нам не очень интересен сейчас адрес структуры, нам интересно получить адреса её полей, вернее адреса полей переменной типа нашей структуры.

Конечно же мы можем это получить путём обычного разыменования указателя, то есть сначала его разыменовать, а потом получить стандартным способом доступ к полям разыменованной переменной, то есть через точку

 

(*st1_p).nm

(*st1_p).course

(*st1_p).age

 

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

 

->

 

Например, в таблице приоритетов операций такая стрелочка носит название 'Выбор элемента структуры или объединения по указателю'.

И теперь, используя такой оператор, мы спокойно можем обратиться к полям нашей структуры, имеющей указатель, вот таким образом

 

st1_p->nm

st1_p->course

st1_p->age

 

Стало гораздо симпатичнее, не правда ли?

Нам теперь не требуется никаких звёздочек и скобочек.

Будет ещё передача структур в качестве параметров в функциях с помощью их указателей, но это, скорее всего, в следующем уроке.

Ну и давайте тогда поиграемся с такими указателями в практическом проекте.

Проект мы также создадим из проекта прошлого урока с именем MYPROG27 и присвоим ему имя MYPROG28.

Откроем наш проект в Eclipse, произведём его первоначальную настройку и удалим весь наш код из функции main() за исключением возврата. Функция main() приобретёт вот такой вид

 

int main()

{

   return 0; //Return an integer from a function

}

 

Первым делом давайте весь функционал по работе с нашими студентами переместим в отдельный модуль. Для этого сначала создадим и присоединим к проекту заголовочный файл student.h следующего содержания

 

 

А также создадим файл и тоже присоединим к проекту с именем student.c со следующим содержимым

 

 

Думаю, как подключить это всё грамотно в Makefile, мы знаем, но тем не менее на всякий случай вот текст нашего Makefile с подключенным модулем полностью

 

 

Откроем файл main.c и подключим наш модуль

 

 

Объявления всех структур также удалим.

Функцию addStudent удалим тоже вместе с телом и прототипом, она пока нам не нужна.

Объявление вот этого пользовательского типа также удалим

 

typedef unsigned int my_int32;

 

Пока стандартным способом создадим переменную типа нашей структуры и стандартным способом заполним её поля

 

 

Создадим указатель типа нашей структуры и присвоим сразу ему адрес нашей переменной

 

 

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

 

 

Запустим нашу программу на выполнение

 

 

Всё отлично вывелось. То есть такой способ доступа к полям структур через разыменование указателя на них тоже имеет право на существование.

Создадим ещё одну переменную структуры, аналогично присвоим значения полям, создадим переменную-указатель, присвоив ей адрес нашей переменной

 

 

 

Теперь выведем значения полей, используя уже оператор-стрелочку

 

 

Испытаем доступ, запустив проект на выполнение

 

 

Также всё прекрасно работает.

Создадим ещё одного такого студента с указателем, только заполним его поля тоже с помощью такого же оператора и выведем поля в консоль

 

 

Проверим, как это сработало

 

 

Всё отлично.

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

Закомментируем весь наш код, который мы ввели в функции main(), а также закомментируем объявление структуры в файле student.h

 

 

Вернёмся в файл main.c и в функции main() теперь объявим одновременно и структуру и переменную с помощью вот такого кода

 

 

Причём мы даже можем использовать для создания переменной неименованную структуру, то есть вот так

 

 

Только разница будет в том, что мы не сможем тогда объявлять ещё переменные типа этой структуры, будет только одна переменная или несколько через запятую. Мы планируем создать только одну переменную, поэтому можем оставить такой тип. Но мы тогда не создадим указатель, поэтому оставим предыдущее именованное объявление.

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

 

 

Проверим

 

 

По прежнему всё прекрасно работает.

Закомментируем и этот код.

В файле student.h объявим тип структуры через typedef

 

 

Вернёмся в функцию main() файла main.c, создадим переменную нашего типа, указатель на неё, с помощью которого также заполним её поля и выведем их в консоль

 

 

Разница с предыдущими кодами здесь лишь в ненадобности использования ключевого слова struct, но по моим практическим наблюдениям, такой вид структур и указателей на переменные их типов используется чаще всего.

Проверим работу кода

 

 

 

Всё работает точно так же.

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

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

Всем спасибо за внимание!

 

Предыдущий урок Программирование на C Следующий урок

Исходный код

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

C Указатели на структуры

2 комментария на “C Урок 28. Указатели на структуры
  1. Нодир:

    Добрый день! Как установить заголовочный файл graphics.h или самостоятельно написоний мное header файлы через командную строку cmd в папку C:\MinGW\include. Проста так закинул не работает!

    • Фёдор:

      А зачем Вы закидываете его именно туда, положите его в инклюды внутри вашего проекта, для этого надо будет поправить make файл:

      1)Сделать из него объектник

      graphics.o: src/graphics.c inc/graphics.h
      $(CC) -Iinc -O0 -g3 -Wall -c src/graphics.c
      $(CC) -Iinc -masm=intel -g3 -Wall -c src/graphics.c -S

      2)Добавить связь с ним при компиляции main

      main.o: src/main.c inc/main.h inc/ariph.h inc/utils.h inc/student.h inc/graphics.h
      $(CC) -Iinc -O0 -g3 -Wall -c src/main.c
      $(CC) -Iinc -masm=intel -g3 -Wall -c src/main.c -S

      3)И в зависимости при окончательной сборки

      all: main.o ariph.o utils.o graphics.o
      $(CC) -o pointer_struct.exe main.o ariph.o utils.o graphics.o

      А вообще советую посмотреть предыдущие лекции про make файлы, там все подробно расписано.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*