Подтвердить что ты не робот

Инициализация всего массива 2D с одним значением

Со следующим объявлением

int array[ROW][COLUMN]={0};

Я получаю массив со всеми нулями, но со следующим

int array[ROW][COLUMN]={1};

Я не получаю массив со всем одним значением. Значение по умолчанию равно 0.

Почему это поведение и как я могу инициализировать все 1?

EDIT: я только понял, что использование memset со значением как 1, задает каждый байт как 1 и, следовательно, фактическое значение каждой ячейки массива не будет 1, а 16843009. Как установить его на 1?

4b9b3361

Ответ 1

Вы получаете это поведение, потому что int array [ROW][COLUMN] = {1}; означает не означает "установить все элементы в один". Позвольте мне попытаться объяснить, как это работает шаг за шагом.

Явный, явный способ инициализации вашего массива будет выглядеть следующим образом:

#define ROW 2
#define COLUMN 2

int array [ROW][COLUMN] =
{
  {0, 0},
  {0, 0}
};

Однако C позволяет вам исключить некоторые элементы в массиве (или struct/union). Например, вы можете написать:

int array [ROW][COLUMN] =
{
  {1, 2}
};

Это означает, что инициализируйте первые элементы 1 и 2, а остальные элементы "как если бы они имели статическую продолжительность хранения". В C есть правило, говорящее, что все объекты статической продолжительности хранения, которые явно не инициализированы программистом, должны быть установлены на ноль.

Итак, в приведенном выше примере первая строка получает значение 1,2, а следующая - 0,0, так как мы не даем им никаких явных значений.

Далее, в C существует правило, позволяющее использовать стиль lax brace. Первый пример также можно записать как

int array [ROW][COLUMN] = {0, 0, 0, 0};

хотя, конечно, это плохой стиль, его труднее читать и понимать. Но это правило удобно, поскольку оно позволяет нам писать

int array [ROW][COLUMN] = {0};

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

поэтому, если вы попытаетесь выполнить

int array [ROW][COLUMN] = {1};

это означает "инициализировать первый столбец в первой строке до 1 и установить все остальные элементы в ноль".

Ответ 2

Если вы хотите инициализировать массив до -1, вы можете использовать следующее,

memset(array, -1, sizeof(array[0][0]) * row * count)

Но это будет работать только 0 и -1

Ответ 3

int array[ROW][COLUMN]={1};

Это инициализирует только первый элемент в 1. Все остальное получает 0.

В первом случае вы делаете то же самое - инициализируете первый элемент до 0, а остальные по умолчанию - 0.

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

С массивом char вы можете использовать memset для установки каждого байта, но это обычно не работает с массивом int (хотя это нормально для 0).

Общий цикл for сделает это быстро:

for (int i = 0; i < ROW; i++)
  for (int j = 0; j < COLUMN; j++)
    array[i][j] = 1;

Или, возможно, быстрее (в зависимости от компилятора)

for (int i = 0; i < ROW*COLUMN; i++)
  *((int*)a + i) = 1;

Ответ 4

Обратите внимание, что GCC имеет расширение для обозначения обозначенного инициализатора, что очень полезно для контекста. Это также разрешено clang без комментариев (частично потому, что оно пытается быть совместимым с GCC).

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

#include <stdio.h>

enum { ROW = 5, COLUMN = 10 };

int array[ROW][COLUMN] = { [0 ... ROW-1] = { [0 ... COLUMN-1] = 1 } };

int main(void)
{
    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < COLUMN; j++)
            printf("%2d", array[i][j]);
        putchar('\n');
    }
    return 0;
}

Неудивительно, что результат:

 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1

Обратите внимание, что Fortran 66 (Fortran IV) имел количество повторов для инициализаторов для массивов; мне всегда казалось странным, что C не получил их, когда в язык были добавлены назначенные инициализаторы. А Паскаль использует нотацию 0..9 для обозначения диапазона от 0 до 9 включительно, но C не использует .. в качестве токена, поэтому неудивительно, что он не использовался.

Обратите внимание, что пробелы вокруг обозначения ... являются по существу обязательными; если они привязаны к числам, то число интерпретируется как число с плавающей запятой. Например, 0...9 будет маркироваться как 0., ., .9, а числа с плавающей запятой не допускаются в качестве индексов массива. С указанными константами ...ROW-1 не вызовет проблем, но лучше перейти к безопасным привычкам.


Дополнения:

Попутно отмечу, что GCC 7.3.0 отклоняет:

int array[ROW][COLUMN] = { [0 ... ROW-1] = { [0 ... COLUMN-1] = { 1 } } };

где есть дополнительный набор скобок вокруг скалярного инициализатора 1 (error: braces around scalar initializer [-Werror]). Я не уверен, что правильно, учитывая, что вы можете обычно указывать скобки вокруг скаляра в int a = { 1 };, что явно разрешено стандартом. Я тоже не уверен, что это неверно.

Мне также интересно, будет ли лучшая нотация [0]...[9] - она однозначна, ее нельзя спутать с любым другим допустимым синтаксисом и избежать путаницы с числами с плавающей запятой.

int array[ROW][COLUMN] = { [0]...[4] = { [0]...[9] = 1 } };

Может, комитет по стандартам рассмотрит это?

Ответ 5

Вместо этого используйте векторный массив:

vector<vector<int>> array(ROW, vector<int>(COLUMN, 1));

Ответ 6

Для инициализации 2d массива с нуля используйте метод ниже: int arr[n][m] = {};

ПРИМЕЧАНИЕ: вышеупомянутый метод будет работать только для инициализации с 0;