Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

tableaux 2D en C : un truc m'échappe

Aucune réponse
Avatar
pehache
Je ne suis pas un pro du C, je n'ai jamais fait que bricoler dans ce
langage. Et là il y un truc que je ne comprends pas du tout avec les
tableaux 2D :

int x[10][10];
int i, j;

for (i=0;i<10;i++) { for (j=0;j<10;j++) { x[j] = 10*i+j; } }

printf(" x = %p\n", x );
printf(" *x = %p\n", *x );
printf("**x = %d\n", **x );

donne comme sortie :

x = 0x7fffffffdc70
*x = 0x7fffffffdc70
**x = 0

on a *x = x, donc on devrait avoir **x = *(*x) = *x = x, non ? Mais en fait
non.

Quelqu'un peut m'expliquer ?

10 réponses

1 2
Avatar
Pascal J. Bourguignon
pehache writes:
Je ne suis pas un pro du C, je n'ai jamais fait que bricoler dans ce
langage. Et là il y un truc que je ne comprends pas du tout avec les
tableaux 2D :
int x[10][10];
int i, j;
for (i=0;i<10;i++) { for (j=0;j<10;j++) { x[j] = 10*i+j; } }
printf(" x = %pn", x );
printf(" *x = %pn", *x );
printf("**x = %dn", **x );
donne comme sortie :
x = 0x7fffffffdc70
*x = 0x7fffffffdc70
**x = 0
on a *x = x, donc on devrait avoir **x = *(*x) = *x = x, non ? Mais en fait
non.
Quelqu'un peut m'expliquer ?

