Forum Clubic

[C++] Pointeur sur un tableau

Bonjour tlm,

Je suis en train d’apprendre le C++ et j’étudie a présent les pointeurs. Les pointeur c’est bon, mais je ne comprend pas comment récupérer les valeurs d’un tableau…

J’ai écris un petit bout de code tout simple, mais il ne veut pas fonctionner comme je le veux

Voici le bout de code =>

// tabPointeur.cpp : Defines the entry point for the console application.
//

#include “stdafx.h”
#include

using namespace std;

#define lag 1
#define log 1

int main()
{

int tab[lag][log];

//rempli le tableau de nombre suivant leurs largeur et leurs hauteur
int i=0, d=0, compteur = 0;
for(i = 0; i <= lag;i++)
{
	for(d = 0; d <= log;d++)
	{
		tab[i][d] = ++compteur;
		cout << tab[i][d];
	}
	cout << endl;
}

int *pTab = NULL;
pTab = &amp;tab[0][0];

for(int sa = 0; sa < 10; sa++)
{
	cout << *((pTab+sa));
	if(sa % 2 == 1)
		cout << endl;
}
int retour;
cin >> retour;

return 0;

}

dans ce bout de code je rentre une tableau du style


| 1 | 2 |
|--------
| 3 | 4 |

et lorsque je lis le tableau avec le pointeur j’arrive à :


| 1 | 3 |
|--------
| 4 | 1 |

Je ne comprend pas pouquoi le tableau qu’il me ressort me donne deux fois le “1” alors que je rentre le 1 qu’une fois…

Si quelqu’un à la solution de comment “naviguer” dans un tableau avec un pointeur… J’ai cherché sur le web, mais très peu de site web parle de ça :frowning:

Euh juste une petite chose, que je n’ai pas dite. J’arrive à la faire avec des tableau a une dimension, mais c’est a deux dimension que les résultats son pas très normaux…

ya un probleme dans tes boucles for

c’est:

