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

6 Структурированные типы данных 2012

.pdf
Скачиваний:
48
Добавлен:
29.02.2016
Размер:
529.73 Кб
Скачать

1

6Структурированные типы данных

6.1Массивы

Массив (регулярный тип данных) – структурированный тип данных, описывающий упорядоченную последовательность элементов одного базового типа. Доступ к элементам массивов производится с помощью имени переменной и целочисленных индексов, указываемых в квадратных скобках. Наименьшее значение индекса у первого элемента массива, а наибольшее – у последнего. В отличие от языка Паскаль в С нет отдельного идентификатора для описания массивов, для этого используется идентификатор базового типа и имя переменной, после которого в скобках указывается число элементов массива. В С и С++ первый элемент массива всегда соответствует нулевому значению - 0.

Различают три основных вида массивов:

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

Базовый_тип имя_массива[размер];

Примеры описания одномерных массивов:

float vect[100];

/*

массив из

100 вещественных элементов */

int numbers[1000];

/*

массив из

1000 целочисленных элементов */

2) двухмерные массивы

(матрицы), индексы которых показывают номер столбца

и номер строки элемента; формат объявления массива

тип_массива имя_матрицы [размер_столбцов][размер_строк];

Примеры матриц:

 

 

 

float Matr[4][5];

/* вещественная матрица из 4 строк

и 5 столбцов */

int matrix[8][4];

/* целочисленная матрица в 8 строк

и 4 столбцов */

3) многомерные массивы (тензоры) – адресация элементов

которых

производится тремя и более индексами; формат объявления N-мерного массива

 

базовый_тип имя [размер_индексаN] … [размер_индекса2][размер_индекса1];

Примеры:

 

 

 

float M[10][10][10];

/* вещественный массив размерности

10 x 10 x 10 */

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

указания

имени

переменной массива и номера (номеров) соответствующего индекса:

 

 

Имя_массива[индекс];

Пример задания единичного значения первым элементам массивов

vect[0]=1;

/* первый элемент вектора

*/

Matr[0][0]=1;

/*

первый

элемент

матрицы

*/

M[0][0][0]=1;

/*

первый

элемент

трехмерного массива */

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

Пример использования массивов для вывода на печать первых 20 чисел

Фибоначчи на языке С++:

 

#include <iostream.h>

// подключение заголовочного файла

const int size=20;

// константа размера массива

int vector[size];

// переменная-вектор

int main()

// главная функция программы

{ int i;

// переменная индекса

cout << "\nЧисла Фибоначчи" << endl;

vector[0] = vector[1] = 1;

// начальная инициализация двух значений

for (i=2; i<size; i++)

// цикл расчета числа Фибоначчи

{vector[i] = vector[i-1] + vector[i-2]; // расчет i-го числа cout << vector[i] << endl; // вывод значения i-го числа

 

} //

конец тела цикла for

 

 

return 0;

// возврат кода успешного завершения

}

//

конец main

 

Пример программы расчета значений на интервале квадратной функции по

формуле y(x) = a x2 + b x + c,

с использованием векторов для значений аргумента и функции на языке С++

 

 

 

2

 

#include

<iostream.h>

// подключение заголовочного файла ввода-вывода

#include

<math.h>

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

#include

<conio.h>

// подключение заголовочного файла консоли

const

size=20;

// константа размера векторов

 

float

x[size];

// вектор аргумента (независимой переменной)

float

y[size];

// вектор функции (зависимой переменной)

float

a,

b, c;

// параметры расчетного выражения

float

xn, xk, hx;

// начало, конец и шаг изменения аргумента

int main()

// заголовок главной функции

 

{ cout << "a=";

// вывод экранного запроса на

ввод значения a

cin

>>

a;

// ввод с клавиатуры значения

a

cout << "b=";

// вывод экранного запроса на

ввод значения b

cin

>>

b;

// ввод с клавиатуры значения

b

cout << "c=";

// вывод экранного запроса на

ввод значения c

cin

>>

c;

// ввод с клавиатуры значения

c

cout << "начало х=";

// вывод экранного запроса на

ввод значения xn

cin

>>

xn;

// ввод с клавиатуры значения

xn

cout << "конец x=";

// вывод экранного запроса на

ввод значения xk

cin

>>

xk;

// ввод с клавиатуры значения

xk

hx = (xk-xn)/(size-1);

// Определение шага изменения

аргумента

x[0]=xn;

// инициализация первых элементов массивов

y[0]=a*pow(x[0],2)+b*x[0]+c;

 

 

cout << "\nX=" << x[0] << "

Y=" << y[0];

 

for

(int i=1; i<size; i++)

 

 

{x[i]=x[i-1]+hx; y[i]=a*pow(x[i],2)+b*x[i]+c;

cout << "\nX=" << x[i] << " Y=" << y[i] ;

}// конец тела цикла for

getch();

//

приостановка программы

return 0;

//

код успешного завершения

}// -------- конец main ----------------------------------

