double arrow

Динамические многомерные массивы

По аналогии с одномерными массивами многомерные массивы могут создаваться динамически. Рассмотрим пример создания двухмерного массива 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; // Объявлении переменных одновременно со структурой

Или


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



Сейчас читают про: