Inicialización de la matriz 2D completa con un valor

81

Con la siguiente declaración

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

Obtengo la matriz con todos los ceros pero con el siguiente

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

No obtengo la matriz con un solo valor. El valor predeterminado sigue siendo 0.

¿Por qué este comportamiento y cómo puedo inicializar con todos 1?

EDITAR: Acabo de entender que usar memsetcon valor como 1, establecerá cada byte como 1 y, por lo tanto, el valor real de cada celda de la matriz no será 1 pero 16843009. ¿Cómo lo configuro en 1?

Kraken
fuente
1
@ckruse: La pregunta no es cómo , es por qué .
masoud
@MM. La respuesta se da en el hilo que vinculé.
ckruse
En realidad, el problema eran why and howambos. :)
Kraken
@Kraken La pregunta en su edición quizás debería publicarse como una pregunta separada de esta.
Lundin
1
@Kraken En realidad encontré esa pregunta aquí . Recomendaría hacer lo que se sugiere en mi respuesta (¡por supuesto!) Y no confiar en las extensiones de GCC.
Lundin

Respuestas:

123

Se obtiene este comportamiento, ya que int array [ROW][COLUMN] = {1};lo hace no media "set todos los artículos a uno". Permítanme intentar explicar cómo funciona esto paso a paso.

La forma explícita y demasiado clara de inicializar su matriz sería así:

#define ROW 2
#define COLUMN 2

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

Sin embargo, C le permite omitir algunos de los elementos de una matriz (o estructura / unión). Por ejemplo, podría escribir:

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

Es decir, inicializar los primeros elementos en 1 y 2, y el resto de elementos "como si tuvieran una duración de almacenamiento estático". Hay una regla en C que dice que todos los objetos de duración de almacenamiento estático, que no sean inicializados explícitamente por el programador, deben establecerse en cero.

Entonces, en el ejemplo anterior, la primera fila se establece en 1,2 y la siguiente en 0,0 ya que no les dimos ningún valor explícito.

A continuación, hay una regla en C que permite un estilo de corsé laxo. El primer ejemplo también podría escribirse como

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

aunque, por supuesto, este es un estilo deficiente, es más difícil de leer y comprender. Pero esta regla es conveniente, porque nos permite escribir

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

lo que significa: "inicializar la primera columna de la primera fila en 0, y todos los demás elementos como si tuvieran una duración de almacenamiento estática, es decir, ponerlos en cero".

por lo tanto, si intentas

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

significa "inicializar la primera columna de la primera fila en 1 y establecer todos los demás elementos en cero".

Lundin
fuente
2
Gracias por eso, ¿algo que pueda hacer para inicializar toda la matriz con 1? considerando que mis filas y columnas tienen un tamaño de cientos?
Kraken
1
@Kraken Con trucos macro. Mira esto .
Lundin
Soy solo yo o necesitas el segundo paréntesis:int array [ROW][COLUMN] = {{0}};
user1794469
@ user1794469 No, no lo haces.
Lundin
1
@ user1794469 Sí, y eso es bueno, porque en la mayoría de los casos saltarse las llaves es una mala práctica. Pero el compilador no tiene que dar un diagnóstico. Con respecto a las buenas / malas prácticas para este caso, consulte mi respuesta a esta pregunta .
Lundin
40

Si desea inicializar la matriz -1, puede usar lo siguiente,

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

Pero esto funcionará 0y -1solo

user2021512
fuente
14
Es más fácil usar "sizeof (matriz)" en lugar de "sizeof (matriz [0] [0]) * fila * recuento".
Vladyslav Savchenko
Funciona para cualquier byte constante, aunque no me queda claro qué sería útil además 0000y1111
user1794469
4
Necesito incluir <cstring>en C ++
MTK
Pero, ¿por qué esto solo funciona para 0 y -1?
user9989615
12
int array[ROW][COLUMN]={1};

Esto inicializa solo el primer elemento en 1. Todo lo demás obtiene un 0.

En la primera instancia, está haciendo lo mismo: inicializando el primer elemento en 0 y el resto por defecto en 0.

