Перейти к основному содержимому

Массивы

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

тип_переменной название_массива [длина_массива]

После типа переменной идет название массива, а затем в квадратных скобках размер массива - максимальное количество значений, которое можно поместить в массив.

Важно !

Все элементы массива располагаются в памяти подряд !!!

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

#include <stdio.h>

int main(void)
{
int numbers[4];
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;

printf("numbers[0] = %d \n", numbers[0]); // 1 - первый элемент
printf("numbers[2] = %d \n", numbers[2]); // 3 - третий элемент
return 0;
}
Важно !

Нумерация элементов начинается с нуля, поэтому первый элемент массива имеет индекс 0, а не 1 - numbers[0]

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

int numbers[] = { 1, 2, 3, 5 };

Также, можно инициализировать не все элементы, но в этом случае следует указывать размер массива:

int numbers[5] = { 10, 12}; // 10, 12, 0, 0, 0

Можно инициализировать значения не по порядку:

int numbers[5] = { [1]=11, [3] = 13 };

Внимание !

Если начальные значения не заданы, то в памяти лежит мусор !

Размер массива можно установить динамически с помощью переменной/константы:

#include <stdio.h>

int main( void )
{
int maxSize;
printf ("Input num = ");
scanf("%d", &maxSize);
int array[maxSize];
array[0] = 1;
array[1] = 2;
array[2] = 3;
for (int i = 0; i < maxSize; i++)
{
printf ("%d = %d\n", i, array[i]);
}
return 0;
}

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

const int numbers[3] = {11, 12, 13};

Многомерные массивы

Часто в программах удобнее работать с многомерным массивом - массив, элементами которого являются другие массивы. Для примера определим двухмерный массив чисел:

int numbers[3][2] = { {1, 2}, {4, 5}, {7, 8} };

Здесь массив numbers имеет три элемента (3 строки), а каждый из этих элементов сам представляет массив из двух элементов (2 столбцов).

Для понимания !

Двухмерные и прочие многомерные массивы фактически являются абстракциями. В реальности все массивы являются одномерными и представляют сплошной блок памяти:

int numbers[3][2] = { 1, 2, 4, 5, 7, 8 };

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

#include <stdio.h>

int main(void)
{
int numbers[3][2] = { {1, 2}, {4, 5}, {7, 8} };
// проходим по 3 строкам таблицы
for(int i = 0; i < 3; i++)
{
// проходим по 2 столбцам каждой строки
for(int j = 0; j < 2; j++)
{
printf("numbers[%d][%d] = %d \n", i, j, numbers[i][j]);
}
}
return 0;
}

Размер и количество элементов массива

Для того, чтобы узнать размер массива, можно использовать оператор sizeof, который возвращает размер всего массива в байтах в виде значения типа size_t:

#include <stdio.h>

int main( void )
{
int numbers[] = { 5, 6, 7};
size_t size = sizeof(numbers);
size_t count = sizeof(numbers) / sizeof(numbers[0]);

printf("numbers size: %zu \n", size); // numbers size: 12
printf("count: %zu \n", size); // count: 12

return 0;
}

Так как size_t фактически является псевдонимом для типа unsigned long long, то есть 64-разрядное положительное число, то для его вывода на консоль применяется спецификатор %zu.

Количество элементов в массиве можно вычислить разделив размер всего массива на размер одного элемента:

size_t count = sizeof(numbers) / sizeof(numbers[0]);

Пердача массива в функцию

В языке Си имя массива — это указатель на самый первый элемент массива. Поэтому:

:::dander Так делать нельзя !

int a[5];
int b[5];
a = b;

Можно создать обычный указатель, установить его на нулевой элемент массива, а после изменять уже его

Так делать можно !
int a[5];
int *pa;

pa = a; // так можно
pa = &a[0]; // и так

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

Внимание !

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

Сортировка пузырьком

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

Сортировка пузырьком

Напишем программу, получающую данные массива от пользователя и сортирующую этот массив по возрастанию, используя сортировку пузырьком:

#include <stdio.h>

#define MAX_SIZE 5

int Input(int* arr, int n)
{
int i;
for(i=0; i < n; i++)
scanf("%d",&arr[i]);

return i;
}

void Print(int *arr,int len)
{
int i;
for (i = 0; i < len; i++)
printf("%d ",arr[i]);

printf("\n");
}

void SwapArr(int *arr,int i,int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}

void BubbleSort(int* arr,int n)
{
int noSwap;
for (int i = 0; i < n; i++)
{
printf("%d\n",i);
noSwap = 1;
for (int j = n-1; j > i; j--)
{
if( arr[j - 1] > arr[j] )
{
SwapArr(arr,j-1,j);
noSwap = 0;
}
}
if(noSwap)
break;
}
}

int main( void )
{
int arr[MAX_SIZE];

Input(arr, MAX_SIZE);
BubbleSort(arr, MAX_SIZE);
Print(arr, MAX_SIZE);

return 0;
}

В константе MAX_SIZE устанавливается размер массива, функция Input получает значения элементов массива, функция BubbleSort осуществляет сортировку, функция Print выводит значения элементов на консоль. Функция SwapArr является вспомогательной и просто меняет элементы местами.

Самостоятельная работа

Задачи

Задача 1

Ввести с клавиатуры массив из 5 элементов и умножить все его элементы на число 3. Распечатать полученный массив.

Задача 2

В массиве из предыдущей задачи:

  • Найти минимальный элемент в массиве.
  • Найти максимальный элемент в массиве.
  • Поменять местами максимальный и минимальный элемент в массиве.

Задача 3

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

Задача 4

Циклически сдвинуть массив влево на 1 элемент.

Задача 5

Сделать реверс массива.

Задача 6

Отсортировать массив по возрастанию.