D'abord, il y a un problème avec ton code: il ne compile pas!
#include <stdio.h>
int main(){
int x[10][10];
int i, j;
for (i=0;i<10;i++) {
for (j=0;j<10;j++) {
x[j] = 10*i+j;
} }
printf(" x = %pn", x );
printf(" *x = %pn", *x );
printf("**x = %dn", **x );
}
SRC="/tmp/a.c" ; EXE="a" ; gcc -I. -L. -g3 -ggdb3 -o ${EXE} ${SRC} && ./${EXE} && echo status = $?
/tmp/a.c:6:50: error: array type 'int [10]' is not assignable
for (i=0;i<10;i++) { for (j=0;j<10;j++) { x[j] = 10*i+j; } }
~~~~ ^
1 error generated.
(Je suis sur macOS, alors gcc, c'est en fait clang).
int x[10];
alloue un tableau de 10 int:
x:
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
int x[10][10];
alloue un tableau de 100 int organisé comme 10 tableaux de 10 int consécutifs:
x:
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+
mais avec int x[10][10];
x[i] est un int[10], un tableau de 10 int!
Tu ne peux donc pas lui assigner un int.
Il faut utiliser un double indexage: x[i][j] = 10*i+j;
-*- mode: compilation; default-directory: "/tmp/" -*-
Compilation started at Fri Dec 15 16:55:00
SRC="/tmp/a.c" ; EXE="a" ; gcc -I. -L. -g3 -ggdb3 -o ${EXE} ${SRC} && cat "$SRC" && ./${EXE} && echo status = $?
#include <stdio.h>
int main(){
int x[10][10];
int i, j;
printf(" sizeof(x) = %lun",sizeof(x));
for (i=0;i<10;i++) {
for (j=0;j<10;j++) {
x[i][j] = 10*i+j;
} }
printf(" x = %pn", x );
printf(" *x = %pn", *x );
printf("**x = %dn", **x );
return 0;
}
sizeof(x) = 400
x = 0x7ffeea53b800
*x = 0x7ffeea53b800
**x = 0
status = 0
Compilation finished at Fri Dec 15 16:55:00
x est un int[10][10]. C'est aussi un pointeur vers le premier tableau
alloué int[10] donc *x retourne la même addresse que x, mais x "pointe"
sur 100 int, tandis que *x "pointe" sur 10 int. Un pointeur vers un tableau
est un pointeur sur le premier élement du tableau. Donc **x pointe sur
x[0][0], qui vaut 10*0+0 = 0. Donc **x retourne 0.
Dans les équations, x n'est pas une adresse, c'est un tableau, mais si
on l'utilise comme un adresse on obtient l'adresse du tableau. C'est un
cas particulier dans la sémantique de C, qui permet de confondre dans
la syntaxe un pointeur et un tableau:
int a[10];
int *p=a;
assert(p[1]==a[1]);
Mais il y a une différence qu'il faut garder à l'esprit:
a est un tableau, donc il y a 10 slots alloués pour a;
sizeof(a) = 10*sizeof(int) = 40
p est un pointeur, il n'y a rien d'alloué pour lui, à part le pointeur;
sizeof(p) = 8 (en 64-bit, ou 4 en 32-bit).
Dans le cas des tableaux multidimensionnels, chaque niveau de "pointeur"
réfère un sous-tableau avec un indice de moins.
-*- mode: compilation; default-directory: "/tmp/" -*-
Compilation started at Fri Dec 15 17:03:21
SRC="/tmp/a.c" ; EXE="a" ; gcc -I. -L. -g3 -ggdb3 -o ${EXE} ${SRC} && cat "$SRC" && ./${EXE} && echo status = $?
#include <stdio.h>
int main(){
int x[10][10];
int i, j;
for (i=0;i<10;i++) {
for (j=0;j<10;j++) {
x[i][j] = 10*i+j;
} }
printf(" x = %p sizeof(x )=%lun", x ,sizeof(x));
printf(" *x = %p sizeof(*x )=%lun", *x ,sizeof(*x));
printf("**x = %d sizeof(**x)=%lun", **x ,sizeof(**x));
return 0;
}
x = 0x7ffeee39a800 sizeof(x )@0
*x = 0x7ffeee39a800 sizeof(*x )@
**x = 0 sizeof(**x)=4
status = 0
Compilation finished at Fri Dec 15 17:03:21
--
__Pascal J. Bourguignon
http://www.informatimago.com
Avatar
Marc SCHAEFER
pehache wrote:
x = 0x7fffffffdc70

L'adresse du début de la structure qui contient le tableau.
*x = 0x7fffffffdc70

L'adresse du début de la première "colonne", disons.
**x = 0

La valeur contenue dans la première ligne et la première colonne,
soit zéro ici.
on a *x = x, donc on devrait avoir **x = *(*x) = *x = x, non ? Mais en fait

Non, on a la valeur de l'adresse x = l'adresse *x. Mais il n'y a pas
égalité stricte. Donc ton développement mathématique ensuite n'a pas
de sens.
Regarde le code ci-dessous (il reste quelques warnings de format):
# /*
gcc -g -Wall $0 -o $(basename $0 .c) && ./$(basename $0 .c)
exit $?
*/
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
int i;
int j;
int x[10][10];
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
x[i][j] = i + j + 1;
printf("x[%d,%d] = %d; %x %xn", i, j, x[i][j], x[i], &x[i][j]);
}
}
return 0;
}
Observons:
x[0,0] = 1; 54c29a90 54c29a90
x[0,1] = 2; 54c29a90 54c29a94
x[0,2] = 3; 54c29a90 54c29a98
x[0,3] = 4; 54c29a90 54c29a9c
x[0,4] = 5; 54c29a90 54c29aa0
x[0,5] = 6; 54c29a90 54c29aa4
x[0,6] = 7; 54c29a90 54c29aa8
x[0,7] = 8; 54c29a90 54c29aac
x[0,8] = 9; 54c29a90 54c29ab0
x[0,9] = 10; 54c29a90 54c29ab4
x[1,0] = 2; 54c29ab8 54c29ab8
x[1,1] = 3; 54c29ab8 54c29abc
x[1,2] = 4; 54c29ab8 54c29ac0
x[1,3] = 5; 54c29ab8 54c29ac4
x[1,4] = 6; 54c29ab8 54c29ac8
x[1,5] = 7; 54c29ab8 54c29acc
x[1,6] = 8; 54c29ab8 54c29ad0
x[1,7] = 9; 54c29ab8 54c29ad4
x[1,8] = 10; 54c29ab8 54c29ad8
x[1,9] = 11; 54c29ab8 54c29adc
x[2,0] = 3; 54c29ae0 54c29ae0
[ ... ]
C'est plus clair ?
Avatar
espie
In article ,
pehache wrote:
Je ne suis pas un pro du C, je n'ai jamais fait que bricoler dans ce
langage. Et là il y un truc que je ne comprends pas du tout avec les
tableaux 2D :
int x[10][10];
int i, j;
for (i=0;i<10;i++) { for (j=0;j<10;j++) { x[j] = 10*i+j; } }
printf(" x = %pn", x );
printf(" *x = %pn", *x );
printf("**x = %dn", **x );

