Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СИ++(лекции).doc
Скачиваний:
23
Добавлен:
27.03.2015
Размер:
551.42 Кб
Скачать

Глава 5. Структуры и объединения

1. Структура как тип и совокупность данных

Будем считать, что структура это объединение в единое целое множество поименованных элементов в общем случае различных типов. В случае массивов элементы имеют один и тот же тип, что не всегда удобно. Например, информация о студенте содержит сведения разного типа: имя, фамилии и отчество – это char*, тогда как дата рождения и дата поступления – это совокупность трех неотрицательных чисел, характеризующих день, месяц и год. Номер специальности и группы – это некоторые целые числа. Обязательно каждый студент имеет студенческий билет, который имеет уникальное значение для данного вуза. Естественно необходимо иметь паспортные данные и так далее. Если ко всей этой совокупности необходимо обращаться как к единому целому, то представить ее в виде некоторого массива невозможно, так как каждый элемент имеет свой тип данных. Объединить эту информацию в единое целое можно с помощью введения нового типа данных, определяемых как структура. Для описания используется следующая схема:

struct имя_структуры{

описание элементов структуры

};

Описание элементов структуры состоит из описания полей структуры и, возможно, описания методов обработки элементов этой структуры. Описание полей структуры создается следующим образом: указывается тип поля и список имен таких полей. Кроме того, в описание элементов структуры могут быть включены функции создания объекта (конструктор) и функции его обработки. Функция конструктора очень специфическая. Она не имеет типа возвращаемого результата и носит то же имя, что и структура. Эта функция при объявлении объекта типа структуры выполняет все операции, указанные в ней (присваивает полям значения по умолчанию, выделяет под поля-указатели место в памяти т так далее). Остальные функции структуры – это обычные функции, где в качестве объектов, над которыми производятся действия, могут быть использованы формальные параметры и поля объекта, к которому применяется данный метод. При описании функции нельзя использовать операторы цикла. Если их использовать необходимо, то в теле описания структуры остается только прототип функции, а описание самой функции выносится за пределы описания структуры. Например, можно ввести структуру, описывающую календарную дату. Полями структуры являются три поля типа int, которые задают день, месяц и год даты.

const int dm[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};

struct date{

//Описание полей день, месяц и год

int dd,mm,yy;

//Функция конструктора задает полям значения по умолчанию

date(int d=1,int m=1,int y=2011)

{

dd=d;

mm=m;

yy=y;

}

//Функция, возвращающая 1, если год даты является високосным и

//0 в противном случае

int vis(void)

{

if(yy%4==0&&yy%100!=0||yy%400==0) return 1;

else return 0;

}

//Функция осуществляющая проверку правильности ввода даты

int date_true(void)

{

if(yy<=0)return 0;

if(mm<1||mm>12) return 0;

if(mm!=2&&(dd<1||dd>dm[mm])) return 0;

if(mm==2&&(dd<1||dd>28+vis())) return 0;

return 1;

}

//Функция печати даты в формате dd.mm.yy

void date_print(void)

{

char s[9];

int y=yy%100;

s[0]='0'+dd/10;

s[1]='0'+dd%10;

s[2]='.';

s[3]='0'+mm/10;

s[4]='0'+mm%10;

s[5]='.';

s[6]='0'+y/10;

s[7]='0'+y%10;

s[8]='\0';

cout<<s<<'\n';

}

};

Обращение dateTD(2,12,1978),ZD; создает объекты с именемTDи значениями полейddсо значением 2,mm– 12 иyy– 1978 и объектZDсо значениями полей:dd– 1,mm– 1,.yy– 2011, то есть значения по умолчанию. Если объявлен объект типаdate, то обращение к элементам структуры осуществляется через точку. Например, изменить значение поляddу объектаTDна значение 15 можно с помощью следующего оператора присваивания:TD.dd=15; . Проверку правильности заданной даты осуществляет применение методаdate_true к данному объекту: TD.date_true(). Если значение этого выражения совпадает с 1, то дата задана правильно. В случае неаправильно заданной даты эта функция возвращает значение 0. Задавать значение полей можно и при явном обращении к конструктору. Все эти возможности продемонстрированы в программе приведенной ниже.

int _tmain(int argc, _TCHAR* argv[])

