Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

технология программирования

.pdf
Скачиваний:
85
Добавлен:
30.03.2015
Размер:
1.38 Mб
Скачать

const MAX_STR_LEN=80; // В С++ возможно определение констант struct String // Структурный тип Строка

{

char s[MAX_STR_LEN]; // Массив символов - "Содержимое" Строки int str_len; // Текущая длина строки

};

// Переопределим ("перегрузим") оператор сложения для данных типа String

String operator+(String s1, String s2)

{

String TmpStr; // для временного хранения

//Длина строки-результата сложения равна сумме длина складываемых строк.

//Позаботимся также о том, чтобы не выйти за границу отведенного массива if ((TmpStr.str_len=s1.str_len+s2.str_len)>=MAX_STR_LEN)

{

TmpStr.s[0]='\x0';

 

 

 

TmpStr.str_len=0;

 

 

 

return TmpStr;

//

Вернем нулевую строку.

}

 

//

 

Иначе или далее сольем строки

strcpy(TmpStr.s, s1.s);

//s1.s->

TmpStr.s

strcat(TmpStr.s, s2.s);

// присоединим s2.s к TmpStr.s

return TmpStr;

// и возвратим результат

}

 

 

 

 

void main()

 

 

 

 

{

 

 

 

 

String str1, str2, str3;

 

 

 

strcpy(str1.s, "Перегрузка операторов -");

// Заполение содержимым

str1.str_len=strlen(str1.s);

 

 

// Опеределение текущей длины

strcpy(str2.s, "это очень удобно!");

 

 

str2.str_len=strlen(str2.s);

 

 

 

printf("Первая строка: длина=%d, содержимое=%s\n",

str1.str_len, str1.s);

 

 

 

printf("Вторая строка: длина=%d, содержимое=%s\n",

str2.str_len, str2.s);

 

 

 

str3=str1+str2;

// Используем перегруженный оператор!

//Компилятор, ориентируясь на типы слагаемых, генерирует код,

//эквалентный вызову str3=operator+(str1,str2);

printf("Третья строка:\n длина=%d, содержимое=%s\n", str3.str_len, str3.s);

}

Результаты

Первая строка: длина =23, содержимое = Перегрузка операторовВторая строка: длина =17, содержимое = это очень удобно!

Третья строка:длина=40, содержимое= Перегрузка операторов - это очень удобно! Для чисел знак «+» выполняет обычное арифметическое сложение.

11

2.5 Шаблоны функций

Если при написании программ на С++ часто приходиться создавать множество почти одинаковых функций для обработки данных разных типов, то используя ключевое слово template («шаблон»), можно задать компилятору образец, по которому он сам сгенерирует код, необходимый для конкретного типа. Компилятор создаст подходящую функцию, когда "узнает" какой тип аргументов класса Т подходит в конкретном случае. Т может быть и именем простого типа данных

Пример.

#include <stdio.h>

#include <string.h>

template <class T> void swap(T &a, T &b)

{

T c;

// создать переменную для временного хранения значения

c=b; b=a; a=c;

//обменять

 

Перед обменом

}

 

 

// i = 0

 

j = 1

void main()

 

//

x=0.000

y=1.000

{ int i = 0, j =1;

 

//

s1=first

s2 = second

double x = 0.0, y = 1.0;

 

 

 

 

char *s1= "first", *s2 = "second";

//

 

После обмена

printf("\t Перед обменом: \n " " i=%d j=%d\n " " x= %f y= %f \n "

 

" s1= %s s2= %s \n ", i, j, x, y, s1, s2);

 

//

i=1

j=0

swap( i, j );

 

 

// x=1.000

y=0.0000

swap( x, y );

 

 

// s1= second

s2= first

swap( s1, s2 );

 

 

 

 

 

printf("\t После обмена: \n " " i=%d j=%d \n" "x=%f y=%f\n" "s1=%s s2=%s\n", i, j, x, y, s1, s2);

}

Для примера «ОБМЕН» можно организовать обмен значениями через указатели:

# include <stdio.h>

void OBMEN(int *x, int*y)

{

int t;

t = *x; *x = *y; *y = t;

}

void main()

{

int a = 5, b = 9; OBMEN(&a, &b);

printf("\n a= %d b= %d", a, b);

}

12