Tu connais l'acronyme GIGO (Garbage In, Garbage Out) ?
Tu fais de la merde le compilo te le rend, facon boomerang.
Je ne sais pas ce que tu utilises comme compilo, mais commence par
ACTIVER LES PUTAINS DE WARNINGS et les corriger.
Rien a foutre de ce que le programme t'ecrit, ton code c'est de la
merde, ca ne devrait pas compiler.
1/ change de compilo
2/ lis la doc et active les avertissements et corrige-les
3/ poste le code que tu testes et pas un fragment.
Apres, on pourra discuter, sinon ca sert a rien.
Avatar
Samuel DEVULDER
Le 15/12/2017 à 16:05, pehache a écrit :
on a *x = x,

En valeur oui, mais pas du tout au niveau du typage! Le C étant un
langage typé, tu peux avoir la même valeur numérique (ici la même
adresse) mais pas le même type. L'opérateur "*" change de sémantique en
fonction du type pointé.
donc on devrait avoir **x = *(*x)

Oui du fait de la précédence de l'opérateur "*".
= *x = x, non ? Mais en fait

Non! C'est pas parce que *x a la même valeur "numérique" que x que *(*x)
= *(x). Je le redis: le fonctionnement de "*" change en fonction du truc
qui suit, or x et *x ne sont pas du même type. Appliquer "*" dessus ne
fait pas du tout la même chose.
Bref, ton analyse ne marche pas parce que
Le C a des pointeurs typé <<


sam.
Avatar
Lucas Levrel
Le 15 décembre 2017, à 17:06, Pascal J. Bourguignon a écrit :
mais avec int x[10][10];
x[i] est un int[10], un tableau de 10 int!
Tu ne peux donc pas lui assigner un int.

On peut lui assigner quelque chose ? Il me semblait que dans
int y[42];
y était "const", et du coup j'aurais dit la même chose de x[10] (qui est
d'un type semblable à ce y, modulo le nombre d'éléments).
--
LL
Ἕν οἶδα ὅτι οὐδὲν οἶδα (Σωκράτης)
Avatar
JKB
Le Tue, 19 Dec 2017 09:11:48 +0100,
Lucas Levrel écrivait :
Le 15 décembre 2017, à 17:06, Pascal J. Bourguignon a écrit :
mais avec int x[10][10];
x[i] est un int[10], un tableau de 10 int!
Tu ne peux donc pas lui assigner un int.

On peut lui assigner quelque chose ? Il me semblait que dans
int y[42];

Ça dépend des compilos ;-) J'ai déjà vu un compilo que je ne
citerai pas, sur sparc, se débrouiller pour que x[][] ne soit pas
alloué de manière contiguë... Je ne fais donc plus d'hypothèses de
ce genre.
JKB
--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
=> http://loubardes.de-charybde-en-scylla.fr
Avatar
Pascal J. Bourguignon
Lucas Levrel writes:
Le 15 décembre 2017, à 17:06, Pascal J. Bourguignon a écri t :
mais avec int x[10][10];
x[i] est un int[10], un tableau de 10 int!
Tu ne peux donc pas lui assigner un int.

On peut lui assigner quelque chose ? Il me semblait que dans
int y[42];
y était "const", et du coup j'aurais dit la même chose de x[10] (qui
est d'un type semblable à ce y, modulo le nombre d'élément s).

