Студопедия — Лабораторная работа № 7. Указатели. Динамическое управление памятью
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Лабораторная работа № 7. Указатели. Динамическое управление памятью






 

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

 

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

Указатель — это без знаковое целое, используемое для хранения адреса какого-либо участка памяти. Указатель всегда является переменной величиной. Всякий указатель используется для работы с данными, которые имеют какой-то свой тип и, соответственно, свой размер, например, double или int. Формальное описание указателя такое:

Тип_данных * Имя_указателя;

где

· Тип_данных — любой ранее определённый тип (стандартный или пользовательский);

· * — знак «звёздочка» здесь является признаком того, что речь идёт об указателе;

· Имя_указателя — определяется по общим правилам (как для любого идентификатора пользователя).

Запись double *u; необходимо понимать: «u — это указатель на объект типа double». Значение указателя u в момент выделения памяти не определено. Запись double a = 2.5; u = & a; настраивает указатель на переменную а. Здесь знак & означает вычисление адреса, т.е. мы вычисляем адрес переменной a и записываем его в ячейку u. Если применить операцию разыменования:

cout < < *u < < endl;

этим оператором мы выводим на экран монитора содержимое переменной a, т.к. указатель u настроен на эту же переменную a. Можно и изменить значение переменной a, используя указатель u:

*u = 11.3;

cout < < a < < endl;

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

Указатель = new Тип [ Количество_элементов ];

где Тип — это тот же тип данных, что и тип, на который рассчитан указатель.

Запись оператора для освобождения динамической памяти:

delete [] Указатель;

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

Так как строк в матрице может быть достаточно много, а указатели, используемые для выделения памяти под каждую строку матрицы, имеют один и тот же тип, то эти указатели есть смысл объединить в одномерный массив указателей. Естественно, память под массив указателей также будем выделять динамически. А адрес этого массива указателей будем хранить в указателе на указатель. На рисунке 8 покажем, как это может выглядеть:


Рис. 8. Создание динамического массива

Здесь a — это указатель на массив указателей. Формальное описание для него:

Тип ** имя_указателя; a[i] — указатели на строки матрицы, в которых будут в дальнейшем хранится данные, т.е. элементы матрицы a[i][j].

 

Задание

1. Изучить: правила использования динамической памяти; указатель и его назначение; формат определения указателя; способы инициализации указателя; операции над указателями; связь массива с указателем; способы доступа к элементам массива через указатель; оператор косвенного доступа.

2. Разработать алгоритм решения в соответствии с заданием.

3. Составить программу решения задачи.

4. Подготовить тестовый вариант программы и исходных данных.

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

 

Пример выполнения работы

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

Объявим переменные n и m, которые задают размер матрицы; переменную a, которая является указателем на указатель для выделения динамической памяти; переменные i и j для индексов строк и столбцов матрицы. Для матрицы выделяется динамическая память; в память для матрицы с клавиатуры введены числа.

void main()

{

int n, m; // Переменные для размера матрицы не определены.

int **a; // Определяем a- указатель на указатель для динамической

// памяти матрицы.

int i, j;

clrscr();

cout < < “Введи количество строк и количество столбцов матрицы: ”;

cin > > n > > m; // Вводится размер матрицы.

a = new int *[n]; // Выделяется память под массив указателей.

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

a[i] = new int[m]; // Выделяется память под элементы i-той строки

cout < < “Введи элементы матрицы: \n”;

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

for (j = 0; j < = m-1; j++)

{ printf(" a[ %d, %d ]= ", i, j); // Поясняющий текст.

scanf(" %d", & a[i][j]); }

cout < < “Введена матрица: \n”;

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

{ for (j = 0; j < = m-1; j++)

printf(" %d ", a[i][ j]); // Вывод элемента i-той строки матрицы.

printf(“\n”); // Перевод курсора на новую строку монитора.

}

getch(); }

 

Условие: Пусть задан одномерный массив вещественных чисел x[0], x[1],..., x[n-1] (n - заданное натуральное число). Требуется получить и распечатать элементы этого массива в следующем порядке: x[k+1], x[k+2],..., x[n-1], x[0], x[1],..., x[k], (где k - индекс первого по порядку максимального элемента массива x). Физическое расположение в памяти элементов массива x не изменять. Для решения задачи использовать вспомогательный массив указателей.

 

