4 façons différentes d’utiliser des tableaux 2 D avec des pointeurs, lequel est correct? Une explication aiderait beaucoup

Les quatre programmes ci-dessous saisissent une masortingce 2 D puis l’impriment.

  • Le premier imprime des valeurs de déchets et donne également quelques avertissements (que je n’ai pas compris).
  • Le second fonctionne correctement, cela a également un sens, car j’imaginais qu’un tableau 2D était stocké linéairement dans la mémoire.
  • Le troisième fonctionne correctement, mais je ne sais pas pourquoi cela fonctionne.
  • Le 4ème fonctionne aussi bien.

  • Il serait donc très utile que quelqu’un puisse expliquer comment chacune des méthodes fonctionne, bravo

Je crains que ma compréhension du fonctionnement des pointeurs ne soit aussi bonne que je le pensais.

int main(){ int n; int a [3][4]; int i=0,j=0,count=0; for(i=0;i<3;i++){ for(j=0;j<4;j++){ scanf("%d",(a+4*i+j)); // Output-514623632 514623648 514623664 514623680 514623696 514623712 514623728 514623744 514623760 514623776 514623792 514623808 } } for(i=0;i<3;i++){ for(j=0;j<4;j++){ printf("%d\t",*(a+4*i+j)); } } return 0; } Warnings -solution.c:15:21: warning: format '%d' expects argument of type 'int *', but argument 2 has type 'int (*)[4]' [-Wformat=] scanf("%d",(a+4*i+j)); solution.c:20:22: warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *' [-Wformat=] printf("%d\t",*(a+4*i+j)); ~^ ~~~~~~~~~ %ls 

 int main(){ int n; int a [3][4]; int i=0,j=0,count=0; for(i=0;i<3;i++){ for(j=0;j<4;j++){ scanf("%d",*(a+4*i+j)); } } for(i=0;i<3;i++){ for(j=0;j<4;j++){ printf("%d\t",**(a+4*i+j)); // Output -1 2 3 4 5 6 7 8 9 10 11 12 } } return 0; } 

 int main(){ int n; int a [3][4]; int i=0,j=0,count=0; for(i=0;i<3;i++){ for(j=0;j<4;j++){ scanf("%d",(*(a+i)+j)); } } for(i=0;i<3;i++){ for(j=0;j<4;j++){ printf("%d\t",*(*(a+i)+j)); // Output- 1 2 3 4 5 6 7 8 9 10 11 12 } } return 0; } 

 int main(){ int n; int * a=(int*)malloc(12*sizeof(int)) ; int i=0,j=0,count=0; for(i=0;i<3;i++){ for(j=0;j<4;j++){ *(a+4*i+j)=++count; } } for(i=0;i<3;i++){ for(j=0;j<4;j++){ printf("%d\n",*(a+4*i+j)); // Output- 1 2 3 4 5 6 7 8 9 10 11 12 } } return 0; } 

Cela semble se résumer à une idée fausse commune qui dit “un tableau est un pointeur” – ce n’est pas vrai.

Ce qui est vrai, c’est qu’un identificateur de tableau correspond à un pointeur sur le premier élément de tableau dans la plupart des contextes (ceci exclut par exemple les opérateurs & et sizeof ).

Regardez maintenant votre tableau:

 int a[3][4]; 

Ici, a est un tableau de 3 éléments et le type d’élément est int ()[4] . Cela explique directement pourquoi votre premier exemple ne fonctionne pas comme prévu. Dans votre expression, a à un pointeur sur le premier élément. Le type est donc int (*)[4] et pas simplement int * comme vous semblez l’attendre. Par conséquent, a+1 appendait 4 fois la taille d’un int à la valeur du pointeur. Avec cette explication, vous devez également comprendre les avertissements que vous recevez.

Notez également que pour la même raison, le deuxième exemple est incorrect. L’opérateur de déréférencement ajouté corrige les types utilisés, mais vous continuez d’accéder à des emplacements non valides, car votre arithmétique de pointeur fonctionne toujours sur int (*)[4] . Bien sûr, il n’ya aucune garantie d’échec, c’est juste un comportement indéfini.

La seule version correcte utilisant un tableau 2d est le troisième exemple:

(a+i) est un pointeur sur le ième élément d’ a . Le déréférencement de ce dernier donne un tableau de type int ()[4] , qui est à nouveau considéré comme un pointeur sur son premier élément. emplacement de votre valeur désirée.

Le quasortingème exemple n’est pas un tableau 2d, c’est une allocation dynamic utilisée comme un tableau plat, donc ce n’est pas très intéressant ici. Si vous voulez allouer dynamicment un tableau 2d, vous devez écrire par exemple:

 int (*a)[4] = malloc(3 * sizeof *a); 

Revoir maintenant mon premier paragraphe: avec int a[3][4] , vous avez (void *)a == (void *)*a car le premier élément de a commence au même endroit que le premier élément de a[0] , seuls les types de a et *a diffèrent. Cela ne serait pas possible si les tableaux et les pointeurs étaient identiques.

(a+4*i+j) : le compilateur se plaint du type car a n’est pas du type int * . Vous l’avez déclaré en tant int a[3][4] qui est généralement lu comme un tableau 2D d’ints de dimension 3×4. En réalité, a est un tableau de 3 tableaux de 4 ints. Alors a est l’adresse du premier tableau de 4 ints. Rappelez-vous que la définition du type v[N] définit v tant qu’adresse du premier élément du tableau et qu’il est possible de décomposer en pointeur en type d’élément. Ensuite, dans votre cas, a décomposition en un pointeur sur un tableau de 4 ints. C’est pourquoi le compilateur se plaint car %d besoin d’un argument correspondant de type int * .

Même si l’adresse pourrait être correcte, l’arithmétique n’est pas ce que vous pensez. a+3*i+j signifie l’adresse du tableau 3 * i + j de 4 ints à partir de l’adresse a .

Vous pouvez forcer à se désintégrer à int * :

 int *ta = (int *)a; // ta contains the same address but of different type... int i=0,j=0,count=0; for(i=0;i<3;i++){ for(j=0;j<4;j++){ scanf("%d",(ta+4*i+j)); // arithmetic is the right one (ints by ints) } } for(i=0;i<3;i++){ for(j=0;j<4;j++){ printf("%d\t",*(ta+4*i+j)); } } 

C'est la même chose pour le deuxième exemple, l'arithmétique est la mauvaise.

Les troisième et quasortingème sont corrects. Le troisième parce que vous sautez (avec i) dans le bon tableau, puis dans celui-ci dans le bon int.

Le quasortingème est presque le même que le code que j'ai donné.

---MODIFIER---

Comme Felix l'a dit dans des commentaires, veillez à ce que même si cela fonctionne dans de nombreux architectures / systèmes d'exploitation / compilateurs courants, une règle de pseudonyme ssortingcte vous empêche de le faire. Lire le lien qu'il a fourni pour plus.