{

//Создается объект с именем d и значениями 7 декабря 1978 года

date d(7,12,1978);

setlocale(LC_CTYPE,"russian");

//Печать даты

d.date_print();

do

{

cout<<"\nВведите день, месяц и год даты ";

//Задание значения полей объекта непосредственным вводом

//с контролем правильности ввода даты

cin>>d.dd>>d.mm>>d.yy;

if(!d.date_true())cout<<"\nДата введена неправильно!\n";

}while(!d.date_true());

d.date_print();

int dv,mv,yv;

do

{

//Задание значений с помошью простых переменных

cout<<"\nВведите день, месяц и год даты ";

cin>>dv>>mv>>yv;

//Перенос этих значений в поля объекта с помощью непосредственного

//обращения к конструктору с контролем правильности ввода даты

d=date(dv,mv,yv);

if(!d.date_true())cout<<"Дата введена неправильно!\n";

}while(!d.date_true());

d.date_print();

cin.get();

return 0;

}

Введенные структуры играют роль новых типов данных. На их основе можно вводить новые типы данных. Пусть необходимо составить список студентов, содержаших имя студента, его дату рлждения и номер студенческого билета. Кроме того, включим в структуру конструктор и функцию, печатающую информацию о студенте. Полностью листинг программы представлен ниже.

Файл stdafx.h

#pragma once

#define WIN32_LEAN_AND_MEAN

#include <stdio.h>

#include <tchar.h>

#include <string.h>

#include <iostream>

using namespace std;

Файл Date.cpp

#include "stdafx.h"

const int dm[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};

//Структура, описывающая даты

struct date{

int dd,mm,yy;

//Конструктор

date(int d=1,int m=1,int y=2011)

{

dd=d;

mm=m;

yy=y;

}

//Определяет, является ли год високосным

int vis(void)

{

if(yy%4==0&&yy%100!=0||yy%400==0) return 1;

else return 0;

}

//Проверка правильности ввода даты

int date_true(void)

{

if(yy<=0)return 0;

if(mm<1||mm>12) return 0;

if(mm!=2&&(dd<1||dd>dm[mm])) return 0;

if(mm==2&&(dd<1||dd>28+vis())) return 0;

return 1;

}

//Печать даты

void date_print(void)

{

char s[9];

int y=yy%100;

s[0]='0'+dd/10;

s[1]='0'+dd%10;

s[2]='.';

s[3]='0'+mm/10;

s[4]='0'+mm%10;

s[5]='.';

s[6]='0'+y/10;

s[7]='0'+y%10;

s[8]='\0';

cout<<s;

}

};

//Структура, описывающая студента

struct Student{

char *name;//Имя

date bd; //День рождения

int nstb; //Номер студенческого билета

//Конструктор

Student(char*vname='\0',int d=1,int m=1,int y=2011,int vnstb=0)

{

name=strdup(vname);//Выделение памяти под имя и копирование

//введенного имени

bd.dd=d; //День

bd.mm=m; //месяц

bd.yy=y; //и год рождения

nstb=vnstb; //Номер студенческого билета

}

//Печать информации о студенте

void Student_print(void)

{

cout.width(30);

setlocale(LC_CTYPE,".866");

cout<<name<<" ";

bd.date_print();

cout<<" "<<nstb<<'\n';

}

};

int _tmain(int argc, _TCHAR* argv[])

{

int n,i,d,m,y,nb;

date dv;

Student *ss;

char s[25];

setlocale(LC_CTYPE,"russian");

cout<<"\nВведите число студентов ";

cin>>n;

cin.get();

//Запрос места под список студентов

ss=new Student[n];

for(i=1;i<=n;i++)

{

//Ввод информации о текущем студенте

cout<<"Введите имя "<<i<<"-го студента ";

gets(s);

do

{

cout<<"Введите день, месяц и год его рождения ";

cin>>d>>m>>y;

dv=date(d,m,y);

if(!(dv.date_true()))

cout<<"Дата рождения введена неправильно!\n";

}while(!(dv.date_true()));

cout<<"И номер его студенческого билета ";

cin>>nb;

//Задание полей студента с помощью конструктора

ss[i]=Student(s,d,m,y,nb);

cin.get();

}

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

for(i=1;i<=n;i++)

ss[i].Student_print();

cin.get();

return 0;

}

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

struct date{

. . .

int date_pd(void);

. . .

};

int date::date_pd(void)

{

int dl=0.i;

for(i=1;i<mm-1;i++)

dl+=dm[i];

if(mm>2)dl+=vis();

dl+=dd;

return dl;

}

1Лексема – словарная единица, рассматриваемая в контексте языка во всей совокупности своих форм и значений, например, отдельной лексемой будет не только слово «дорога», но и два слова «железная дорога».