2.6 Возврат из функции нескольких значений

Пусть функция должна возвратить два значения целого типа и получить одно значение того же типа. Для этого можно использовать два способа.

Первый способ заключается в использовании глобальной переменной.

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

Пример. Написать программу, функция в которой будет вычислять квадрат и куб аргумента. (Одно значение будем возвращать из функции оператором return, другое будет записываться по указателю int*.)

# include <stdio.h>

//uk5.cpp

# include <iostream.h>

 

int fun(int, int*);

// прототип функции

void main()

 

{

 

int a, kub, qv;

cin>>a; // ввод из потока

qv=fun(a,&kub); //исходное число, адрес ячейки, куда поместить //второе значение

cout<<"для числа " << a<< "\t квадрат=" <<qv<<"\t куб=" <<kub;

}

int fun(int k, int* p)

{

*p=k*k*k; // значение куба помещаем по адресу *p return k*k;

}

2.7 Стандартные типы даных

Объявление типа данных имеет формат вида

[<класс памяти>] <тип><идентификатор_1> [ [ = <нач.значение1;> ] [ , <идентификатор_2>[ = нач.зн.2 ] ...];

Класс auto (автоматический) используется для описания локализованных в блоке переменных. Область действия ограничена той функцией или блоком, в котором она объявлена. Класс extern - внешний, используется для явного описания глобальных переменных или для определения ссылок на внешние переменные. Класс register - регистровый, описывает переменные, хранящиеся в сверхбыстродействующей памяти на регистрах; область действия - аналогична переменным класса auto. Переменные класса static (статитический) подобно автоматическим переменным локализуются в блоке или функции, где они описаны, но при выходе из блока значения сохраняют.

Примеры объявлений:

13

static char c, b; register int x=0;

Одни и те же стандартные типы могут иметь эквивалентные названия. Их классификация приведена в таблице 2.

 

 

 

 

 

Таблица 2

 

 

 

 

Типы данных

 

 

 

 

 

 

 

 

Обозначение

Размер

Диапазон

Тип данных

 

 

 

(байт)

 

 

 

1

char,

1

 

-128...127

Символьный

 

 

signed char

 

 

 

со знаком

 

2

unsigned char

1

 

0...255

Символный без знака

 

3

short, short int,

2

 

-32768...

Короткое целое со знаком

 

 

signed short ,

 

 

32767

 

 

 

signed short int

 

 

 

 

 

4

unsigned short,

2

 

0...65535

Короткое целое без знака

 

 

unsigned short int

 

 

 

 

 

5

int, signed,

1, 2,

4

Зависит от

Целое

 

 

signed int

 

 

реализации

 

 

6

unsigned,

1, 2,

4

Зависит от реа-

Целое без знака

 

 

unsigned int

 

 

лизации

 

 

7

long, signed long,

4

 

-2147483648…

Длинное целое со знаком

 

 

long int

 

 

2147483647

 

 

8

unsigned long

4

 

0...4294967295

Длинное целое без знака

 

9

float

8

 

-3.4e-38...

Вещественное число с

 

 

 

 

 

3.14e+38

плавающей точкой

 

10

double

8

 

-1.7е-

Вещественное число уд-

 

 

 

 

 

308..1.7е308

военной точности

 

11

long double

10

 

-3.4e-4932...

Длинное вещественное

 

 

 

 

 

3.4e4932

число удвоенной точно-

 

 

 

 

 

 

сти

 

 

 

 

 

1

 

 

 

2.8 ТИПЫ, ОПРЕДЕЛЯЕМЫЕ ПОЛЬЗОВАТЕЛЕМ

Кроме рассмотренных ранее типов язык Си позволяет создавать еще

5типов данных: - структуры (structure),

-объединения (union),

-поля битов (bit fieldse),

-перечисления или перечислимый тип (enumeration),

-с помощью оператора typedef

14

2.8.1 Структуры

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

Структура в языке С/С++ аналогична по смыслу записи в ТР. Вид ее описания:

struct <имя структуры>

{

тип <имя_поля1>; // Определение структуры тип <имя_поля2>; // является оператором, тип <имя_поляN>; // поэтому заканчивается

} ;

// точкой с запятой.

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

является оператором, поэтому заканчивается точкой

с запятой.

 

Переменные, которые объединяются структурой, называются членами, элементами или полями структуры.

Пример определения структуры STUDENT (сведений о студенте) struct STUDENT {

сhar Name[30]; char Groupe[5]; int Age;

};

Такая запись не задает никакой переменной и выделения памяти не производится. Под именем STUDENT задаетcя частный вид структуры или шаблон структуры, т.е. определен новый тип struсt STUDENT. Для объявления конкретных переменных этого типа можно написать:

struct <имяструктуры> <список переменных>;

Пр. struct STUDENT stud1, stud2;

Переменные также могут задаваться одновременно с шаблоном struct STUDENT {

сhar Name[30]; char Groupe[5]; int Age;

} stud1, stud2;

Теперь объявлены две переменные и компилятор автоматически выделит под них память (под каждую переменную непрерывный участок).

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

struct stud1="Графкин Е.","В-227",18;

Доступ к элементу поля осуществляется с помощью операции "точка" или

"выделения элемента": <имя_переменной_стр>.<имя_поля>

Пр. strcpy(stud2.name, "Петров К.");

15

Для печати содержимого поля группы элемента структуры запись будет иметь вид: printf(" %c", stud1.Grupe);

Для пятого го элемента этого поля - printf("%c",stud1.Grupe[4]);

На практике структурные переменные объединяются в массивы структур. Для объявления массива структур сначала задается шаблон структуры, далее объявляется массив:

struct stud1 sudents[40]; // в памяти создается 30 переменных [0..29].

Если объявлены две переменные типа структура с одним шаблоном, то их можно присваивать друг другу: stud2=stud1;

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

Пример:

void main()

struct St1 m,k;

 

{struct St1

{int a;

struct St2 l;

 

 

char b;

k . a=1;

 

 

};

k . b=’f’;

 

struct St2

{int a;

m=k; //

верно

 

char b;

l=k; //

неверно

 

};

l . a=k . a;

l . b=k . b; // верно

Переменная типа структура может быть глобальной, локальной или формальным параметром. Любое поле структуры может быть параметром функции func1(int k.a); параметром может являтся и адрес поля func2(int &k.a).

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

struct <имя структуры> * <имя указателя>;

Например, struct St*uk; // uk – переменная типа указатель на структуру St. Если передается стуруктура по значению, то все ее элементы заносятся в стек.

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

Указателю можно присвоить адрес переменной uk=&m.

Для получения значения поля а переменной m используется операция доступа к полю:

(*uk).a или uk->a;

Структура операции доступа к полю по указателю

переменная_указатель -> имя_поля; ( перем_указ -> элемент_структуры;)

16

Операция "стрелка" употребляется, когда необходимо использовать значение элемента структуры с применением переменной-указателя.

В качестве элементов структуры можно использовать массивы, другие структуры, и массивы структур. Например:

struct Adr сhar

{city[30];

int ind;

char adres[40];

};

struct STUDadr сhar Name[30];

{struct Adr addr; char groupe[6];

}st1, st2;

Adr-шаблон структуры, определеный перед объявлением структуры STUDadr. Для присвоения значения элементу ind структуры STUDadr значения надо записать: st1.addr.ind=50;

2.8.2Поля битов

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

Доступ к биту обеспечивают поля битов (bit fields) – это специальный тип членов структуры, в котором определено, из скольких битов состоит каждый элемент. Полем считается последовательность соседних двоичных разрядов в числе типа int или unsigned (signed). Оно объявляется как элемент структуры.

Основная форма объявления структуры битовых полей

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

тип имя 1 : ширина ;

тип имя : ширина ;

;

где ширина – целое число от одного до 16; тип – int или unsigned. Имя может отсутствовать, тогда отведенные биты не используются (пропускаются). Длина структуры всегда кратна восьми.

Пример 1. Для переменной obj будет выделено восемь бит, но используется только первый.

struct onebit

unsigned b: 1;

obj;

17

Пример 2.

 

 

struct М

// значения диапазонов полей

int а:4;

//

а -8, 7

int b:1;

//

b - 1, 0

unsigned с:5;

// с 0,31

int :2;

//

пусто

int d :2;

// d -2,1

unsigned е :2

//

е 0,3

Расположение полей в структуре М из 16 бит получится следующее

 

А

b

с

не спользуется

 

d

е

 

0 … 3

4

5 … 9

10 11

 

12 13

14 15

Операции для полей битов такие же, как и для структур:

 

Присваивание. Пусть struct М byte; то byte.а=3;

 

 

 

 

 

 

byte.b=0;

 

 

Доступ к полю (точка)

byte.с=30;

 

 

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

«&» (адрес).

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

В структуре могут быть смешаны обычные переменные и поля битов. Поля битов не могут располагаться на пересечении границ объявленных для них типов (они располагаются в оставшемся пространстве предыдущего поля или начиная с новой целой границы)

Безымянное поле используется только как заполнитель. Для принудительного выравнивания к границе следующего целого числа используется специальный размер

Struct int f1:1

int : 2;

 

int f2:1;

 

: ;

stb.f3 заполняется в следующем int.

int f3:1 ;

 

stb;

 

2.8.3 Объединения

Используются для хранения значений различных типов в одной и той же области памяти, но не одновременно.

Объединение – это структура, все элементы которой имеют нулевое смещение, а сама структура достаточно велика, чтобы вместить самый большой элемент, и выровнена так, чтобы можно было работать с любым элементом. Объявляется

18

объединение, как и структура, но с ключевым словом union. Это объявление не задает какуюлибо переменную, а определяет лишь шаблон.

union имя структуры

тип 1 имя 1 ;

тип 2 имя 2 ;

тип имя ;

Для объявления переменной записывается:

union <имя структуры> <имя переменной>;

В объединении не допускаются элементы типа полей битов. Можно объявлять переменные одновременно с заданием шаблона.

 

Пример а) union u int i;

б) struct s int i;

