Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
шпоры программирование.doc
Скачиваний:
7
Добавлен:
17.04.2019
Размер:
257.54 Кб
Скачать
  1. Составные типы данных: структуры, указатели на структуры.

Основы работы со структурами

Создадим несколько структур для работы с геометрическими объектами. Основным графическим объектом является точка, которая описывается своими координатами x , y и z. Пусть координаты имеют тип double.

Определение структуры

Определение структуры задает ее внутреннюю организацию, описывая данные, входящие в состав структуры:

struct point

{

double x;

double y;

double z;

};

Ключевое слово struct начинает объявление структуры, состоящее из списка объявлений в фигурных скобках. Затем следует имя структуры, в данном случае этим именем является point. Переменные, перечисленные в объявлении структуры, называются ее членами, элементами или полями.

Смысл определения структуры

Определение структуры необходимо для того, чтобы создавать на его основе переменные типа point. Определение не создает никаких переменных, т.е. не происходит ни выделения физической памяти, ни объявления переменной. В то же время определение обычной переменной предполагает выделение памяти под эту переменную. Таким образом, определение структуры задает организацию данных (структурных переменных) после того, как они будут определены.

Определение структурной переменной

Переменная, имеющая тип point определяется следующим способом:

point A; данное объявление сделано в стиле C++.

struct point A; данное объявление сделано в стиле C.

Определение переменных означает, что под эту переменную выделяется память. Под структурную переменную всегда отводится столько памяти, сколько достаточно для хранения всех ее полей. В нашем примере необходимо выделить по восемь байт для трех полей типа double. Таким образом, структура занимает в памяти 24 байта.

В языке C/C++ есть одноместная операция sizeof, выполняемая при компиляции с помощью которой можно вычислить размер любого объекта. Следующие два выражения дают в результате целое число, равное размеру заданного объекта или типа в байтах:

sizeof A; размер объекта

sizeof(struct point); или sizeof(point); размер типа

Строго говоря, операция sizeof дает целое число без знака.

Доступ к полям структуры

Когда структурная переменная определена, доступ к ее полям возможен доступ при помощи операции точки. Операция точки в соответствии с общепринятой терминологией называется операцией доступа к полю структуры.

A.x=1.11;

A.y=2.22;

A.z=3.33;

С полями структурной переменной можно обращаться точно так же, как и с обычными переменными:

std::cout << A.x << std::endl;

Структуры можно вкладывать друг в друга. Представим вектор на плоскости, как пару точек:

struct my_vector

{

struct point A1;

struct point A2;

};

Тогда следующие выражения будут означать соответствующие координаты начальной и конечной точки вектора:

a1.A1.x=1.11;

a1.A1.y=2.22;

a1.A1.z=3.33;

a1.A2.x=2.34;

a1.A2.y=3.22;

a1.A2.z=1.14;

Глубина вложения может быть произвольной.

Присваивание структурных переменных

Мы можем присвоить значение одной структурной переменной другой структурной переменной:

struct point A;

A.x=1.11;

A.y=2.22;

A.z=3.33;

struct point B;

B.x=2.34;

B.y=3.22;

B.z=1.14;

struct my_vector a1;

a1.A1=A;

a1.A2=B;

std::cout << a1.A1.z << std::endl;

struct my_vector a2;

a2=a1;

В данной программе структурной переменной a1.A1 присваивается значение структурной переменной A, а структурной переменной a1.A2 присваивается значение структурной переменной B. Значение каждого поля переменной A присваивается соответствующему полю переменной a1.A1.

Структуры также можно инициализировать при объявлении:

struct point A={1.11, 2.22, 3.33};

struct point B={2.34, 3.22, 1.14};

struct my_vector a1 ={{1.11, 2.22, 3.33},{2.34, 3.22, 1.14}};

или

struct point A={1.11, 2.22, 3.33};

struct point B={2.34, 3.22, 1.14};

struct my_vector a1 ={A,B};

Структуры и функции

Разрешенными операциями над структурами являются копирование и присваивание структуры как целого, взятие ее адреса операцией &, а также обращение к ее элементам. Копирование и присваивание включают в себя также передачу аргументов в функции и возвращение значений из функции. Структуры нельзя сравнивать между собой, складывать. Автоматическую структуру (определенную в стеке), как было показано выше, можно инициализировать.

Рассмотрим вопросы работы со структурами на конкретных примерах – напишем ряд функций для манипулирования точками и векторами. Здесь возможно несколько подходов к решению: передавать отдельные компоненты структур, целые структуры, указатели и ссылки на них. В каждом подходе есть свои сильные и слабые стороны.

Определим функцию, вычисляющую квадрат расстояния между двумя точками.

double square_distance(struct point A, struct point B)

{return ((B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y)+(B.z-A.z)*(B.z-A.z));}

int main()

{

double d;

struct point A={1.11, 2.22, 3.33};

struct point B={2.34, 3.22, 1.14};

d=square_distance(A,B);

std::cout << d << std::endl;

return 0;

}

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

struct point middle_point(struct point A, struct point B)

{

struct point temp;

temp.x=(A.x+B.x)/2;

temp.y=(A.y+B.y)/2;

temp.z=(A.z+B.z)/2;

return temp;

}

int main()

