Aller au contenu
  • Pas encore inscrit ?

    Pourquoi ne pas vous inscrire ? C'est simple, rapide et gratuit.
    Pour en savoir plus, lisez Les avantages de l'inscription... et la Charte de Zébulon.
    De plus, les messages que vous postez en tant qu'invité restent invisibles tant qu'un modérateur ne les a pas validés. Inscrivez-vous, ce sera un gain de temps pour tout le monde, vous, les helpeurs et les modérateurs ! :wink:

[C] pb avec des pointeurs et structures


Messages recommandés

Posté(e)

Bonjour,

 

J'utilise le programme suivant pour inserer des nombres dans une structures. (Au final je souhaites utiliser une deuxième structure temporaire pour y inserer les enregistrements mis a jour pour ensuite les transferer dans la premiere).

Mais pour le moment le problème est le suivant : j'insère bien mes enregistrement dans le tableau 2dimensions de ma structure, seulement ensuite lorsque je cherche à les retrouver je bloque. Mon programme est le suivant :

 

#include <stdio.h>
#include <stdlib.h>

typedef struct {
 int val; /* Contenu de la cellule */
 int gen; /* Nombre de générations pendant lesquelles la cellule a eu sa valeur courante */
} cellule;

typedef struct {
 cellule *tab; /* Tableau à 2 dimensions de cellules */
 int largeur, hauteur; /* Dimensions du tableau de cellules */
} field_t;

cellule *pos(field_t *F,int x,int y){
return (F->tab) + ((x * F->largeur) + y); /* (F->tab) + F->largeur * y + x; */
}
int main() {

int i, j;

field_t *ptr_champ = (field_t*)malloc(sizeof(field_t));

ptr_champ->largeur = 10;
ptr_champ->hauteur = 5;

ptr_champ->tab = (cellule*)malloc(sizeof(cellule)*(ptr_champ->largeur)*(ptr_champ->hauteur));

for(i = 1; i < (ptr_champ->largeur)-1; i++) {
	for(j = 1; j < (ptr_champ->hauteur)-1; j++) {
		/* insertion */
		ptr_champ->tab = pos(ptr_champ,i,j);
		if (i < 5)
			ptr_champ->tab->val = 16;
		else
			ptr_champ->tab->val = 18;

		ptr_champ->tab->gen = 17;
		printf("TEST- %d %d : %d - %p\n", i, j, ptr_champ->tab->val, ptr_champ->tab);
	}
}

printf("----------------------------------------\n");
printf("----------------------------------------\n");

for(i = 1; i < (ptr_champ->largeur)-1; i++) {
	for(j = 1; j < (ptr_champ->hauteur)-1; j++) {
		/* En reutilisant la fonction suivante de nouvelles adresses sont affectees...
		 * ptr_champ->tab = pos(ptr_champ,i,j);
		 * sans la fonction, ptr_champ-tab pointe vers la derniere adresse 
		 */
		printf("TEST- %d %d : %d - %p\n", i, j, ptr_champ->tab->val, ptr_champ->tab);
	}
}

free(ptr_champ->tab);
free(ptr_champ);

return 0;	
}

 

par ailleurs mon premier free() plante.

Toute idée ou indice est le bienvenue, en vous remerciant !

Posté(e)

Effectivement, joli "Invalid pointer"....

Dis donc, t'essaierais pas, par hasard, de libérer un bloc mémoire qui ne commence pas à l'adresse que tu donnes ?

L'adresse représentée par la valeur de ptr_champ->tab à la fin de la boucle n'a pas été allouée de manière individuelle, donc le free() refuse de libérer quoi que ce soit.

 

Je crois que voilà ton erreur :

ptr_champ->tab = pos(ptr_champ,i,j); 

Ta fonction pos() travaille en adressage relatif, donc si tu changes la valeur de départ à chaque appel, tu vas vite sortir de ce que tu as alloué !

Solution : garder au chaud la valeur initiale de ptr_champ->tab pour la restaurer une fois que tu as fini, ou arrêter de réaffecter cette valeur à chaque cellule à laquelle tu accèdes...

 

Tu aurais pu remarquer que les adresses affichées n'augmentaient pas de manière linéaire...

TEST- 1 1 : 16 - 0x80498d8

TEST- 1 2 : 16 - 0x8049938

TEST- 1 3 : 16 - 0x80499a0

TEST- 2 1 : 16 - 0x8049a48