y n'est pas const, il est "inassignable", mais une extension triviale du
langage aurait dû permettre depuis longtemps de faire:
int x[42]={1,2,3};
int y[42];
y=x;
assert(y[0]==1 && y[1]==2 && y[2]==3 && y[3]==0 && y[4] ==0 /*etc*/);
Même C++ ne permet pas de le faire ! Pour ce genre de choses, il faut un
vrai langage de programmation, comme Pascal, pas des jouets comme C ou C++ …
Et ceci est d'autant plus irritant, que si le tableau est inclus dans
une structure, alors il est possible d'assigner la structure englobante
(quel langage de débiles) :
#include <stdio.h>
#include <assert.h>
struct { int x[3]; } typedef s;
int main(){
s x={{2,3,4}};
s y;
y=x;
assert(y.x[0]==x.x[0] && y.x[1]==x.x[1] && y.x[2]==x.x[ 2]);
return 0;
}
Mais la question c'est int x[10][10]; avec:
struct { int x[10]; } typedef d;
struct { int x; } typedef s;
int main(){
d b;
s a={42};
b=a; /* error: assigning to 'd' from incompatible type 's' */
return 0;
}
Noter que l'erreur c'est un assignement entre type incompatible, pas le
fait que la destination est "inassignable".
--
__Pascal J. Bourguignon
http://www.informatimago.com
Avatar
segoviaalvaro61
¿Estás buscando un préstamo de emergencia real? ¿Necesi ta un préstamo de cualquier tipo y por cualquier motivo? Estamos aqu í para ayudarlo y ofrecerle préstamos confiables con solo un 2% p ara todos, un interés económico; nuestros préstamos se aprue ban rápidamente en solo 72 horas de la solicitud. Los prestatarios
interesados deben contactarnos:
Avatar
Jose PUJOL
Offre de prêt d'argent entre particulier en 48 heures
e-mail : )
Vous êtes à la recherche d'un prêt d'urgence de l'argent ? s oit :
Pour booster leurs activités financières ?
Pour rénover l'intérieur de votre appartement, maison, immeuble ?
Loyer ?
L'achat de la voiture ?
De crédit pour le mariage ?
Le règlement d'une dette ?
Pour la réalisation d'un projet ?
Ou pour d'autres raisons, etc ...
J'accorde des prêts à toutes personnes honnêtes, et il est p robable que je
remboursement de mon argent avec de très simple
une commission de 3%.Pour plus d'informations, veuillez contacter
contactez-moi directement à mon adresse e-mail :
Avatar
Samuel DEVULDER
C'est quoi tous ces spammeurs en série qui, pour la plupart, ne parlent
pas francais??
Le 20/01/2018 à 19:00, Jose PUJOL a écrit :
Offre de prêt d'argent entre particulier en 48 heures

Le 21/12/2017 à 11:14, a écrit :
¿Estás buscando un préstamo de emergencia real? ¿Necesita un préstamo de cualquier tipo y por cualquier motivo? Estamos aquí para ayudarlo y ofrecerle préstamos confiables con solo un 2% para todos, un interés económico; nuestros préstamos se aprueban rápidamente en solo 72 horas de la solicitud. Los prestatarios
interesados deben contactarnos:

Le 15/01/2018 à 01:54, a écrit :
E-mail:
Hola Señor/Señora,
Usted necesita un préstamo para hacer frente a dificultades financieras y también para romper finalmente el punto muerto que causan los bancos, por el rechazo de sus expedientes de solicitud de crédito?
También le pegan y no tienes el favor de los bancos o mejor usted tiene un proyecto y necesita financiación. Soy una persona capaz de hacerle un préstamo en la cantidad que necesita con condiciones muy simple. Así que no dude en ponerse en contacto conmigo para aprender más ya que ofrece 2.000 € a 2.000.000 euros con 3% de interés sobre la duración del préstamo varía de 1 a 20 años. Contacto-me por esta dirección de correo electrónico:

(etc)
1 2