По аналогии с одномерными массивами многомерные массивы могут создаваться динамически. Рассмотрим пример создания двухмерного массива n × m (матрица n × m), при этом значения n и m заранее неизвестны – вводятся с клавиатуры. В примере создается матрица n × m, заполняется случайными числами, выводится на печать, в конце программы память освобождается.
#include <stdio.h>
#include <stdlib.h>
void main()
{
int **p; // Указатель на указатель может быть использован для выделения памяти под
// 2-х мерный массив динамически
int n, m; // Заранее неизвестные размерности массива
int i, j; // Индексные переменные
printf("n="); scanf("%d", &n); // Ввод с клавиатуры числа строк матрицы
printf("m="); scanf("%d", &m); // Ввод с клавиатуры числа столбцов матрицы
p=malloc(n*sizeof(int *)); // Выделяем память под массив указателей
// Выделяем память для каждого указателя в массиве указателей
for(i=0; i<n; i++) p[i]=malloc(m*sizeof(int));
// Заполняем массив (матрицу) случайными числами и печатаем его
|
|
for(i=0; i<n; i++)
{
for(j=0; j<m; j++)
{
p[i][j]=rand() % 100; // Получаем псевдослучайное целое число
printf("%d ", p[i][j]);
}
printf("\n"); // После печать строки матрицы переход на новую строчку
}
// Освобождаем память, порядок освобождения обратен порядку выделения
for(i=0; i<n; i++) free(p[i]); // Освобождаем память для строк матрицы
free(p);// освобождаем память для массива указателей
}
Указатель на массив указателей и указатель на массив
Следует отметить, что с помощью скобок () в языке Си можно создавать указатели разных типов. Существуют указатели на массивы указателей и указатели на массивы заданного типа и заданного числа элементов.
Например:
int ** p1; // Указатель на массив указателей
int (*p2)[10]; // Указатель на массив из 10 элементов типа int
При выполнении арифметических операций с такими указателями будет происходить следующее:
p1++; // Значение адреса увеличится на 4
p2++; // Значение адреса увеличится на 40=4*10 в Win32
Это происходит потому, что при выполнении арифметических операций с указателями за единицу принимается размер объекта в памяти, на который указывает указатель.
В заключение представим пример программы, которая выполняет сортировку элементов массива в порядке неубывания. При сортировке используется алгоритм прямого выбора: в массиве размерности n ищется минимальный элемент, потом минимальный элемент меняется местами с первым элементом, после этого первый элемент будет на своем месте; на следующем шаге рассматривается массив размерности на единицу меньший (без первого элемента) к нему применяется тот же алгоритм, и т.д. Массив в программе создается динамически, размерность вводится с клавиатуры, заполняется случайными числа и выводится на печать до сортировки и после сортировки.
|
|
#include <stdio.h>
#include <stdlib.h>
void main()
{
int *pM; // Указатель на массив
int n; // Число элементов массива
printf("n="); scanf("%d", &n); // Ввод числа элементов
// Выделение памяти для массива
pM=(int *)malloc(n*sizeof(int));
// Заполняем массив псевдослучайными числами в интервале 0..99
for(int i=0; i<n; i++) pM[i]=rand() % 100;
// Печатаем исходный массив
for(int i=0; i<n; i++) printf("%d ", pM[i]);
for(int i=0; i<n-1; i++) // Считаем, что массив начинается с i-го
// элемента
{
int imin=i, // Индекс миниамльного элемента
// (считаем минимальным i-ый элемент)
min=pM[i]; // Значение минимального элемента
// Сравниваем выбранный элемент со всеми последующими
for(int j=i+1; j<n; j++)
if (pM[j]<min) // Нашли элемент меньший чем min
{
min=pM[j];
imin=j;
}
// Минимальный элемент меняем с i-m
pM[imin]=pM[i];
pM[i]=min;
}
// Пеачть массива после сортировки
printf("\n"); // Переход на новую строчку
for(int i=0; i<n; i++) printf("%d ", pM[i]);
}
Термины
Указатель – это переменная, которая хранит адрес участка памяти, выделенного для объектов определенных типов.
Ссылка – это переменная, представляющая новое имя уже существующего объекта, ссылка по своей сути является указателем, но к ней нет необходимости применять операцию * (обращение по адресу) при обращении к объекту, любое обращение к ссылке приводит к обращению к объекту, на который ссылается ссылка.
Массив – это производный тип, представляющий собой множество элементов, все элементы массива имеют один и тот же тип и следуют в памяти друг за другом.
Строка – это символьный массив, заканчивающийся символом с кодом 0 (символ NULL) – это служебный символ, являющийся признаком конца строки.
Лекция 6. Структуры и объединения
Структуры
Дадим следующее определение структуры.
Структура - это производный тип языка Си, включающий в себя множество элементов, элементы следуют в памяти друг за другом и могут быть разнотипными.
Формат определения структуры следующий:
struct [<имя_структурного_типа>]
{
….. // Объявления полей структуры
} [<имя_переменной_струрного_типа>];
Пример:
Struct A
{
int x; // Поле структуры
float y; // Поле структуры
};
После объявления структуры имя структуры является именем нового типа. Аналогично переменным стандартных типов могут объявляться переменные структурного типа, при этом каждая переменная структурного типа имеет свои копии полей структуры в оперативной памяти. Также можно объявлять указатели на структуры, массивы структур, полями структуры могут быть массивы или указатели.
A a1, a2; // Объявление переменных структурного типа
Примечание. Такой формат определения переменных структурного типа разрешен в языке Си++ в исходном Си стандарта ANSI требуется при подобном объявлении переменных структурного типа дополнительно указывать ключевое слово struct:
Struct A a1, a2; // Объявление переменных структурного типа в Си стандарта ANSI
Разрешено объявлять переменные структурного типа одновременно с объявлением структуры и также, если далее переменные этого типа не будут создаваться, то имя структуры может отсутствовать.
Struct A
{
int x; // Поле структуры
float y; // Поле структуры
} a1, a2; // Объявлении переменных одновременно со структурой
Или