TEST- 2 2 : 16 - 0x8049af8

TEST- 2 3 : 16 - 0x8049bb0

TEST- 3 1 : 16 - 0x8049ca8

TEST- 3 2 : 16 - 0x8049da8

TEST- 3 3 : 16 - 0x8049eb0

TEST- 4 1 : 16 - 0x8049ff8

TEST- 4 2 : 16 - 0x804a148

TEST- 4 3 : 16 - 0x804a2a0

TEST- 5 1 : 18 - 0x804a438

TEST- 5 2 : 18 - 0x804a5d8

TEST- 5 3 : 18 - 0x804a780

TEST- 6 1 : 18 - 0x804a968

TEST- 6 2 : 18 - 0x804ab58

TEST- 6 3 : 18 - 0x804ad50

TEST- 7 1 : 18 - 0x804af88

TEST- 7 2 : 18 - 0x804b1c8

TEST- 7 3 : 18 - 0x804b410

TEST- 8 1 : 18 - 0x804b698

TEST- 8 2 : 18 - 0x804b928

TEST- 8 3 : 18 - 0x804bbc0

----------------------------------------

----------------------------------------

TEST- 1 1 : 18 - 0x804bbc0

TEST- 1 2 : 18 - 0x804bbc0

TEST- 1 3 : 18 - 0x804bbc0

(...)

Et en faisant le "test aux limites" tu te serais rendu compte que tu n'arrivais pas à remplir les 50 cellules que tu as allouées ! Tester un tableau de 50 éléments avec seulement 24 valeurs.... hum.... A ce propos, ne perds jamais de vue qu'en C les tableaux sont numérotés de 0 à n-1 (n étant la taille du tableau). C'est peut-être à cause de cela que tu n'as justement que 24 valeurs...

 

Eventuellement, dans ta fonction pos() il faudrait que tu multiplies tes offsets par sizeof(cellule) ça serait plus prudent. Là, je ne suis pas certain qu'il calcule les bonnes adresses...

Posté(e)

Merci !

entre temps j'ai réalisé cela :

#include <stdio.h>
#include <stdlib.h>

/* [...] structures identiques que préecedemment */

cellule *pos(field_t *F,int x,int y){
return (F->tab) + ((x * F->largeur) + y); /* (F->tab) + F->largeur * y + x; */
}
int main() {

int i, j;

field_t *ptr_champ = (field_t*)malloc(sizeof(field_t));
cellule *ptr_cellule, *adr_ptr;
cellule *ptr_cell;

ptr_champ->largeur = 10;
ptr_champ->hauteur = 5;

ptr_champ->tab = (cellule*)malloc(sizeof(cellule)*(ptr_champ->largeur)*(ptr_champ->hauteur));
ptr_cell	   = (cellule*)malloc(sizeof(cellule)*(ptr_champ->largeur)*(ptr_champ->hauteur));
ptr_champ->tab = pos(ptr_champ,1,1);

for(i = 1; i < (ptr_champ->largeur)-1; i++) {
	for(j = 1; j < (ptr_champ->hauteur)-1; j++) {
		/* insertion */

		if (i < 5)
			ptr_champ->tab->val = 16;
		else
			ptr_champ->tab->val = 18;

		if((i == 1) && (j == 1)) {
			ptr_cellule = ptr_champ->tab;
			printf("----\n");
		}

		ptr_champ->tab->gen = 17;
		printf("TEST- %d %d : %d - %p\n", i, j, ptr_champ->tab->val, ptr_champ->tab);
		(ptr_champ->tab)++;
	}
}
ptr_champ->tab = ptr_cellule;
printf("----------------------------------------\n");

for(i = 1; i < (ptr_champ->largeur)-1; i++) {
	for(j = 1; j < (ptr_champ->hauteur)-1; j++) {
		ptr_cell->val = ptr_champ->tab->val;
		printf("TEST- %d %d : %d - %p\n", i, j, ptr_champ->tab->val, ptr_champ->tab);
		printf("TEST- %d %d : %d - %p\n", i, j, ptr_cell->val, ptr_cell);
		if((i == 1) && (j == 1)) {
			adr_ptr = ptr_cell;
			printf("---- %p : %p\n", ptr_cell, adr_ptr);
		}
		(ptr_champ->tab)++;
		(ptr_cell)++;
		printf("TEST-- %d %d : %d - %p\n", i, j, ptr_champ->tab->val, ptr_champ->tab);
		printf("TEST-- %d %d : %d - %p\n", i, j, ptr_cell->val, ptr_cell);
	}
}

printf("---- %p : %p\n", ptr_cell, adr_ptr);
ptr_cell = adr_ptr;
printf("---- %p : %p\n", ptr_cell, adr_ptr);

for(i = 1; i < (ptr_champ->largeur)-1; i++) {
	for(j = 1; j < (ptr_champ->hauteur)-1; j++) {
		printf("TEST--- %d %d : %d - %p\n", i, j, ptr_cell->val, ptr_cell);
		(ptr_cell)++;
		printf("TEST---- %d %d : %d - %p\n", i, j, ptr_cell->val, ptr_cell);
	}
}
free(ptr_champ->tab); /* ne plante plus... */
free(ptr_champ);

return 0;	
}

