- •Глава 1. Основные понятия.
- •Общие сведения о программах, лексемах и алфавите
- •Процесс создания программы
- •Основные типы.
- •Основные типы данных
- •Глава 2. Создание консольных приложений в среде VisualStudio
- •1. Создание проекта
- •2. Начальный состав проекта
- •3. Добавление новых элементов в проект
- •Глава 4. Адреса, указатели, массивы, память
- •1. Указатели и адреса объектов
- •2. Указатели на функции
- •3. Ссылки
- •Глава 5. Структуры и объединения
- •1. Структура как тип и совокупность данных
Глава 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Лексема – словарная единица, рассматриваемая в контексте языка во всей совокупности своих форм и значений, например, отдельной лексемой будет не только слово «дорога», но и два слова «железная дорога».