Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Язык C

Массивы в C: объявление, инициализация, доступ, многомерные массивы и передача в функции

Что такое массив?

Массив — непрерывная область памяти, хранящая фиксированное число элементов одного типа. Элементы доступны по индексу (0-базированный).

Ключевые свойства:

Объявление и определение

тип имя[размер];           // неинициализированный (мусор, если локальный)
тип имя[размер] = {значения}; // с инициализатором
тип имя[] = {значения};     // размер выводится из инициализатора

Примеры

int scores[100];                    // 100 int, неинициализированы
double prices[5] = {10.5, 20.0, 30.0}; // 3 инициализированы, остальные 0
char name[] = "Hello";              // размер 6 (включая \0)
int matrix[3][4] = {                // 2D массив
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

Инициализация

Доступ к элементам

int arr[5] = {10, 20, 30, 40, 50};
int x = arr[2];    // чтение: 30
arr[2] = 99;       // запись
// arr[5] — UB (выход за границы!)

Границы НЕ проверяются ни компилятором, ни runtime. Выход за границы — UB (краш, повреждение данных, уязвимость).

Массивы и указатели

В большинстве контекстов arr преобразуется в int * (указатель на первый элемент). Исключения:

int arr[5] = {1,2,3,4,5};
int *p = arr;        // p указывает на arr[0]
p[2] == arr[2];      // true, эквивалентно *(p+2)
*(arr + 2) == 3;     // арифметика указателей

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

Массив массивов. В памяти — единый непрерывный блок (row-major order).

int matrix[3][4]; // 3 строки, 4 столбца = 12 int
matrix[1][2] = 42; // строка 1, столбец 2

// Инициализация
int m[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};

// Доступ через указатели
int (*row)[4] = matrix;     // указатель на массив из 4 int (строку)
int *flat = &matrix[0][0];  // указатель на первый элемент (плоский вид)
flat[5] == matrix[1][1];    // true (индекс 1*4+1=5)

VLA (Variable Length Arrays) — C99, опционально в C11+

void func(int n) {
    int vla[n]; // размер определяется во время выполнения
    // работает как обычный массив, но на стеке!
    // ОСТОРОЖНО: большие n → stack overflow
}

Не рекомендуется для больших/непредсказуемых размеров. Используйте malloc.

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

Массив передаётся как указатель на первый элемент. Размер не передаётся автоматически.

Варианты сигнатуры (эквивалентны):

void func(int arr[]);        // как документация: ожидается массив
void func(int *arr);         // реальность: указатель
void func(int arr[10]);      // размер игнорируется компилятором
void func(int arr[static 10]); // C99: обещание, что arr указывает минимум на 10 элементов (оптимизация)

Передача размера

void print_array(int *arr, size_t n) {
    for (size_t i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");
}

int main() {
    int a[] = {1,2,3,4,5};
    print_array(a, sizeof(a)/sizeof(a[0])); // вычисляем размер ВНЕ функции
}

Передача 2D массива

Нужно знать все размерности кроме первой:

void print_matrix(int rows, int cols, int mat[][cols]) { // VLA параметр (C99)
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) printf("%d ", mat[i][j]);
        printf("\n");
    }
}

// Или через указатель на массив:
void print_matrix2(int rows, int cols, int (*mat)[cols]) { ... }

// Для фиксированного размера:
void print_fixed(int mat[][4]) { ... } // только 4 столбца!

Возврат массива из функции

Нельзя вернуть локальный массив (указатель на стек — висячий). Варианты:

  1. Статический массив (не потокобезопасно): static int arr[10]; return arr;
  2. Динамическое выделение: int *arr = malloc(n * sizeof(int)); return arr; (вызывающий должен free).
  3. Структура-обёртка: struct Vec { int *data; size_t len; };
  4. Вызывающий передаёт буфер: void fill(int *out, size_t n).

Строки как массивы char

char str[] = "Hello";  // изменяемый массив на стеке, размер 6
char *ptr = "Hello";   // указатель на строковый литерал (read-only память!)
// str[0] = 'h'; // OK
// ptr[0] = 'h'; // UB! (сегфолт на современных ОС)

Частые ошибки

Пример: работа с массивом

#include <stdio.h>
#include <stdlib.h>

void read_array(int *arr, size_t n) {
    for (size_t i = 0; i < n; i++) {
        if (scanf("%d", &arr[i]) != 1) arr[i] = 0;
    }
}

double average(const int *arr, size_t n) {
    long long sum = 0;
    for (size_t i = 0; i < n; i++) sum += arr[i];
    return (double)sum / n;
}

int main() {
    size_t n = 5;
    int *data = malloc(n * sizeof(int));
    if (!data) return 1;
    
    printf("Введите %zu чисел: ", n);
    read_array(data, n);
    printf("Среднее: %.2f\n", average(data, n));
    
    free(data);
    return 0;
}

Язык C

  1. Массивы в C#: объявление, инициализация и операции
  2. Зубчатые массивы в C#: объявление, инициализация и доступ
  3. Как передавать массивы в функции в C++: практическое руководство
  4. Как передавать одномерные и двумерные массивы в функции в C — практическое руководство
  5. Понимание взаимосвязи между массивами и указателями в C
  6. Техники копирования массивов в Java: подробное руководство
  7. Массивы в C++: объявление, инициализация и работа с указателями
  8. Динамическое выделение массивов в C++: практическое руководство с примерами кода
  9. Учебник по массивам в Java: объявление, создание и инициализация с примерами кода
  10. MATLAB: Мастерство работы с многомерными и специальными массивами