Est ce que c'est cela :

if((i == 1) && (j == 1)) {
			adr_ptr = ptr_cell;

		}

"garder une valeur au chaud"... et faire des "(ptr_cell)++;" est ce vraiment correct ?

d'ailleurs free(ptr_champ->tab); ne plante plus

Posté(e)

Euh.

 

Là je vais te demander de commenter ton code parce que j'ai déjà eu pas mal de souci pour suivre dans le premier, mais là entre ptr_cell, ptr_cellule et ptr_champ ça ne va pas être possible... D'ailleurs si tu pouvais choisir définitivement entre le français et l'anglais pour tes noms de variables, ça serait super.

 

Autre question : pourquoi tu fais tes boucles de 1 à n-2 ?

 

Dernière question : puisque tu n'utilises plus pos() mais que tu passes par des (cellule *)++ il serait bon de la supprimer définitivement.

Posté(e)

Désolé je me suis laissé aller.

 

Les boucles vont de 1 a n-1 car ce programme doit faire parti d'un autre. L'autre va afficher les valeurs dans un terminal avec les ncurses. Pour faire plus joli, il y aura un cadre. Donc la première ligne (i=0) et la premiere colonne (j=0) ainsi que les dernieres (n-1) ne sont pas prises en comptes.

 

a pu de pos ^^

 

#include <stdio.h>
#include <stdlib.h>

typedef struct {
 int val; /* Contenu de la cellule */
 int gen; /* Nombre de générations pendant lesquelles la cellule a eu sa valeur courante */
} cellule;

typedef struct {
 cellule *tab; /* Tableau à 2 dimensions de cellules */
 int largeur, hauteur; /* Dimensions du tableau de cellules */
} champ_t;

