web-dev-qa-db-fra.com

Initialisation d'un tableau 2D entier avec une valeur

Avec la déclaration suivante

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

Je reçois le tableau avec tous les zéros mais avec le suivant

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

Je ne reçois pas le tableau avec une seule valeur. La valeur par défaut est toujours 0.

Pourquoi ce comportement et comment puis-je initialiser avec tous les 1?

EDIT: Je viens de comprendre que l’utilisation de memset avec la valeur 1 définit chaque octet sur 1 et que, par conséquent, la valeur réelle de chaque cellule du tableau ne sera pas 1 mais 16843009. Comment le régler à 1?

64
Kraken

Vous obtenez ce comportement, parce que int array [ROW][COLUMN] = {1}; ne () pas signifie "définir tous les éléments à un". Laissez-moi essayer d’expliquer comment cela fonctionne étape par étape.

La façon explicite et trop claire d’initialiser votre tableau serait la suivante:

#define ROW 2
#define COLUMN 2

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

Cependant, C vous permet de laisser de côté certains des éléments d’un tableau (ou de struct/union). Vous pouvez par exemple écrire:

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

Cela signifie, initialisez les premiers éléments sur 1 et 2 et les autres éléments "comme s'ils avaient une durée de stockage statique". Une règle en C dit que tous les objets de durée de stockage statique, qui ne sont pas explicitement initialisés par le programmeur, doivent être mis à zéro.

Ainsi, dans l'exemple ci-dessus, la première ligne est définie sur 1,2 et la suivante sur 0,0 car nous ne leur avons pas donné de valeurs explicites.

Ensuite, il existe une règle en C autorisant le style lax accolade. Le premier exemple pourrait aussi bien être écrit

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

bien que ce soit un style médiocre, il est plus difficile à lire et à comprendre. Mais cette règle est pratique, car elle nous permet d’écrire

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

ce qui signifie: "initialisez la première colonne de la première ligne à 0 et tous les autres éléments comme s'ils avaient une durée de stockage statique, c'est-à-dire qu'ils sont mis à zéro."

donc, si vous essayez

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

cela signifie "initialiser la toute première colonne de la première ligne à 1 et mettre tous les autres éléments à zéro".

90
Lundin

Si vous souhaitez initialiser le tableau sur -1, vous pouvez utiliser ce qui suit,

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

Mais cela fonctionnera 0 et -1 uniquement

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

Cela initialise uniquement l'élément premier à 1. Tout le reste obtient un 0.

Dans le premier cas, vous procédez de la même manière: initialiser le premier élément à 0 et le reste par défaut à 0.

La raison est simple: pour un tableau, le compilateur initialise chaque valeur que vous ne spécifiez pas avec 0.

Avec un tableau char, vous pouvez utiliser memset pour définir chaque octet, mais cela ne fonctionnera généralement pas avec un tableau int (bien que ce soit bien pour 0).

Une boucle générale for fera ceci rapidement:

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

Ou éventuellement plus rapide (selon le compilateur)

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

Notez que GCC a une extension à la notation initializer désigné , ce qui est très utile pour le contexte. Il est également autorisé par clang sans commentaire (en partie parce qu'il essaie d'être compatible avec GCC).

La notation d'extension vous permet d'utiliser ... pour désigner une plage d'éléments à initialiser avec la valeur suivante. Par exemple:

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

Le résultat est, sans surprise:

 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

Notez que Fortran 66 (Fortran IV) avait des comptages répétés pour les initialiseurs de tableaux; Cela m'a toujours paru étrange que C ne les ait pas obtenues lorsque des initialiseurs désignés ont été ajoutés à la langue. Et Pascal utilise la notation 0..9 pour désigner la plage de 0 à 9 inclus, mais C n'utilise pas .. comme jeton. Il n'est donc pas surprenant que cela n'ait pas été utilisé.

Notez que les espaces autour de la notation ... sont essentiellement obligatoires; s'ils sont associés à des nombres, ils sont interprétés comme un nombre à virgule flottante. Par exemple, 0...9 serait symbolisé par 0., ., .9 et les nombres à virgule flottante ne sont pas autorisés en tant qu'indices de tableau. Avec les constantes nommées, ...ROW-1 ne poserait pas de problème, mais il est préférable d'entrer dans les habitudes sécuritaires.


Addenda:

Je note en passant que GCC 7.3.0 rejette:

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

où il existe un ensemble supplémentaire d'accolades autour de l'initialiseur scalaire 1 (error: braces around scalar initializer [-Werror]). Je ne suis pas sûr que ce soit exact, étant donné que vous pouvez normalement spécifier des accolades autour d'un scalaire dans int a = { 1 };, ce qui est explicitement autorisé par le standard. Je ne suis pas sûr que ce soit faux non plus.

Je me demande également si une meilleure notation serait [0]...[9] - qui est sans ambiguïté, ne peut être confondue avec aucune autre syntaxe valide et évite la confusion avec des nombres à virgule flottante.

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

Peut-être que le comité des normes envisagerait cela?

5
Jonathan Leffler

Utilisez vector array à la place:

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