Массивы
Чаще всего программы обрабатывают не одиночные переменные, а наборы данных. Для хранения таких наборов в языке Си используются массивы. Массив представляет собой набор однотипных значений. Объявление массива выглядит следующим образом:
тип_переменной название_массива [длина_массива]
После типа переменной идет название массива, а затем в квадратных скобках размер массива - максимальное количество значений, которое можно поместить в массив.
Все элементы массива располагаются в памяти подряд !!!
Каждый элемент массива имеет свой номер, который называется индексом. По этому индексу можно обращаться к отдельным элементам. Например:
#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
Отсортировать массив по возрастанию.