int main() {

int i, j;

champ_t *ptr_champ = (champ_t*)malloc(sizeof(champ_t));
cellule *ptr_cell;
cellule *adr_ptr_champ, *adr_ptr_cell; /* variables utilisees pour stocker les adresses des cellules */

ptr_champ->largeur = 10;
ptr_champ->hauteur = 5;

/* allocation de la place pour stocker les 10*5 cellules */
ptr_champ->tab = (cellule*)malloc(sizeof(cellule)*(ptr_champ->largeur)*(ptr_champ->hauteur));
ptr_cell	   = (cellule*)malloc(sizeof(cellule)*(ptr_champ->largeur)*(ptr_champ->hauteur));

/* allocation de la place pour stocker l adresse de chacune des deux premieres cellules */
adr_ptr_champ  = (cellule*)malloc(sizeof(cellule*));
adr_ptr_cell   = (cellule*)malloc(sizeof(cellule*));

printf("--- 1 eme etape : initialisation ---\n");

for(i = 1; i < (ptr_champ->largeur)-1; i++) {
	for(j = 1; j < (ptr_champ->hauteur)-1; j++) {
		/* insertion */
		if (i < 5)
			ptr_champ->tab->val = 16;
		else
			ptr_champ->tab->val = 18;

		if((i == 1) && (j == 1)) {
			adr_ptr_champ = ptr_champ->tab; /* sauvegarde de l adresse de la premiere cellule du champ */
		}

		ptr_champ->tab->gen = 17;
		printf("TEST- %d %d : %d - %p\n", i, j, ptr_champ->tab->val, ptr_champ->tab);
		(ptr_champ->tab)++;
	}
}
ptr_champ->tab = adr_ptr_champ; /* on refait pointer ptr_champ->tab vers la premiere cellule du champ modifiee */
printf("--- 2 eme etape : transfert des valeurs ---\n\n");

for(i = 1; i < (ptr_champ->largeur)-1; i++) {
	for(j = 1; j < (ptr_champ->hauteur)-1; j++) {
		/* recopie des valeurs de champ vers mes nouvelles cellules */
		ptr_cell->val = ptr_champ->tab->val;
		/* on verifie que la valeur est copiee d une structure dans l autre et que 
		 * les adresses sont differentes
		 * printf("TEST- %d %d : %d - %p\n", i, j, ptr_champ->tab->val, ptr_champ->tab);
		 * printf("TEST- %d %d : %d - %p\n", i, j, ptr_cell->val, ptr_cell);
			*/
		if((i == 1) && (j == 1)) {
			adr_ptr_cell = ptr_cell; /* sauvegarde de l adresse de la premiere cellule du champ */
		}
		(ptr_champ->tab)++;
		(ptr_cell)++;
		/*
		printf("TEST-- %d %d : %d - %p\n", i, j, ptr_champ->tab->val, ptr_champ->tab);
		printf("TEST-- %d %d : %d - %p\n", i, j, ptr_cell->val, ptr_cell);
		*/
	}
}
printf("--- 3 eme etape : lecture des valeurs dans la deuxieme struture ---\n\n");
printf("On refait pointer ptr_cell vers sa premiere valeur:\n");
printf("ptr_cell(%p) <- adr_ptr_cell(%p)\n\n", ptr_cell, adr_ptr_cell);
ptr_cell = adr_ptr_cell;
for(i = 1; i < (ptr_champ->largeur)-1; i++) {
	for(j = 1; j < (ptr_champ->hauteur)-1; j++) {
		printf("val contenue dans ptr_cell %d, a l adresse :  %p\n", ptr_cell->val, ptr_cell);
		(ptr_cell)++;
	}
}
free(ptr_champ->tab); /* plante */
free(ptr_champ);

return 0;
}

 

je ne sais pas si ça se vois, mais je programme un peu a l'aveuglette...

et aurais tu une idée pour l'erreur sur le free lors de l'execution du programme. Alouant bien "ptr_champ->tab" au départ je devrais pouvoir le desaouler a la fin. non ?

 

Merci encore

Posté(e)
je ne sais pas si ça se vois, mais je programme un peu a l'aveuglette...
C'est pas bien ! (Et je suis sûr que tu sais que c'est pas bien) ;-)
et aurais tu une idée pour l'erreur sur le free lors de l'execution du programme. Alouant bien "ptr_champ->tab" au départ je devrais pouvoir le desaouler a la fin. non ?
Tu l'alloues au départ, mais pendant ton traitement tu fais (ptr_champ->tab)++ donc fatalement tu arrives à la fin avec une valeur de ptr_champ->tab modifiée ! Tu t'es fait ch$*% à déclarer adr_ptr_champ pour y sauvegarder la valeur d'origine de ptr_champ->tab, c'est donc cette adresse que tu devrais libérer.

A propos, je vois que tu alloues de la mémoire pour l'initialisation de adr_ptr_champ mais tu ne t'en sers pas, et tu écrases allègrement l'adresse de ce que tu as alloué par ptr_champ->tab... (Et je retrouve là les mêmes erreurs que lorsque je vois, en objet, des gens initialiser une variable avec un new Object() pour ensuite lui filer l'adresse d'un autre Object(). Ici c'est plus grave parce qu'il n'y a pas de Garbage Collector)

Autre truc étrange : tu as mis à l'intérieur de ta boucle un double test pour une condition qui n'arrive qu'une fois et dont tu connais par avance les valeurs (i==1 et j==1), pourquoi ne pas déplacer cette opération avant les boucles ?

la première ligne (i=0) et la premiere colonne (j=0) ainsi que les dernieres (n-1) ne sont pas prises en comptes.
OK, mais tu avoueras que c'est quand même bête d'allouer de la mémoire si c'est pour ne pas s'en servir...

Rejoindre la conversation

Vous pouvez publier maintenant et vous inscrire plus tard. Si vous avez un compte, connectez-vous maintenant pour publier avec votre compte.
Remarque : votre message nécessitera l’approbation d’un modérateur avant de pouvoir être visible.

Invité
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

  • En ligne récemment   0 membre est en ligne

    • Aucun utilisateur enregistré regarde cette page.
×
×
  • Créer...