char c;

 

char c;

 

long l; a, *р

;

long l ; b;

 

Для переменной типа union места в памяти выделяется столько, сколько надо элементу объединения, имеющему наибольший размер в памяти. Остальные переменные будут располагаться в том же месте памяти, начиная с одного и того же адреса (с наложением).

При инициализации объединения задается значение первого элемента в соответствии с его типом.

union u char name 10 int t

u1= Утро

Объединения могут входить в структуры и массивы и наоборот.

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

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

Пример 1. использования полей битов и объединений.

#include <stdio.h>

 

#include <conio.h>

 

struct byte

 

{

 

unsigned b1:1;

 

unsigned b2:1; // целое без знака

 

unsigned b3:1;

 

unsigned b4:1;

 

unsigned b5:1;

 

unsigned b6:1;

 

unsigned b7:1;

 

unsigned b8:1;

 

};

//Определена структура битовое поле

union bits {

 

char ch;

 

19

struct byte b;

 

} u;

 

void decode(union bits b);

// Прототип функции

void main()

 

{

 

do { u.ch=getche();

 

printf(": ");

 

decode(u);

 

} while (u.ch!='q');

// цикл повторять, пока не будет

}

// введен символ "q"

void decode(union bits p)

// функция

{

 

printf("%d%d%d%d%d%d%d%d",p.b.b8,p.b.b7,p.b.b6, p.b.b5, p.b.b4,p.b.b3,p.b.b2,p.b.b1);

printf("\n");

}

2.8.4 Перечисления

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

enum имя типа список названий список переменных ;

Список переменных может быть пустым.

Пример объявления. enum test{test1, test2, test3,test4}; enum test t;

Каждое из имен test1… test4 представляет собой целую величину (если они не определены по-другому). По умолчанию они соответствуют 0,1,2,3.

Во время объявления типа можно одному или нескольким перечисленным константам присвоить другие значения (константными выражениями).

Пример. еnum Ages {stas=18, ira, alex=19,Nina= alex-1};

Когда нет явного инициализатора, то применяется правило по умалчиванию: каждая следующая перечислимая константа увеличивается на единицу (+1) по сравнению с предшествующей. В примере вычислится ira=19; Nina=18;

Спеременными перечислимого типа можно проводить следующие операции:

присвоить переменную типа enum другой переменной того же типа;

провести сравнение с целью выяснения равенства или неравенства;

некоторые арифметические операции с константами типа enum.

Пример. i= test4-test2;

Оператор print f( %d %d”, test1, test4); выдаст на экран числа 0 и 3.

t= test3;

 

 

t++ ;

 

теперь t= test4;

t -=2 ;

//

t = test2;

20