La razón es sencilla: para una matriz, el compilador inicializará cada valor que no especifique con 0.

Con una charmatriz, podría usar memsetpara configurar cada byte, pero esto generalmente no funcionará con una intmatriz (aunque está bien para 0).

Un forciclo general hará esto rápidamente:

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

O posiblemente más rápido (dependiendo del compilador)

for (int i = 0; i < ROW*COLUMN; i++)
  *((int*)a + i) = 1;
teppic
fuente
1
@Kraken - No lo hace - también 0inicializa solo el primer valor. Luego inicializa todo el resto con 0por defecto.
teppic
@EricPostpischil, entonces, establece todos los bytes con 1, por lo tanto, si considero un entero de 32 bits, entonces si mi valuecampo memsetes 1, entonces el valor real en la matriz no será 1, pero 2^0 + 2^8 + 2^16 + 2^24?
Kraken
@Kraken: Básicamente, sí. memsetestablece cada byte en su destino en el valor que se le da, lo que no funcionará para establecer un inten 1. memsetNo se puede usar para establecer valores de objetos de varios bytes a menos que desee que cada byte del objeto tenga el mismo valor.
Eric Postpischil
@EricPostpischil ¿Entonces no hay forma de hacerlo aparte de inicializar manualmente cada uno? ¿Teniendo en cuenta que mis filas y columnas se encuentran incluso en unos pocos miles?
Kraken
@Kraken He publicado una explicación de por qué {1} no funciona. Y, de hecho, no hay otra forma que la inicialización manual. Sin embargo, no tiene que escribir miles de números, hay trucos de macro, pero ese es quizás un tema para otra pregunta.
Lundin
8

Tenga en cuenta que GCC tiene una extensión para la notación de inicializador designada que es muy útil para el contexto. También está permitido clangsin comentarios (en parte porque intenta ser compatible con GCC).

La notación de extensión le permite usar ...para designar un rango de elementos que se inicializarán con el siguiente valor. Por ejemplo:

#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;
}

El resultado es, como era de esperar:

 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

Tenga en cuenta que Fortran 66 (Fortran IV) tenía recuentos de repetición para inicializadores para matrices; Siempre me ha parecido extraño que C no los obtuviera cuando se agregaron inicializadores designados al idioma. Y Pascal usa la 0..9notación para designar el rango de 0 a 9 inclusive, pero C no lo usa ..como token, por lo que no es sorprendente que no se haya usado.

Tenga en cuenta que los espacios alrededor de la ...notación son esencialmente obligatorios; si están unidos a números, entonces el número se interpreta como un número de punto flotante. Por ejemplo, 0...9sería tokenized como 0., ., .9, y números de punto flotante no están permitidos como subíndices de matriz. Con las constantes nombradas, ...ROW-1no causaría problemas, pero es mejor adquirir hábitos seguros.


Adenda:

Observo de pasada que GCC 7.3.0 rechaza:

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

donde hay un conjunto adicional de llaves alrededor del inicializador escalar 1( error: braces around scalar initializer [-Werror]). No estoy seguro de que sea correcto dado que normalmente puede especificar llaves alrededor de un escalar int a = { 1 };, lo cual está explícitamente permitido por el estándar. Tampoco estoy seguro de que sea incorrecto.

También me pregunto si sería una mejor notación [0]...[9]: no es ambigua, no se puede confundir con ninguna otra sintaxis válida y evita la confusión con números de coma flotante.

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

¿Quizás el comité de estándares consideraría eso?

Jonathan Leffler
fuente
5

Para inicializar una matriz 2d con cero, use el método siguiente: int arr[n][m] = {};

NOTA : El método anterior solo funcionará para inicializar con 0;

Gaurav Suthar
fuente
3

Utilice una matriz de vectores en su lugar:

vector<vector<int>> array(ROW, vector<int>(COLUMN, 1));
Jogendra Kumar
fuente
3
Posible, pero OP no ha mencionado C ++.
Sangeet
0
char grid[row][col];
memset(grid, ' ', sizeof(grid));

Eso es para inicializar los elementos de la matriz de caracteres en caracteres de espacio.

inhalador
fuente