{

struct point middle;

struct point A={1.11, 2.22, 3.33};

struct point B={2.34, 3.22, 1.14};

middle=middle_point(A,B);

std::cout << "x= " << middle.x << "y= " << middle.y << "z= " << middle.z << std::endl;

return 0;

}

или

int main()

{

struct point A={1.11, 2.22, 3.33};

struct point B={2.34, 3.22, 1.14};

std::cout << "x= " << middle_point(A,B).x << "y= " << middle_point(A,B).y << "z= " << middle_point(A,B).z << std::endl;

return 0;

}

Данная функция возвращает точку, которая находится между точками A и B.

В дальнейшем удобно использовать для инициализации переменных функцию, которая трем числам сопоставляет структуру:

struct point make_point(double x, double y, double z)

{

struct point temp;

temp.x=x;

temp.y=y;

temp.z=z;

return temp;

}

int main()

{

double x,y,z;

std::cout << "Enter coordinate x:" << std::endl;

std::cin >> x;

std::cout << "Enter coordinate y:" << std::endl;

std::cin >> y;

std::cout << "Enter coordinate z:" << std::endl;

std::cin >> z;

struct point C;

C=make_point(x,y,z);

std::cout << "x= " << C.x << "y= " << C.y << "z= " << C.z << std::endl;

return 0;

}

При помощи данной функции можно определить динамическую инициализацию полей структуры как в данной программе или для передачи аргументов структур в функции:

int main()

{

struct point middle;

struct point A={1.11, 2.22, 3.33};

struct point B={2.34, 3.22, 1.14};

middle=make_point((A.x+B.x)/2,(A.y+B.y)/2,(A.z+B.z)/2);

std::cout << "x= " << middle.x << "y= " << middle.y << "z= " << middle.z << std::endl;

return 0;

}

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

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

Указатели на структуры обладают всеми свойствами указателей на обычные переменные.

Следующее объявление показывает, что ptr_my_vect является указателем на структуру типа my_vector:

int main()

{

struct point A={1.11, 2.22, 3.33};

struct point B={2.34, 3.22, 1.14};

struct my_vector a={A,B};

struct my_vector *ptr_my_vect =&a; //указатель на a

std::cout << " x=" << (*ptr_my_vect).A1.x << " y=" << (*ptr_my_vect).A1.y << " z=" << (*ptr_my_vect).A1.z << std::endl;

std::cout << " x=" << (*ptr_my_vect).A2.x << " y=" << (*ptr_my_vect).A2.y << " z=" << (*ptr_my_vect).A2.z << std::endl;

return 0;

}

Скобки при обращении к полям необходимы, поскольку приоритет операции по разыменовыванию указателя ниже, чем обращения к полям структуры. Указатели на структуры используются так часто, что для них введено дополнительное обозначение: обратиться по указателю к полям структуры можно посредством операции, состоящей из знака «минус» и «больше». Поэтому выше приведенный пример можно записать так:

std::cout << " x=" << ptr_my_vect->A1.x << " y=" << ptr_my_vect->A1.y << " z=" << ptr_my_vect->A1.z << std::endl;

std::cout << " x=" << ptr_my_vect->A2.x << " y=" << ptr_my_vect->A2.y << " z=" << ptr_my_vect->A2.z << std::endl;

Операции обращения к структурам (точка и ->) наряду с круглыми скобками для вызовов функций и квадратными скобками для индексов массивов находятся на самой вершине иерархии приоритетов, а потому применяются к своим аргументам всегда в первую очередь.

Приведем примеры программ, которые используют указатели на структуры.

Определим координаты вектора, соединяющего две точки. Поскольку координаты вектора определяются тремя числами, для их представления будем использовать структуру point. Функция будет выглядеть следующим образом:

struct point get_vector_coordinates(struct my_vector *vec)

{

struct point temp;

temp.x=vec->A2.x-vec->A1.x;

temp.y=vec->A2.y-vec->A1.y;

temp.z=vec->A2.z-vec->A1.z;

return temp;

}

int main()

{

struct point A={1.11, 2.22, 3.33};

struct point B={2.34, 3.22, 1.14};

struct my_vector a={A,B};

struct point *AB =new struct point;

*AB=get_vector_coordinates(&a);

std::cout << " x=" << AB->x << " y=" << AB->y << " z=" << AB->z << std::endl;

return 0;

}

Определить скалярное произведение двух векторов.

double scalar_product(struct my_vector *vec1,struct my_vector *vec2)

{

return (get_vector_coordinates(vec1).x*get_vector_coordinates(vec2).x+get_vector_coordinates(vec1).y*get_vector_coordinates(vec2).y+get_vector_coordinates(vec1).z*get_vector_coordinates(vec2).z);

}

Переместить вектор на величину t вдоль его направления:

struct my_vector * move_along(struct my_vector *vec, double t)

{

vec->A1.x +=t;

vec->A1.y +=t;

vec->A1.z +=t;

vec->A2.x +=t;

vec->A2.y +=t;

vec->A2.z +=t;

return vec;

}

int main()

{

struct point A={1.11, 2.22, 3.33};

struct point B={2.34, 3.22, 1.14};

struct my_vector a={A,B};

struct my_vector *a_t = new struct my_vector;

*a_t=a;

a_t=move_along(a_t,5.55);

std::cout << " x=" << a_t->A1.x << " y=" << a_t->A1.y << " z=" << a_t->A1.z << std::endl;

return 0;

}