for(i = 0; i < lag;i++)
{
for(d = 0; d < log;d++)

car les indices du tableau commencent à 0.

ex: pour un tableau de 2, c’est l’indice 0 et 1 pour acceder aux valeurs

Ha merci jeanguy… Je 'avais pas vu ce bug, merci beaucoup.

Et juste une dernière petite question, je veux attribuer (mais cette fois ci dynamiquement) un tableau (le même que dans le programme précédent)

Je fait donc:
int* tab = new int[lag][log];

Mais mon compilateur n’accepte pas tellement il me mets:
error C2440: ‘initializing’ : cannot convert from ‘int (*)[2]’ to 'int
Alors que j’arrive très bien à une dimension
int
tab = new int[lag];

Quelle serait le problème, d’après vous…

Déjà tu mets lag et log à 1. hors quand on fait new int[x][y] x et y représente le nombre d’élément et non la valeur du dernier indice du tableau.
pour avoir un tableau a 2 lignes 2 colonnes => lag et log à 2 et remplacer i<= lag par un < idem pour log

c’est immonde comme code :
[cpp]
int i=0, d=0, compteur = 0;
for(i = 0; i <= lag;i++)
{
for(d = 0; d <= log;d++)
{
[/ccp]
à remplacer en :
[cpp]
int compteur = 0;
for(int i = 0; i < lag;i++)
{
for(int d = 0; d < log;d++)
{
[/cpp]

[cpp]
int *pTab = NULL;
pTab = &tab[0][0];

<=>
int *pTab = &tab[0][0]; // ici tu fais appel au constructeur par recopie alors qu’avant tu construisait avec la valeur null puis l’affectation
[/cpp]

Par contre me rappel plus si &tab[0][0] == tab !?

En plus int *pTab = &tab[0][0] pas bon car &tab[0][0] est un pointeur sur un tableau a 2 dimensions donc int **pTab mais la encore ca ne peut pas marcher car int **pTab signifi que *pTab[…] = pointeur hors new int[x][y] ne marche pas comme ca.

je me rappel plus la solution qu’il faut faire …

Ha voilà c’est bon j’ai trouvé comment faire un tableau dynamique à deux dimensions, voici mon code (qui créer un tableau dynamique de pointeurs, qui poite eux même sur des integers

#include “stdafx.h”
#include

using namespace std;

#define tailleTableau 30

int main()
{

int** a = new int*[tailleTableau];

for(int i = 0; i < tailleTableau; i++)
{
	*(a+i) = new int[tailleTableau];

	for(int d = 0; d < tailleTableau; d++)
	{
		*(*(a+i)) = 20;
	}
}

char sa;
cin >> sa;

return 0;

}

Et mille fois merci à jeanguy et ffluff

des corrections. deja les define sont tous en majuscule. sur le coup j’a cru à des variables. hors un tableau se dimensionne par des constantes ou alors faut faire un malloc () ou en c++ un new.

ensuite tu mélanges les pointeurs et les doubles pointeurs.

ton tableau a des lignes et des colonnes. une ligne est composée de colonnes. donc chaque ligne est un tableau de int.

donc

[cpp]int ligne[LOG]; [/cpp]
Ensuite tu as plusieures lignes. donc ca fait

[cpp]int ligne1[LOG];
int ligne2[LOG];
int ligne3[LOG];
…[/cpp]
si tu veux un pointeur sur la ligne1 tu as un int *ptLigne1;
si tu veux un pointeur sur la ligne2 tu as un int *ptLigne2;

et les pointeurs sont intialisés

[cpp]ptLigne1 = ligne1,
ptLigne2 = ligne2;[/cpp]

si tu veux un tableau composé des pointeurs. comme cela en fonction d’une variable tu tapes sur ligne1 ou ligne2 ou …

donc tu as
int * ptLigne[LAG]; mais on peut ecrire
ptLigne[] comme *ptLigne; donc ca fait int * *ptligne;

ca c’est pour faire comprendre et on obtient int **ptLigne;

maintenant on veut que le premier indice soit ligne1;

donc

[cpp]ptLigne{0] = ligne1;
ptLigne[1] = ligne2;
ptLigne[2] = ligne3;[/cpp]

alors que ce passe t’il alors si on fait un double tableau
int ligne[LAG][LOG];

donc que vaut ligne{0] et bien c’est pareil que ligne1 dans l’exemple que j’avais avant;

ensuite autre erreur. tu colles ton tableau dans la pile. si un jour tu colle une fonction ou qu’une interruption arrive dans ta fonction. ton tableau a ses valeurs d’ecrasées. et ca tu peux mettre des nuits pour trouver d’ou ca vient.

alors reflexe. faire attention à tout ce qui est dans la pile. certains compilateurs conservent le sommet de la pile et mettent les variables de pile au dessus. et d’autres empilent les variables locales en pîle. ceux ci ne presentent pas ce risque d’ecrasement des variables locales.

les compilateurs c++ gerent ce risque, mais de mettre les adresses de retour au dessus des variables causent plus de risques de plantage. mieux vaut avoir un tableau, ou une variable ecrasés, plutot que planter le systeme. là on comprends rien du tout de ce qui se passe.

de toute facon comme on s’arrete au stop. les tableaux en local (qui sont pratiques lorsque on retourne un pointeur) doivent etre en static. encore que j’ai seulement programmé en dos. je sais pas comment windows et sa structure événementielle reagit à ca.

ensuite autre punition, le int i=0, … ca se fait pas. tu peux relire ton code dans 20 ans, et là ca va te faire drole. desagreablement drole. et l’ainé qui se marie demain midi. non faut etre clair.

[cpp]int i;
int d;
int compteur;

i = 0;
d = 0;
compteur = 0;[/cpp]

ensuite le mieux c’est que tu initialise i à la déclaration mais ensuite que tu l’utilise dans une boucle juste apres. tu perds de la place mémoire pour rien. deux fois le codage de i = 0; du code au plus qui sert à rien et un cout machine augmenté pour le client. surtout que i est dans la pile ca prends du temps et de la place.

bien sur pareil pour d ca sert à rien.

compteur c’est bien. initialisé une seule fois.

comme quoi, les petites astuces comme i_truc, j_machin, k_zik sont du meilleur effet pour savoir que l’on a pas à les initialiser. ce sont des indices. donc ils vont avoir leur sort à un moment ou un autre.

une autre erreur là le tableau est initialisé dans la fonction. pas de probleme. mais généralement tout ce qui est dans la pile doit etre initialisé à la main. donc le tableau doit etre intialisé par des 0 au debut de la fonction. comme ca on est tranquille.

memset (tab, 0, sizeof (tab)); etant donné la declaration de tab. mais attention des fois les tableau à deux dimensions sont en fait un tableau de pointeurs sur des lignes, qui contient des adresses de colonnes. si le compilo mets chaque ligne de maniere contigue tout baigne. on intialise pas les tableaux de pointeurs de lignes. mais c’est pas toujours le cas. alors mieux vaut initialiser à la main lorsque on a affaire à des compilos esoteriques. et la fonction sizeof a des aléas assez inquietants, comme souvent ca dépends du compilo.

ensuite les defines ce sont des MAJ mais aussi on donne des noms fonctionnels comme NBCHAMPS pour log et NBENR pour les lignes. Ou alors NBCOLS et NBLIGNES ca on comprends. ce sont apparemment des détails mais c’est essentiel. lorsque tu reliras ton travail et surtout lorsque quelqu’un d’autre va le récupérer. et là c’est ton emploi qui est en jeu. si si pour un NBLIGNES à la place de LAG;

ensuite la relecture via des pointeurs. Là c’est erreur sur erreur.

deja tu declare mal ton pointeur. tu confonds allegrement les pointeurs sur int avec les doubles pointeurs. une horreur ! tu as des lignes d’entiers. donc il te faut un pointeur sur chaque ligne donc int * ptligne;

ce pointeur ligne indexe en fait chaque colonne de chaque ligne. il décrit une ligne.

ensuite faut un tableau de ces pointeurs de lignes donc tabLigne [lag] ou mieux tabcols[NBLIGNES] qui permet de prendre l’adresse de la colonne. tabcol ou alors ptcols donc int **pt_int;

ce qui fait que pt_int{0 1 …] indiquent les adresses de debut de chaque ligne, et ensuite que pt_int[0 ou 1 ou …][0 1 2 3 … ] indiquent chaque entier du tableau. la valeur

pt_int [3]{10] indique la 11eme cellule de le 4eme ligne puisque que l’on commence les indices à 0.

ensuite, commentaire : sur les commentaires. dans un programme il faut - et je sais bien que c’est souvent un voeu pieux - quatre lignes de commentaires par ligne de programme. c’est comme ca.

au début tu expliques pas ce que fait le code présent. on ne sait pas. quelqu’un qui reprends ton source pour voir s’il lui est utile le colle à la poubelle de suite. et toi tu est guere mieux placé. ton travail est divisé par 100. 100 etant le nombre de fois ou l’on aurait pu utiliser ton bout de code.

deja tu parles de stdafx.h. a quoi sert ce fichier, affichage standard il est pas dans des dossiers systemes du compilo comme iostream.h (d’ailleurs le .h a viré de là, etrange?) faut donc expliquer ce qu’il fait ce fichier. il doit servir puisque il est là. il doit reprendre une constante utilisée ici. à la lecture ca a pas l’air d’etre utile.

le seul commentaire indique comment tu remplis le tableau. en fonction de la largeur et de la hauteur. hors celles ci sont constantes. donc une seule valeur doit etre rentrée. comment est t’elle calculée.

si on regarde le code, on s’apercevoit que l’on remplit le tableau par une suite algébrique d’increment 1 en partant du haut à gauche du tableau puis vers la colonne puis en revenant à la colonne de gauche de la ligne en dessous.

décrit comme cela. on sait ce que fait le programme. ensuite à chaque d’expliquer l’algo utilisé pour remplir via un schema. les valeurs à obtenir et les indices correspondants. soit quelque chose comme,

[cpp]/*******************************
i = 0, d=0 * i = 0, d = 1
valeur 1 * valeur 2


i = 1, d=0 * i = 1 d = 1
valeur 3 * valeur = 4
******************************/[/cpp]

et bien sur ensuite tu vois de suite que la valeur vaut log * i + d + 1, tu en tire le code suivant. ou log est le nombre de colonnes.

ou bien alors tu vois que tu remplis le tableau à plusieurs dimensions en commencant par les colonnes et en descendant par les lignes et que cette méthode à l’avantage de ne pas necessiter de multiplication.

la tout le monde comprends et rapidement.

ensuite tu relis le tableau via des pointeurs et là aussi tu expliques comment tu fais. le pourquoi de **pt_int, etc… et en commentant tu trouves de suite ton probleme.

pour compiler, le programme a été testé avec quelles dll du compilo sous quelles versions de windows, on parle de console c’est bien mais comment on lance, le compilateur qui a compilé la version est lequel, on le trouve ou ? si possible on a un zip present sur un ftp sur internet dont on donne la référence. ou alors un numero de dossier. ensuite on indique l’historique des bugs. à chaque changement dans une fonction on incremente un numero de fonction et un code de modif.

voilà les critiques, et c’est pour ca que ca marche pas. ton programme est pas défini par avance et tu te plantes lamentablement.

en programmation et je l’ai dis à quelqu’un qui posait la question, il faut surtout réfléchir. on doit faire quelque chose, on décrit la chose, on donne les ressources que l’on a, et on etudie les solutions à apporter. donc on fait quelque chose comme

[cpp]#if SOLUTION == 1
#elseif SOLUTION == 2
#elseif SOLUTION == 3
#else
int main () {
cout << “solution pas encore étudiée” << SOLUTION;
}
#endif[/cpp]
ca ca montre que la personne a réfléchi au moins à proposer un choix de solutions.

programmer c’est analyser et réfléchir.