Инициализация начальных значений массивов при их объявлении производится

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

базовый_тип имя_массива[размер]={первый_элемент, , последний_элемент }

Примеры

int vector[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; float row[3] = {0.12, 3.45, 6.78};

В этом примере элементы массивов имеют следующие значения

vector[0]=0,

vector[1]=1, …,

vector[9]=9

row[0]=0.12,

row[1]=3.45,

row[2]=6.78

Если требуется проинициализировать двухмерный массив, тогда используется

следующая субагрегатная

форма:

 

тип массив [n][m]={{a0,0,… , a0,m}, ,{ an,0,… , an,m }};

Пример инициализации матрицы целочисленной матрицы в переменной M

 

 

 

1

2

3

 

 

 

4

5

6

7

8

9

 

 

 

int M[3][3]={{1,2,3},{4,5,6},{7,8,9}};

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

int row[];

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

float massa[][][2];

Над переменными-массивами целиком допустимы операции передачи их значений в качестве параметров функций и операции сравнения (равно или не равно). Все остальные операции выполняются над элементами массивов.

3

6.2 Строковый тип данных

Строковый тип данных используется для операций над строками текста. Значением строкового типа является последовательность символов с динамическим атрибутом длины (в зависимости от действительного числа символов при выполнении программы) и константным атрибутом предельного размера строки.

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

Формат объявления короткого строкового типа char имя_строки [атрибут_длины_строки];

Примеры описания:

char str80[80]; /* Строка длиной 80 символов */ char message[16]; /* Строка длиной 16 символов */

Константы строкового типа в С и С++ заключаются с двух сторон в кавычки

(): символы строки.

Примеры инициализации строковых констант:

char name[12]=”Borland C++”;

 

char

error_1[20]=”Нет

доступа к файлу”;

char

zero[1]=””;

//

Пустая

строка

Последний пример описывает пустую строку.

К отдельным символам в строке доступ аналогичен как к компонентам массива. В языке С с помощью заголовочного файла string.h над строками допустимы

стандартные операции, реализуемые с помощью функций:

-strcat(s1, s2) - сложение двух строк s1 и s2, результат помещается в первую строку s1;

-strcmp(s1, s2) - сравнение двух строк;

-strlen(s) – возвращает длину строки в символах;

-strcopy(s1, s2) – копирует строку s2 в строку s1.

Для ввода строк с клавиатуры в С удобно использовать функцию gets(), а для вывода – puts(), которые находятся в заголовочном файле stdio.h.

Для вывода строк можно в С использовать функцию printf() из заголовочного

файла stdio.h.

 

 

 

 

Пример программы

для инвертирования

(перестановки символов в обратном

порядке) вводимой с клавиатуры строки.

 

 

#include <stdio.h>

/*

Модуль с функциями ввода-вывода С */

#include <conio.h>

/*

Модуль для работы

с консолью */

#include <string.h>

/*

Модуль для работы

со строками */

char s1[80];

/*

Исходная строка */

 

char s2[80];

/*

Строка результат */

int main(void)

/*

Главная функция */

 

{ int i, size;

/*

локальные переменные счетчика и размера */

printf("Введите исходную

строку \n");

/*

Вывод на экран приглашения */

gets(s1);

 

 

/*

Ввод строки */

size=strlen(s1);

 

 

/*

Определение длины строки */

printf("\nsize %d \n", size);

/*

Вывод числа элементов строки */

for (i=0; i<(size); i++)

 

/*

Цикл инвертирования строки */

{ s2[i]=s1[size-1-i];

 

 

/*

Формирование символа строки */

} /* конец цикла for */

 

 

 

printf("\nРезультат\n %s",s2);

/*

Вывод строки на экран */

getch();

/*

Ожидание нажатия любой клавиши */

return 0;

 

 

/*

Возврат успеха работы программы */

}/* -------------------- main ----------------------------- */

ВC++Builder до версии 2006 имеется специальный строковый тип-класс, совместимый со стандартом ASCII – AnsiString, аналогичный в языкам Object Pascal и Delphi. Начиная с версии 2006 он замене на UnicodeString. Формат объявления имеет вид

AnsiSring имя_строки; или UnicodeString имя_строки;

4

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

имя_переменной_строки.имя_встроенной_функции();

Таблица 6.1 – Некоторые встроенные функции класса AnsiString

Функция класса

 

 

 

Описание

 

 

 

 

 

ToInt()

Преобразует строковый

тип

в

целочисленные данные типа int

ToDouble()

Преобразует

строковый

тип

в

вещественные данные типа double

c_str()

Преобразует

данные AnsiString в символьный массив

Примеры использования строкового типа AnsiString:

AnsiString Name; // Объявление переменной типа AnsiString char ctext[80]; // Объявление строковой переменной языка С

ctext=Name.c_str(); // Преобразование AnsiString

6.3 Комбинированный тип данных (структуры)

Комбинированный тип данных в языках программирования описывает упорядоченную структуру данных различных базовых типов. В языке программирования С в качестве комбинированного типа данных выступает структура.

Структура является совокупностью элементов (полей) произвольных типов. Они широко используются при формировании баз данных в некоторой предметной области. Формат объявления структуры:

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

{тип_поля_1 имя_поля_1; тип поля_2 имя_поля_2;

 

 

 

 

тип поля_N имя_поля_N;

 

 

} список_переменных;

 

 

 

Список переменных является необязательным и включает имена переменных,

которые будут иметь созданный

тип структуры.

 

Пример структуры записи

календарной даты

struct date

 

 

{

short int day;

/* поле -

число */

 

short int mount;

/* поле -

месяц */

 

int year;

/* поле -

год */

};

/* конец описания date */

 

 

Внутри структуры поля могут также иметь тип структуры. Пример описания

структуры для записи данных о

человеке:

 

struct man

 

 

{

char name[40];

/* поле -

имя */

 

char secondname[40];

/* поле -

отчество */

 

char family[100];

/* поле -

фамилия */

 

date birthday;

/* поле -

день рождения */

};

/* конец описания man */

 

 

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

имя_типа_структуры имя_переменой;

Примеры:

 

 

 

 

man client;

/*

переменная

структуры

man */

date finish;

/*

переменная

структуры

date */

В переменных

комбинированного типа (структуры) доступ к отдельным членам

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

имя_переменной_структуры.имя_поля

Пример задания значений полей в переменной структуры:

5

client.name = “Иван”; client.birthday.year=1979; client.birthday.day=29; client.birthday.mount=2;

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

man client1, client2; client1=client2;

Пример программы, вводящей с клавиатуры почтовый адрес в структуру:

#include <stdio.h>

 

 

struct

addr

/* задание структуры для хранения почтового адреса */

{ char

name[255];

 

/* Имя, фамилия адресата */

char

country[40];

/* Страна проживания */

long

int index;

 

/* Почтовый индекс */

char

sity[80];

 

/* Город */

char

street[80];

 

/* Улица */

int house;

 

/* Номер дома */

int apartment;

 

/* Номер квартиры */

} man;

 

 

/* конец описания структуры addr*/

int main(void)

 

/* главная функция */

{printf("\nФамилия и инициалы \n"); scanf("%s",man.name); printf("\nСтрана проживания\n"); scanf("%s",man.country); printf("\nГород проживания\n"); scanf("%s",man.sity); printf("\nУлица \n"); scanf("%s",man.street); printf("\nНомер дома \n"); scanf("%d",&man.number); printf("%s ",man.name); printf("%s ",man.country); printf("%s ",man.sity); printf("%s ",man.street); printf("%d \n",man.number);

return 0;

 

} /* ---------------------------------------------------

*/

Объекты типа структура можно присваивать, передавать как параметры функции и возвращать из функции в качестве результата. Остальные такие операции, как сравнение (== и !=) не определены. Размер переменной структурного типа нельзя вычислить просто как сумму его членов.

Два структурных типа являются различными даже тогда, когда они имеют одни

ите же члены. Например:

struct s1 { int a; float b; };

struct s2 { int a; float b; };

есть два разных типа, поэтому s1 x;

s2 y = x; // ошибка: несоответствие типов

Структурные типы отличны также от основных типов, поэтому s1 x;

int i = x; // ошибка: несоответствие типов

6.4 Битовое поле

Битовое поле является модификацией структуры в языке С, которое позволяет хранить массив полей, имеющих длину в один или несколько байт, внутри непрерывной последовательности. Битовые поля активно используются для хранения состояния группы различных логических переключателей (флагов). В них каждый бит кодирует состояние соответствующего номера поля: например, 1 – включено, 0 – выключено. Эффективно использование битовых полей при передаче данных по линиям связи.

6

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

struct имя_битового_поля

{тип_поля имя_поля : длина_поля ;

} список_переменных; Тип поля указывается в зависимости от длины поля. Если длина в один байт,

то следует указать unsigned (беззнаковый), при длине в два и более байта – знаковый. Длина полей может быть от 1 до 32.

Пример объявления битового поля для контроля состояния внешнего периферийного устройства:

struct status

{unsigned enabled : 1; /* признак включения устройства */ unsigned ready : 1; /* режим чтения данных с устройства */

unsigned write : 1; /* режим записи данных в устройство */ unsigned error : 1; /* сбой в работе устройства */

};

Пример программы задания с клавиатуры режима работы привода: #include <conio.h>

#include <stdio.h> struct device

{unsigned enabled : 1; /* Включение устройства */ unsigned ready : 1; /* Чтение данных с устройства */ unsigned write : 1; /* Запись данных в устройство */

unsigned error : 1;

/* Состояние сбоя устройства */

};

 

/* device */

 

int main(void)

 

 

 

{ device drive={0x0,0x0,0x0,0x0};

/* Переменная привода */

int ans;

 

 

/* Код ответа */

do

/* цикл опроса меню */

{printf("\n Введите режим работы ");

printf("\n 1 - Включить привод "); /* вывод меню */ printf("\n 2 - Читать данные привода ");

printf("\n 3 - Передать данные на привод ");

printf("\n 4 - Установить сбой привода ");

 

printf("\n 0 - Выключить привод \n ");

 

scanf("%d",&ans);

/* чтение выбора */

switch (ans) {

/* выбор режима */

 

case 1: drive.enabled=1;

 

 

break;

 

 

case 2: drive.ready=1;

 

 

break;

 

 

case 3: drive.write=1;

 

 

break;

 

 

case 4: drive.error=1;

 

 

break;

 

 

case 0:drive.enabled=0x0;

 

 

break;

 

}

/* switch */

 

printf("\n Состояние системы %x",drive);

/* вывод состояния */

} while (ans!=0);

/* конец цикла while */

getch();

/* задержка экрана */

return 0;

 

}

 

/* main */

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

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

union имя_объединения

{ тип_поля_1 имя_поля_1;

7

тип поля_2 имя_поля_2;

тип поля_N имя_поля_N; } список_переменных;

Пример объединения для преобразования целого типа в символьный: union charint

{int i; /* данные типа int */

char c[2];

/*

символьные

данные */

};

/*

charint */

 

Для работы с объединениями необходимо описывать переменные объявленного ранее типа объединения. Формат объявления переменной объединения:

имя_типа_объединения имя_переменой;

Пример: charint x;

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

Доступ к полям переменных объединений аналогичен структурам и производится

с помощью конструкции составного имени.

Пример программы,

преобразующей вводимое число типа long int в два

значения типа signed int и

символьный тип.

#include <conio.h>

/*

подключение модуля консольных функций */

#include <stdio.h>

/*

подключение функций ввода-вывода языка С */

union transint

/*

Описание типа объединения */

{ long int i;

/*

Поле типа long int */

int shi[2];

/*

Поле массива элементов int */

char ch[4];

/*

Поле строки двух символов */

};

/*

Конец описания типа */

int main(void)

/*

Главная функция */

{ transint dig;

/* переменная

типа

объединения */

printf("\nВведите число типа int : ");

/*

вывод экранного

запроса */

scanf("%i",&dig.i);

/*

ввод числа

типа

int с клавиатуры */

 

printf("\nМладший

байт

числа : %X",dig.shi[0]);

/* вывод преобразования */

 

printf("\nСтарший

байт

числа : %X",dig.shi[1]);

 

 

printf("\nСтрока числа

: %s",dig.ch);

/* Вывод результата - строки*/

 

getch();

 

/* Приостановка закрытия окна консоли */

 

return 0;

 

/* Код успешного завершения */

}

/* main

*/

 

 

 

6.6 Ссылочный тип данных и указатели

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

адресов ячеек оперативной

памяти,

которые связанны с некоторыми данными.

Переменные ссылочного типа называются

указателями. Переменная указатель содержит

адрес начала расположения

данных

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

компьютера при выполнении программы.

 

 

 

 

 

Объявляются переменные указатели в следующем формате:

 

 

 

Имя_базового_типа *имя_указателя;

 

 

 

 

 

В

качестве

базового

типа

используются

как

скалярные,

так

и

структурированные типы, которые указывают тип данных, которые хранятся в ячейках

памяти. В

качестве базового типа

возможно также использование и ссылочного типа.

Примеры

 

 

long int *pli;

/*

указатель на длинное целое */

float *vector[12];

/*

объявление массива указателей */

int

* pi;

 

 

char ** cpp;

/*

указатель на указатель на символ */

int

(*vp)[10];

/*

указатель на вектор из 10 целых */

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

помощью оператора &. Формат получения

адреса при присваивании

имя_указателя = &переменная_базового_типа;

Пример

 

 

 

float x, *px;

/*

Объявление

вещественной переменной и указателя*/

px = &x;

/*

Взятие адреса у вещественного числа */

8

Чтобы получить значение данных, которое хранится по адресу указателя, используется оператор *, который ставится перед указателем. Эта основная операция над указателем называется разыменование (ссылка на объект, на который указывает указатель) или косвенным обращением. Операция разыменования - это унарное * (префиксное). Формат операции разыменовывания:

переменная_базового_типа = *переменная_указатель;

Примеры: x = *px; /* передача в х значения, хранимого по адресу px */ char c1 = 'a';

char* p = &c1; /* в p хранится адрес c1 char c2 = *p; // c2 = 'a'

Переменная, на которую указывает p,- это c1, а значение, которое хранится в c1, это 'a', поэтому присваиваемое c2 значение *p есть 'a'.

#include <conio.h>

// Пример использования указателей для доступа к переменным

#include <stdio.h>

 

 

 

 

int main(int argc,

char* argv[])

 

 

 

{ float a, b, c;

 

/* переменные */

 

float *pa=&a, *pb=&b, *pc=&c; /*

указатели на переменные */

printf("\na=");

 

/*

ввод a */

 

scanf("%f",&a);

 

 

 

 

printf("\nb=");

 

/*

ввод b */

 

scanf("%f",&b);

 

 

 

 

(*pc)=(*pa)+(*pb);

/*

расчет с через разыменовывание указателей */

printf("\n c= %4.1f address %p",

c, pc);

/* вывод результатов */

getch();

 

 

 

 

return 0; }//---------------------------------------------------------------------------

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

int *p , m[100];

//

объявления указателя и вектора;

p=m;

//

присваивание адреса указателю на начало массива

Для доступа к элементу массива с помощью указателя, нужно задать смещение адреса в указателе с помощью конструкции:

*(указатель + смещение)

Пример записи в 10-й элемент целочисленного вектора значение 256

int vector[100], *pv;

// объявление

вектора

и указателя;

pv =

vector;

//

присваивание указателю адреса массива

*(pv

+10)=256;

//

присвоение

значения элементу через указатель

К переменным-указателям

применяются следующие

классические операции:

1)присваивания, при этом следует внимательно следить, чтобы указатели имели одинаковый базовый тип;

2)получение адреса от переменной одинакового базового типа;

3) сложения и вычитания;

4) сравнения;

