Что такое одномерный массив в языке С
В языке C одномерный массив — это линейная структура данных, которая хранит набор элементов одного типа. Каждый элемент имеет свой индекс, позволяющий получить к нему доступ.
Длина массива и его тип данных определяются на этапе объявления, после чего не могут изменяться (в стандарте C99 появилась возможность задавать длину переменной, но ей стоит пользоваться с осторожностью, так как есть риск переполнения стека). Каждая запись располагается в памяти последовательно и занимает одинаковый ее объем (размер конкретного элемента определяется его типом). Индексация массивов в C, как и во многих других языках программирования, начинается с нуля.
Как объявить и инициализировать массив
Чтобы объявить массив в C, нужно указать тип данных, который будет храниться, имя и длину — количество элементов (строго целое положительное число, которое указывается в квадратных скобках). Синтаксис выглядит так:
elements_type array_name[array_size];
Примеры объявления:
int numbers[10]; /* Переменная numbers может хранить 10 целых чисел*/
float prices[5]; /* Переменная prices может хранить 5 чисел с плавающей точкой*/
char letters[26]; /* Переменная letters может хранить 26 символов*/
int numbers[0]; /* Такая запись недопустима*/
Объявление и инициализацию можно совместить: для этого нужно указать значение в фигурных скобках. Например:
int numbers[5] = {1, 2, 3, 4, 5}; /* numbers[0] = 1, numbers[1] = 2 и так далее*/
Если указать только часть элементов от объявленного размера, то остальные инициализируются нулями:
int numbers[5] = {1, 2, 3}; /* [1, 2, 3, 0, 0]*/
Также можно выполнить инициализацию исключительно нулями двумя способами:
int numbers[5] = {0}; /* [0, 0, 0, 0, 0]*/
for (int i = 0; i < 5; i++) {
numbers[i] = 0;
} /* [0, 0, 0, 0, 0]*/
Если не указать длину явно, но выполнить инициализацию, то количество символов определится автоматически:
int numbers[] = {1, 2, 3, 4, 5};
Инициализацию можно выполнить, не указывая элементы по порядку:
int numbers[5] = {[1] = 2, [4] = 5}; /* [0, 2, 0, 0, 5]*/
Другие способы инициализации рассмотрим далее.
Как заполнить массив значениями
Часто массивы заполняются значениями в циклах. Рассмотрим примеры таких операций.
- Чтобы заполнить массив одинаковыми числами, например нулями, можно написать следующий код:
int numbers[5];
for (int i = 0; i < 5; i++) {
numbers[i] = 0; /* [0, 0, 0, 0, 0]*/
}
- Чтобы заполнить последовательностью чисел, например, от 1 до 5, подойдет такая программа:
int numbers[5];
for (int i = 0; i < 5; i++) {
numbers[i] = i + 1; /* [1, 2, 3, 4, 5]*/
}
- Также можно заполнять с помощью формул, например, чтобы получить квадраты чисел от 1 до 5:
int numbers[5];
for (int i = 0; i < 5; i++) {
numbers[i] = (i + 1) * (i + 1); /* [1, 4, 9, 16, 25]*/
}
- Чтобы заполнить данными, которые ввел пользователь, можно использовать такой код:
int numbers[5];
printf("Введите 5 чисел: "); /* Допустим, пользователь ввел 1 8 77 4 6*/
for (int i = 0; i < 5; i++) {
scanf("%d", &numbers[i]); /* [1, 8, 77, 4, 6]*/
}
return 0;
Иногда программисты реализуют и собственные функции для заполнения — так код можно использовать повторно:
void fillArray(int arr[], int size, int value) {
for (int i = 0; i < size; i++) {
arr[i] = value; /* Заполняем значениями value*/
}
}
int main() {
int numbers[5];
fillArray(numbers, 5, 42); /* [42, 42, 42, 42, 42]*/
return 0;
}
Еще один способ заполнения — перенос значений из одного массива в другой:
int source[] = {1, 2, 3, 4, 5};
int target[5];
for (int i = 0; i < 5; i++) {
target[i] = source[i]; /* Здесь происходит перенос*/
}
В ситуациях, когда массив не должен изменяться, его можно сделать константным с помощью модификатора const:
#include <stdio.h>
int main() {
const int numbers[5] = {1, 2, 3, 4, 5}; /* Будет доступен для чтения, но при попытке изменить содержимое
возникнет ошибка*/
numbers[0] = 10;
return 0;
}
/* Вывод:
error: assignment of read-only location 'numbers[0]'*/
Отдельно рассмотрим заполнение строковыми значениями, так как это популярный вариант использования одномерных массивов. Чтобы все работало без ошибок, строки должны заканчиваться символом NULL (\0), поэтому к размеру прибавляется единица.
Массив символов можно объявить так же, как массив чисел:
/* Несмотря на то что символов 8, указывается длина 9, так как нужно прибавить 1 для \0*/
char name[9] = {'G', 'i', 't', 'V', 'e', 'r', 's', 'e', '\0'}; /* Получится строка GitVerse*/
Но в работе со строковыми значениями особенно удобно пользоваться автоматическим определением длины (здесь указываются уже не символы, а строки):
char name[] = "GitVerse"; /*Автоматически будет добавлен и символ \0*/
Если указанный размер меньше фактической длины строки, то пользователь получит ошибку или предупреждение (в зависимости от компилятора):
#include <stdio.h>
int main() {
char greeting[4] = "Hello";
printf("%s\n", greeting);
return 0;
}
/* Вывод:
warning: initializer-string for array of 'char' is too long*/
Если строку вводит пользователь, то, в отличие от ситуации с числами, добавляется функция fgets, которая проверяет длину введенной строки:
#include <stdio.h>
int main() {
char name[50];
printf("Введите ваше имя: ");
fgets(name, 50, stdin);
printf("Привет, %s\n", name);
return 0;
}
Как работать с элементами массива
Первая операция, с которой стоит познакомиться, — это чтение записей и их вывод на экран:
#include <stdio.h>
int main() {
int numbers[5] = {10, 20, 30, 40, 50};
/* Для доступа к конкретным записям используются индексы: получим первый, второй и последний
элементы*/
int first = numbers[0];
int second = numbers[1];
int last = numbers[4];
/* Вывод на экран*/
printf("Первый элемент: %d\n", first);
printf("Второй элемент: %d\n", second);
printf("Последний элемент: %d\n", last);
/* Чтобы получить все записи, используется цикл. В этом случае выведем их вместе с
порядковыми номерами*/
printf("Все элементы:\n");
for (int i = 0; i < 5; i++) {
printf("numbers[%d] = %d\n", i, numbers[i]);
}
return 0;
}
/* Вывод:
Первый элемент: 10
Второй элемент: 20
Последний элемент: 50
Все элементы:
numbers[0] = 10
numbers[1] = 20
numbers[2] = 30
numbers[3] = 40
numbers[4] = 50
*/
/* Также для вывода можно воспользоваться указателем (в C имя массива — это указатель на элемент с
индексом 0)*/
int *ptr = numbers;
printf("%d\n", *(ptr + 2)); /* Вывод элемента с индексом 2 */
Далее рассмотрим изменение записей:
#include <stdio.h>
int main() {
int numbers[5] = {1, 2, 3, 4, 5};
printf("До изменения: ");
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
/* Здесь происходит изменение записи — для этого также указывается индекс и новое значение*/
numbers[2] = 10; /* Третий элемент равен 10 вместо 3*/
printf("После: ");
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}
/*Вывод:
До изменения: 1 2 3 4 5
После: 1 2 10 4 5
*/
Также существует оператор sizeof, с помощью которого можно узнать размер массива в байтах:
#include <stdio.h>
int main() {
int numbers[5] = {1, 2, 3, 4, 5};
/*Выводим размер всего массива*/
printf("Размер numbers: %zu байт\n", sizeof(numbers));
/*Выводим размер одного элемента*/
printf("Размер одного элемента: %zu байт\n", sizeof(numbers[0]));
/*Выводим количество записей в массиве: для этого общий размер делим на размер одного
элемента*/
printf("Количество: %zu\n", sizeof(numbers) / sizeof(numbers[0]));
return 0;
}
/*Вывод:
Размер numbers: 20 байт
Размер одного элемента: 4 байт
Количество: 5
*/
В случае со строками ситуация немного отличается. Чтобы найти их длину, нужно вычесть единицу, которая выделяется для \0:
#include <stdio.h>
int main() {
char str[] = "Gitverse";
printf("Размер str: %zu байт\n", sizeof(str));
printf("Размер одного элемента: %zu байт\n", sizeof(str[0]));
printf("Длина строки: %zu символов\n", sizeof(str) - 1);
return 0;
}
/*Вывод:
Размер str: 9 байт
Размер одного элемента: 1 байт
Длина строки: 8 символов
*/
Как уже отмечалось, в C нет встроенных методов для обработки массивов: поиска, сортировки, добавления, удаления содержимого и так далее. Поэтому подобные операции программисту необходимо реализовывать самостоятельно.
Например, чтобы найти максимальное значение, подойдет такая программа:
#include <stdio.h>
int main() {
int arr[] = {1, 5, 2, 4};
int max = arr[0];
for (int i = 1; i < 4; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
printf("%d\n", max);
return 0;
}
/*Вывод: 5*/
Примеры использования одномерных массивов
Как правило, одномерные массивы применяются для хранения данных и проведения различных операций над ними. Результаты этих вычислений нужны программисту для решения своих задач.
Например, можно реализовать алгоритм сортировки — в этом случае пузырьковой:
#include <stdio.h>
void bubbleSort(int arr[], int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main() {
int numbers[8] = {121, 3, 15, 1711, 24, 1, 37, 115};
printf("До сортировки: ");
for (int i = 0; i < 8; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
bubbleSort(numbers, 8);
printf("После сортировки: ");
for (int i = 0; i < 8; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}
/*Вывод:
До сортировки: 121 3 15 1711 24 1 37 115
После сортировки: 1 3 15 24 37 115 121 1711
*/
Второй пример — поиск среднего значения:
#include <stdio.h>
int main() {
/*Допустим, имеются данные о средней дневной температуре в феврале*/
float temperatures[28] = {23.4, 25.1, 22.8, 24.5, 26.2, 21.9, 23.0, 22.3, 23.8, 25.1, 27.2, 26.4, 26.1, 25.8, 26.2, 27.0, 27.8, 27.5, 28.0, 28.9, 28.5, 29.0, 28.7, 29.3, 28.5, 27.3, 27.9, 28.4};
/*Суммирование всех значений*/
float sum = 0;
for (int i = 0; i < 28; i++) {
sum += temperatures[i];
}
float average = sum / 28;
printf("Средняя температура за февраль: %.2f\n", average);
return 0;
}
/*Вывод:
Средняя температура за февраль: 26.31
*/
Еще один пример — реализация переворота строки:
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World!";
/*strlen для поиска длины str*/
int length = strlen(str);
printf("Исходный вариант: %s\n", str);
for (int i = 0; i < length / 2; i++) {
char temp = str[i];
str[i] = str[length - i - 1];
str[length - i - 1] = temp;
}
printf("Перевернутая строка: %s\n", str);
return 0;
}
/*Вывод:
Исходный вариант: Hello, World!
Перевернутая строка: !dlroW ,olleH
*/
Для работы с таблицами или матрицами одномерные массивы не используются, но они могут быть представлены как единичные столбцы.
Таким образом, одномерные массивы удобны для упорядоченного хранения разных типов данных, они предоставляют возможность эффективной работы с памятью и быстрый, простой доступ к записям. При этом стоит помнить, что длина массивов ограничивается заранее и есть риск выхода за ее пределы. Также в С нет встроенных методов для обработки элементов.