Урок 8.1.2. Операции над структурами
8.1.2. Операции над структурами
После того, как рассмотрены способы описания структурных переменных и массивов, естественно рассмотреть, каким образом их можно обрабатывать в программах пользователя.
К структурным данным в Си применимы следующие операции:
Название операции | Знак операции |
выбор элемента через имя (селектор) | . (точка) |
выбор элемента через указатель (селектор) | -> (минус и знак больше) |
присваивание | = |
взятие адреса | & |
1. Для получения доступа к элементу структурной переменной через ее имя используется символ точка, обозначающий операцию выбор поля структуры. Например, для структурных переменных pos, pos1 и массива pos2, описанных как
struct RECORD
{ int num; /* Табельный номер */
char name[20]; /* Имя служащего */
float wage; /* Зарплата в месяц */
};
struct RECORD pos, pos1, pos2[5];
pos.num осуществляет доступ к полю num структурной переменной pos, а pos1.num – то же поле, но в составе структурной переменной pos1. Эти элементы можно записывать в любых выражениях Cи, допускающих использование переменных целого типа, так как элемент num структурного шаблона RECORD имеет тип int:
pos.num=67;
if((pos.num < 1330)&&(pos1.num == 1340))...
Аналогично pos.wage и pos1.wage – переменные с плавающей точкой, а pos.name и pos1.name есть констаны-указатели на символьные строки, ибо name – это имя массива.
Для массива структур перед выделением элемента структуры необходимо указать номер элемента массива, для которого выделяется элемент структуры:
pos2[0].num - элемент num из первого элемента массива;
pos2[3].wage - элемент wage из четвертого элемента массива.
Обратите внимание, что индекс массива записывается сразу после имени массива, а не в конце выражения, то есть запись pos2.num[0] – неверна.
В случае вложенных структур операция выделения элемента применяется необходимое число раз. Например, для уже встречавшихся описаний:
struct NAME
{ char fam[10]; //фамилия
char im[10]; //имя
};
struct RECORD
{ int num;
struct NAME name;
float wage;
};
struct RECORD pos, pos1, pos2[5];
выражение pos.name.fam адресует элемент fam структурной переменной name, которая входит в структурную переменную pos.
2. Присваивание. Можно использовать имена структурных переменных в качестве операндов операции присваивания. При этом обе структурные переменные (слева и справа от знака операции присваивания = ) должны быть описаны с помощью одного и того же структурного шаблона. Так, для структурных переменных pos, pos1 и массива pos2, описанных выше, допустимы следующие операторы:
pos=pos1;
pos1=pos2[1];
pos2[2]=pos;
Выполнение подобных присваиваний заключается в копировании значений всех элементов (в том числе и массивов) правой структурной переменной в соответствующие элементы левой структурной переменной, то есть мы обращаемся к структурной переменной как к единой совокупности значений.
3. К структурным переменным, точно так же, как и к обычным переменным, применима операция взятия адреса, обозначаемая знаком & . В качестве примера использования операции взятия адреса рассмотрим все тот же структурный шаблон RECORD и описание структурной переменной w:
struct RECORD
{ int num;
char name[20];
float wage;
};
struct RECORD w;
После того как описан структурный шаблон, то есть определен тип struct RECORD, можно описать указатель на этот тип. Описание указателя производится аналогично описанию указателей на другие типы данных:
struct RECORD *ptrw;
Итак, у нас описаны структурная переменная w типа struct RECORD и указатель ptrw на тип struct RECORD. Теперь к структурной переменной w мы можем применить операцию взятия адреса и присвоить полученный адрес указателю рtrw:
ptrw = &w;
Заметим, что то же самое можно сделать и по-другому. При описании указатель может быть инициализирован адресом любой структурной переменной соответствующего типа, например, в нашем случае так:
struct RECORD *ptrw=&w;
Теперь ptrw ссылается на структурную переменную w. Каким же образом можно использовать указатель ptrw для получения значения элемента структурной переменной w? . Отвечая на этот вопрос, рассмотрим операцию выделения элемента через указатель.
4. Выделение элемента структурной переменной через указатель можно осуществить двумя способами. Первый, наиболее часто применяемый способ, использует знак операции -> (операция -> записывается как минус, за которым следует символ отношения больше ). Действие операции -> заключается в следующем:
Если P есть указатель на структурный тип и P содержит адрес переменной S такого же структурного типа, тогда обращение P-><элемент_структуры> относится к конкретному элементу структурной переменной S. |
В условиях предыдущего описания данных и инициализации указателя получим обращения :
ptrw->num к элементу num структурной переменной w;
ptrw->name к элементу name структурной переменной w;
ptrw->wage к элементу wage структурной переменной w.
Обратим внимание на то, что в данном случае для обращения к элементу нельзя записать, например, ptrw.num, так как ptrw не является именем структурной переменной.
Рассмотрим второй способ. Второй способ обращения к элементу структурной переменной через ее указатель заключается в применении уже известной нам операции косвенной адресации. Суть состоит в следующем: поскольку ptrw является указателем на структурную переменную w, то, по определению операции косвенной адресации, использование выражения *ptrw равносильно использованию переменной w: и то и другое реализует обращение к одному и тому же полю памяти. Следовательно, (*ptrw).num представляет собой обращение к элементу num структурной переменной w. Скобки здесь обязательны, так как операция . (точка) имеет приоритет выше чем операция * (звездочка). Таким образом, обращения к полям переменной w можно переписать так:
(*ptrw).num к элементу num структурной переменной w;
(*ptrw).name к элементу name структурной переменной w;
(*ptrw).wage к элементу wage структурной переменной w.
Заметим, что первый способ более распространен, так более лаконечен и -> выполняет роль селектора при указателе на стктурную переменную.
5. Обращаться к полям структурной переменной можно и при помощи полей-функций. При этом функции имеют прямой доступ к полям структурной переменной, операцию селектор использовать не надо. Ниже приведен фрагмент программы, в которой поля–функции исполюзуются для печати значений перменной (функция print_rec()) и для изменения значения поля wage (функция wage_raise()).
struct RECORD{ int num; // Табельный номер char name[20]; // Имя служащего float wage; // Зарплата в месяц void print_rec() { printf("num=%d\n name=%s\nwage = %f \n\n",num,name,wage); } void init(int num1, char *name1, float wage1) { num = num1; strcpy(name,name1); wage = wage1; } float wage_raise(int d) { return wage = wage*d; } }; //объявление и инициализация стрктурной переменной RECORD r ={1328, "Ivanov Ivan",2}; //печать значений стрктурной переменной printf(" %d \n %s \n %f \n\n",r.num,r.name, r.wage); //инициализация структурной переменной r.init(1329, "Petrov Petr", 20); //печать значений структурной переменной r.print_rec(); //изменение значения поля структурной переменной r.wage = r.wage * 5; //изменение значения поля структурной переменной r.wage_raise(5); wage_raise(5); //ошибка, обращаться к полям–функциям //можно только через структурную переменную |
Оставить комментарий