#include < windows.h>

#include < wincon.h>

#include < stdio.h>

#include< time.h>

#include< stdlib.h>

void printp(int** p, int n);

void print(int* x, int n);

void rnd_vector(int* x, int n, int a, int b);

int ind_max(int* x, int n);

void formp(int* x, int** p, int n, int k);

void main()

{

SetConsoleOutputCP(1251);

srand ((unsigned)time(NULL));

const int n=10;

int a[n];

int imax; //Индекс максимального элемента массива

rnd_vector(a, n, 1, 50);

print(a, n);

puts(" ");

imax=ind_max(a, n);

int* r[n];

formp(a, r, n, imax);

printp(r, n);

}

/*

Функция заполняет массив x, состоящий из n элементов, случайными целыми числами из промежутка [a; b].

*/

void rnd_vector(int* x, int n, int a, int b)

{

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

x[i]=(int)((double)rand()/RAND_MAX*(b-a+1)+a);

}

/*

Функция печатает массив x, состоящий из n элементов, на экране.

*/

void print(int* x, int n)

{

int i;

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

printf(" %4d", x[i]);

puts(" ");

}

/*

Функция возвращает индекс первого по порядку максимального элемента массива x размера n.

*/

int ind_max(int* x, int n)

{

int max, ind;

max=x[0];

ind=0;

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

if (x[i]> max)

{

max=x[i];

ind=i;

}

return ind;

}

/*

Функция печатает на экране значения, размещённые по адресам p[0], p[1], …, p[n-1], где p - массив, каждый элемент которого есть указатель на тип int, n – размер массива p.

*/

void printp(int** p, int n)

{

int i;

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

printf(" %4d", *p[i]);

puts(" ");

}

/*

Функция заполняет массив указателей p адресами элементов массива x по заданному правилу (см. условие задачи).

n – размер массива p и массива x; k – индекс первого по порядку максимального элемента массива x.

*/

void formp(int* x, int** p, int n, int k)

{

int i, j;

for (i=0, j=k+1; j< n; i++, j++)

p[i]=& x[j];

for (j=0; j< =k; i++, j++)

p[i]=& x[j];

}

 

Условие: Задан одномерный массив целых чисел x. Получить новый массив y, состоящий из тех элементов массива x, которые кратны 7. Порядок следования и количество повторений этих чисел в исходном массиве сохранить. Оба массива разместить в динамической памяти.

Например:

x: 35, 11, 10, 7, 11, 35.

y: 35, 7, 35.

 

#include < windows.h>

#include < wincon.h>

#include < stdio.h>

#include< time.h>

#include< stdlib.h>

int* rand_array(int n, int a, int b);

void print_array(int*x, int n);

void main()

{

SetConsoleOutputCP(1251);

srand ((unsigned)time(NULL));

int n;

puts(" Введите число элементов исходного массива: ");

scanf(" %d", & n);

int*a; //Объявлен указатель на исходный массив

a=rand_array(n, 0, 50);

puts(" Исходный массив: ");

print_array(a, n);

int k=0;

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

if (a[i]%7==0)

k++;

if (k==0)

{

puts(" Новый массив пустой.");

free(a);

return;

}

int*b; // Указатель на массив-результат

b=(int*)malloc(k*sizeof(int));

k=0;

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

if (a[i]%7==0)

b[k++]=a[i];

puts(" Новый массив: ");

print_array(b, k);

free(a);

free(b);

}

/*

Функция создаёт динамический массив из n элементов, заполняет его случайными целыми числами из промежутка [a; b] и возвращает указатель на начало этого массива.

*/

int* rand_array(int n, int a, int b)

{

int*x;

x=(int*)malloc(n*sizeof(int));

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

x[i]=(int)((double)rand()/RAND_MAX*(b-a+1)+a);

return x;

}

/*

Функция печатает массив x на экране.

*/

void print_array(int* x, int n)

{

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

printf(" %5d", x[i]);

puts(" ");

}

 

Задания для самостоятельного выполнения

Обязательно использовать динамическую память.

1. Дополнить матрицу строкой, содержащей максимумы по столбцам.

2. Дополнить матрицу столбцом, содержащим максимумы по строкам.

3. Вычислить произведение двух матриц.

4. Вычислить произведение матрицы на вектор.

5. Транспонировать матрицу.