5)вызов функции с помощью указателя;

6)создания динамических переменных.

Возможна ситуация, когда указатель хранит адрес другого указателя, тогда имеет место многочисленное перенаправление. Пример объявления такого указателя:

int **pp;

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

#include <stdio.h> #include <conio.h> int i, *p;

int main(void)

{p=&i; /* присвоить p адрес i */ printf("\nЧисло типа int : "); scanf("%i \n", &i);

printf("\n %i по адресу %p ",i, p); getch();

return 0;

}

/* main */

9

В примере показано, что для вывода значения указателя используется в функции printf спецификатор p.

Возможна начальная инициализация указателя, например, строковой константой char *p = “Электропривод и АПУ”;

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

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

#include <iostream.h>

#include <conio.h>

 

 

int main()

 

 

{

float M[10];

//

вектор

 

float *PM=M;

//

указатель на вектор

 

for(int i=0;i<10;i++)

{cout << "M[" << i << "]="; cin >> M[i]; M[i]=M[i]*M[i];

} // конец цикла for для ввода матрицы for(int i=0; i<10; i++)

{cout<<"M["<<i<<"]="<<(*PM)<< endl; // вывод матрицы через указатель

PM++;

// перенаправление указателя на следующий элемент

} // конец цикла for для вывода матрицы

getch();

 

return 0;

 

}//---------------------------------------------------------------------------

 

