
КЭкзCPP / СТРУКТУРЫ
.docxСТРУКТУРЫ
Структура – набор элементов почти произвольных типов
struct nameStruct
{
type1 name1;
type2 name2; …
typeN nameN;
} [var1, var2];
Переменная типа структуры определяется обычным образом
nameStruct variable1, variable2;
Например,
struct student
{
char* name;
unsigned mark[4];
unsigned age;
} Ivan, Nobody;
Доступ к конкретным полям структуры производится при помощи оператора “.”
Например,
cout<<”возраст студента ”<<Ivan.name<<” составляет ”<<Ivan.age<<endl;
Ivan.mark[0]=2;
Ivan.name = new char[20];
//cout<<student.age; - ОШИБКА – доступ через имя типа
Как и для массивов при определении может быть проведена инициализация
student urfu = {“Petr_Petrov”, {4,4,3,5}, 18};
Две структуры являются разными типами, даже если состоят из одинаковых элементов
Например,
struct One{int a; char ch};
struct Two{int a; char ch};
Поэтому
One x; …
Two y = x; - ОШИБКА требуется
y.a=x.a;
y.ch = x.ch;
Но если
One a, b;…
b=a; / /допустимо
int c = x; - ОШИБКА( x – не предопределенный тип)
Каждая структура должна иметь единственное определение в программе.
Размер типа структуры не обязательно равен сумме размеров элементов структуры. Часто объекты определенных типов выравниваются в машинах по аппаратно определяемым границам (на границу машинного слова например), так они обрабатываются быстрее. И появляются дыры, поэтому иногда меняют порядок элементов структуры (сначала перечисляют элементы с большим размером). При необходимости структуры помогают экономить память благодаря использованию битовых полей
объявление_поля : константное_выражение;
struct student{
char* name;
unsigned mark[4];
unsigned age;
};
может быть объявлена как (тип поля – целочисленный, конст_выр в битах)
struct student{
char* name;
unsigned mark[4];
unsigned age :8;
};
Имя тип можно использовать немедленно после его появления, до завершения всего объявления
struct Node{
char ch;
Node* next;
Node* prev;};
До полного завершения объявления структуры запрещается использовать ее имя для объявления других объектов
struct list{list my_list};
Структуры можно передавать в функции (и возвращать )
struct house
{
unsigned short reg_num;
char street[51];
char house_num[6];
bool parking;
};
void show_adress(house);
int main(){
house my_house;
my_house.reg_num = 66;
strcpy(my_house.street,"pr. Lenina");
strcpy(my_house.house_num,"51-a");
my_house.parking = false;
show_adress(my_house);
return 0;
}
void show_adress(house home)
{
cout << home.street<<", ";
cout<<home.house_num<<endl;
}
Можно объявлять массивы структур
house urgu[20];
или динамически
house * urgu = new house[20];
Таким образом, можно обращаться к элементам структуры через указатели
Например,
house* phouse;
phouse = &my_house;
phouse->parking = true;
cout<<my_house.parking; //cout<<phouse->parking;
Оператор “->” разыменования указателя на структуру эквивалентен записи (*phouse).parking = true;
Возможно и полезно использовать указатели, ссылки на структуры при вызовах функций.
Например,
int fun_struct(house* one, house& two);
Появляется возможность моделирования новых типов данных на базе уже имеющихся.
typedef struct
{
double x;
double y;
double z;
} coord;
coord my_point;
my_point.x = 2.; my_point.y = 2.1; mypoint.z = 3.14;
или массив координат точек //coord points[25];
пример работы с полиномом
struct dk{int deg; double k;};
dk* read_p(int&);
void show_p(dk*, int);
dk* add_p(dk*, dk*, int, int, int&);
void main()
{
dk *one, *two, *third;
int n_one,n_two,n_third;
one = read_p(n_one);
two = read_p(n_two);
show_p(one,n_one);
show_p(two,n_two);
//third=add_p(one,two,n_one,n_two,n_third);
//show_p(third, n_third);
delete [] one;
delete [] two;
//delete [] third;
}
dk* read_p(int& n)
{
cout<<"input number elementov ";
cin>>n; cout<<endl;
dk* p = new dk[n];
for(int i = n-1; i >-1; i--)
{
cout<<"input degree ";cin>>p[i].deg;
cout<<"input koeff ";cin>>p[i].k; cout<<endl;
}
return p;
}
void show_p(dk p[], int n)
{
for(int j=n-1; j>-1; j--)
if(p[j].deg!=0) {cout<<p[j].k<<"*x";
if(p[j].deg!=1) {cout<<'^'<<p[j].deg;};
if((j>0)&&p[j-1].k>0) cout<<'+';}
else cout<<p[j].k;
cout<<endl;
}
Структуры могут быть вложенными. Уровень вложенности не ограничивается.
Структуры используются в различных библиотечных функциях. Например, для работы с датой и временем (#include<ctime>). Где, в частности, определена структура
struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year; //год текущий минус 1900
int tm_wday;//день недели
int tm_yday;//день в году
int tm_isday;//0, если зимнее время
}
С ней связана переменная
typedef long time_t;
Определены функции
asctime преобразует время и дату из tm в символьную строку;
clock возвращает число тиков процессора, от начала работы процесса;
ctime преобразует время и дату из time_t в символьную строку;
time возвращает время в секундах, прошедшее с 0ч0м0с 1.01.1970 по Гринвичу;
#include<iostream>
#include <ctime>
using namespace std;
int main()
{
time_t tt;
tm *p_my_time;
tt=time(NULL);
p_my_time = localtime(&tt);
cout<<"current time: "<<asctime(p_my_time)<<endl;
return 0;
}
Многомерные массивы
Мм – массив массивов. Определение должно содержать сведения о типе, размерности и количествах элементов каждой размерности
type name_array [n1][n2]…[nN];
например,
int array[4][3][6];
Размещается в памяти в порядке возрастания самого правого индекса – array[0][0][0], array[0][0][1] и т.д. В таком же порядке располагают элементы массива в списке инициализации
int array[4][3][6]={0, 1, 2, 3, 4, 5, 6, 7};
А именно,
array[0][0][0] ==0; array[0][0][1] ==1; array[0][0][2] ==2; array[0][0][3] ==3;
array[0][0][4] ==4; array[0][0][5] ==5; array[0][1][0] ==6; array[0][1][1] ==7;
Если необходимо проинициализировать элементы массива, размещенные не по порядку, то используют {}.
int a[4][5][6] ={{{0}}, {{100},{110,111}}, {{200}, {210}, {220, 221, 222}}};
и получим
a[1][1][0] ==110; a[2][0][0] == 200; и т.д.
Допускается запись вида
double b[][4] = {{2},{3}};
когда компилятор может определить сам первую размерность по списку инициализации. Рассмотрим пример
void main()
{
int b[3][2][4] = { 0, 1, 2, 3,
10, 11, 12, 13,
100,101,102,103,
110,111,112,113,
200,201,202,203,
210,211,212,213
};
cout<<"\tadress of array b[][][]"<<endl;
cout<<"\nb = "<<b;
cout<<"\n\tadress of array b[0][][]"<<endl;
cout<<"\n*b = "<<*b;
cout<<"\n\tadress of array b[0][0][]"<<endl;
cout<<"\n**b = "<<**b;
cout<<"\n\telement of array b[0][0][0]"<<endl;
cout<<"\n***b = "<<***b;
cout<<"\n\tadress of array b[1][][]"<<endl;
cout<<"\n*(b+1) = "<<*(b+1);
cout<<"\n\tadress of array b[2][][]"<<endl;
cout<<"\n*(b+2) = "<<*(b+2);
cout<<"\n\tadress of array b[0][1][]"<<endl;
cout<<"\n*(*b+1) = "<<*(*b+1);
cout<<"\n*(*(*(b+1)+1)+1) = "<<*(*(*(b+1)+1)+1);
cout<<"\n*(b[1][1]+1) = "<<*(b[1][1]+1);
cout<<"\n\telement of array b[2][0][0]"<<endl;
cout<<"\n*(b[1]+1)[1] = "<<*(b[1]+1)[1];
cout<<endl;
}
Так элемент b[i][j][k] соответствует *(*(*(b+i)+j)+k).
Рассмотрим два различных определения
int *massiv[4]; //массив указателей на объекты типа int
int (*ptr)[4]; //указатель ptr на массив из 4 элементов, каждый из которых - int
Благодаря массиву указателей можно более эффективно расходовать память…
Например,
char list[][30] = {“rectangle”, ”circle”, ”segment”};
char *pointer [] = {“rectangle”, ”circle”, ”segment”};