6. Найти максимальный элемент матрицы.

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

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

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

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

11. Поменять местами строки матрицы с номерами i и j.

12. Поменять местами столбцы матрицы с номерами i и j.

13. В матрице найти строку, состоящую только из отрицательных чисел.

14. Проверить матрицу на симметричность.

15. Проверить совпадение двух матриц.

16. Найти минимальный элемент матрицы.

17. Проверить, является ли матрица верхней треугольной.

18. Удалить из матрицы дублирующие строки.

19. Удалить из матрицы дублирующие столбцы.

20. Проверить, является ли матрица нижней треугольной.

21. Подсчитать количество различных элементов матрицы.

22. В матрице найти столбец, состоящий только из отрицательных чисел.

23. Определить в матрице строку с наименьшей суммой элементов.

24. Определить в матрице столбец с наименьшей суммой элементов.

25. Заменить в матрице строку с номером i на сумму строк с номерами i и j. Строку с номером j удалить.

26. Определить номер строки матрицы, в которой находится максимальная сумма элементов столбцов с номером k и l.

27. Определить в матрице строки, элементы которых расположены по возрастанию.

Контрольные вопросы

1. Указать основные правила организации вложенных циклов.

2. Указать способы выхода из внутреннего цикла.

3. Как организовать вывод матрицы в общепринятом виде?

4. Как организовать вывод нижней треугольной матрицы в общепринятом виде?

5. Как организовать ввод матрицы размером N x M элементов?

6. Что такое указатель?

7. Как объявить указатель заданного типа с именем p?

8. Можно ли инициализировать указатель кодом int *p = 0?

9. Можно ли инициализировать указатель кодом int *p = NULL?

10. Дан код int *p. Объясните результат выполнение директивы p = new int;

11. Дан код int *p. Объясните результат выполнения директив:

p = new int;

p = new int;

p = new int;

p = new int;

p = new int;

12. Дан код int *p. Можно ли записать следующий оператор: p = p + 5;

13. Дан код int *p. Объясните результат выполнения директивы cout < < *p.

14. Чем отличается указатель типа int от указателя типа float.

15. Дан код int x = 2; Можно ли записать директиву cout < < *(& x) и

если да, то какой результат появится на экране.

16. Дан код int x[10]. Объясните результат выполнения кода cout < < x.

17. Дан код int x[10]. Можно ли записать выражение x& x[5] и если да, чему равно значение данного выражения.

18. Дан код int *p, x[10]; Можно ли записать p = x.

19. Даны коды int *p, x[10]; p = x; Можно ли записать p++, x++.

20. Дан код int x[10], i. Объясните результат выполнения кода cout < < (x+i).

21. Дан код int x[10], i. Чему равен результат выражения *(x+i) == x[i].

22. Дан код int x[10], i. Чему равен результат выражения *(x+i) < x[i]

23. Дан код int *p. Объясните результат выполнения директивы cout < < p.

24. Дан код int x[10], i. Чему равен результат выражения (x+i) < & x[i]

25. Дан код int *x[10]. Объясните результат выполнения данного кода.

26. Как связано понятие указателя с понятием косвенного доступа к информации?

27. Связь двумерного массива с указателем.

 

 







Дата добавления: 2014-11-10; просмотров: 1739. Нарушение авторских прав; Мы поможем в написании вашей работы!



Шрифт зодчего Шрифт зодчего состоит из прописных (заглавных), строчных букв и цифр...

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

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

Функция спроса населения на данный товар Функция спроса населения на данный товар: Qd=7-Р. Функция предложения: Qs= -5+2Р,где...

Тема: Составление цепи питания Цель: расширить знания о биотических факторах среды. Оборудование:гербарные растения...

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

Типовые примеры и методы их решения. Пример 2.5.1. На вклад начисляются сложные проценты: а) ежегодно; б) ежеквартально; в) ежемесячно Пример 2.5.1. На вклад начисляются сложные проценты: а) ежегодно; б) ежеквартально; в) ежемесячно. Какова должна быть годовая номинальная процентная ставка...

Этапы трансляции и их характеристика Трансляция (от лат. translatio — перевод) — процесс синтеза белка из аминокислот на матрице информационной (матричной) РНК (иРНК...

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

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

Studopedia.info - Студопедия - 2014-2024 год . (0.009 сек.) русская версия | украинская версия