При использовании

указателя на структуры и объединения для доступа к

данным полям таких переменных возможно использовать оператор -> в формате наименование_указателя –> имя_поля_структуры;

Пример задания комплексного числа 10-j20 указателем на структуру: struct TComplex // Структура комплексного числа

{double Re, Im; // Действительная и мнимая части числа } Xcomp; // Список статических переменных

TComplex *pcoml=&Xcomp; Pcomp->Re=10; Xcomp.Im=-20;

6.7 Динамические переменные

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

Динамическое распределение памяти в языке С реализуется в модуле stdlib.h

спомощью функций:

-malloc – создание динамической переменной указанного размера в формате; указатель = (базовый_тип *) malloc(число_байт_под_данные)

-free(указатель) – удаление динамической переменной.

Число

байт под

данные

можно определить используя функцию sizeof.

Пример объявления динамической переменной-вектора из 10 значений типа

float с проверкой

успешного

создания

float

*pfd;

/*

создание указателя */

if((pfd = (float *) malloc(10*sizeof(float)))==NULL)

{printf(“\nМало свободной памяти”); getch();

return -1; } // if

 

 

 

10

 

 

free(pfd);

 

/*уничтожение указателя */

 

 

Пример программы определяющей среднее значение вещественного массива с

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

#include <stdio.h>

 

 

#include <conio.h>

 

 

float

*pfm; /* Вектор заданный с помощью указателя */

float

middle=0; /*

среднее значение */

 

int main(int argc,

char* argv[])

 

{ int

N;

/*

Число элементов массива

*/

int

i=0;

/*

Счетчик цикла */

 

printf("\nN=");

/* Вывод на экран запроса */

scanf("%d",&N);

/* Ввод числа элементов массива */

pfm

= (float*) malloc(N*sizeof(float)); /*создание динамической переменной*/

if (pfm==NULL) {

printf("Not memory");

/* контроль наличия памяти */

 

 

 

getch();

 

 

 

 

return -1;

/* код ошибки */

}

for(i=0;i<N;i++)

{printf("\nM[%2d]=",i);

scanf("%f",pfm);

middle+=*pfm;

pfm++;

} /* конец цикла for */

 

free(pfm);

/* уничтожение динамического массива и Освобождение памяти */

printf("\nmiddle=%f",middle/N);

/* вывод результата */

getch();

/* приостановка

закрытия окна консоли */

return 0;

/* возврат кода

успешного завершения */

}/*----------------------------------------------------------------------

 

 

В языке

С++ для этих целей

используются операторы new и delete. Создание

динамической переменной выполняется в форме

указатель = new тип_переменной;

Удаление динамической переменной delete переменная_указатель;

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

delete [] указатель_массива;

Операция new создает динамическую переменную указанного типа, распределив (при возможности) требуемое число байт в свободной области памяти (которую называют "кучей"). Продолжительность существования динамической переменной - с момента создания и до операции delete, отменяющей распределенную для неѐ память, либо до конца работы программы.

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

Пример создания динамической переменной целочисленного тензора

int *pmatr;

// Создание

указателя

pmatr = new int[3][10][12];

//

Выделение динамической памяти указателю

 

 

 

delete nameptr;

//

Удаление

переменной и освобождение памяти

Пример программы считывающей действительный вектор с клавиатуры и записывающий его элементы в текстовый файл с помощью динамической переменной на языке С++.

#include <iostream.h> #include <fstream.h> #include <conio.h>

float *pfm; // Указатель на вектор

int main(int argc, char* argv[]) //---------------------------------------

{char *fname; // строка-указатель на имя файла int N; // Число элементов массива

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]