Mes amis les erreurs de segmentation ;)

Discutez d'informatique ici !
Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 19:42

par Rockleader » 10 Fév 2014, 20:50

Du coup; au niveau de la taille de ces allocations; est ce qu'elles ont réellement une importance ?

Par exemple; si je reviens sur mon tab qui est donc un pointeur de structure; il ne fait que pointer sur une structure.

Au final

Code: Tout sélectionner
TableauDynamique tab=NULL;
   tab=calloc(N, sizeof(tab));


Ne suffirait il pas de faire simplement

Code: Tout sélectionner
TableauDynamique tab=NULL;
   tab=calloc([COLOR=Red]1[/COLOR], sizeof(tab));


etc etc ?
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !



sylvainc2
Membre Naturel
Messages: 69
Enregistré le: 12 Aoû 2012, 19:22

par sylvainc2 » 10 Fév 2014, 22:05

Si tab pointe vers une seule structure alors il faut faire:

tab = calloc(1, sizeof(struct TableauDynamique));

J'ai changé aussi le sizeof() parce que tab étant un pointeur, il a 4 octets (ou 8 si ton ordi est 64 bits), donc sizeof(tab) alloue seulement 4 octets alors que tu veux allouer de l'espace pour toute la structure (qui contient plus que 4 octets).

Pour l'autre calloc:
tab->t = calloc(N, sizeof(Case));

si tu veux l'utiliser comme tel alors il faut changer le typdedef:

typedef struct uneCase *Case;
pour
typedef struct uneCase Case;

ceci alloue de l'espace pour N structures "Case"

et ensuite changer les références:
tab->t[k]->vide pour tab->t[k].vide,
tab->t[k]->val pour tab->t[k].val

car tab->t est un pointeur vers un tableau de "Case" qui est la même chose que "struct uneCase".

En tout cas,j'ai essayé ton code sur mon pc avec ces changements et il compile et s'exécute correctement sans erreur.

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 19:42

par Rockleader » 11 Fév 2014, 12:01

Mon programme fonctionne maintenant partout sauf sur un dernier cas de ma fonction d'ajout. Je prend une segmentation sur le realloc au moment ou j'atteins la taille limite du tableau alloué par le malloc.

Code: Tout sélectionner
void tableauDynamiqueAjouter(TableauDynamique tab, int v)
{
   [COLOR=Red]if(tab->nbVal==tab->size_max) //le cas nbVal >size_max n'est pas possible
   {
      int N=tab->size_init+tab->size_max; //nouvelle taille tableau
      int k;
      for(k=0;kt[k] = realloc(tab->t[k], N*sizeof(Case)); //on augmente la taille du tableau de la taille initiale + taille courante
         if (tab->t[k] == NULL)
         {
             fprintf(stderr, "Erreur realloc: lors de la réallocation mémoire du tableau\n");
             exit(2); //on quitte si le realloc plante
         }
      }
   }[/COLOR]
   int k=0;
   while(tab->t[k]->vide != VIDE) //on s'arrête lorsque l'on trouve la première case vide
   {
      k++;
   }
   tab->t[k]->val=v; //On ajoute v dans la case vide
   tab->t[k]->vide=PLEIN; //On indique case occupé
   tab->nbVal++;
   printf("test2\n"); //trace d'erreur
}


Avec une trace d'exécution

Chaque test2 correspond donc à l'ajout d'une valeur et chaque essai correspond à un realloc dans la boucle.
D'autant plus étrange que je rentre le bon nombre de fois dans mon realloc qui passe bien jusqu'à la taille 4; mais c'est après qu'il ne fait pas l'affectation. Aurais je loupé quelque chose ?

Taille de base pour votre tableau: 2
Le tableau est vide
test2
test2
essai
essai
essai
essai
Erreur de segmentation (core dumped)



EDIT: Je viens de penser à ce qui pourrait être la source du problème; est ce que le realloc agit de façon analogue au malloc ou bien au calloc ?
Car si la mémoire n'est pas initialisé à 0 cela pourrait expliquer le problème la boucle while finirait par taper sur une seg fault.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
fatal_error
Modérateur
Messages: 6610
Enregistré le: 22 Nov 2007, 13:00

par fatal_error » 11 Fév 2014, 12:57

ca represente quoi la variable k?
la vie est une fête :)

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 19:42

par Rockleader » 11 Fév 2014, 13:04

Le compteur pour mon tableau de structure de Case
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 08:03

par ampholyte » 11 Fév 2014, 13:09

Lorsque tu fais un realloc, il vaut mieux procéder de la manière suivante.

Code: Tout sélectionner
int *tab = NULL;
int *tmp = NULL;

tab = calloc(10, sizeof(int));
/* ... suite */

tmp = realloc(tab, 20, sizeof(int));
if (tmp != NULL) {
    tab = tmp;
} else {
    printf("ERROR\n");
    free(tab);
    tab = NULL;
}

free(tab);
tab = NULL;


Lorsque tu fais un realloc, tu déplaces ce qui a été alloué vers une place plus grande (ou plus petite).

Dans l'exemple ci-dessus, tab[0-9] est initialisé à 0, en revanche après le realloc, tab[10 - 19] n'est pas initialisé.

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 19:42

par Rockleader » 11 Fév 2014, 13:45

Oui; vous m'aviez déjà fait la remarque pour un temporaire; mais ici dans le cas ou ça plante je quitte le prog donc pas nécessaire; mais c'est bien noté.


En ce qui concerne la fonction, j'ai encore resserré l'erreur elle se trouve à priori sur la condition du while dans lequel je ne rentre pas pour une raison que je ne comprends pas.
Pourtant sans le realloc je rentre comme il faut dans cette boucle.

EDIT: C'est bon je me suis débugguer; j'avais oublié la réallocation sur tab->t ce qui faisait que tout le reste pointait n'importe où...Je me suis quand même fichtrement compliqué la vie avec le recul; mais au moins ça m'aura fait un bon exo sur les pointeurs que de faire un pointeur sur une structure contenant elle même un tableau de pointeur de structure --'
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 19:42

par Rockleader » 15 Fév 2014, 20:06

Nouveau petit problème; enfin disons juste que je voudrais tenter de comprendre.


Le but du sous programme est de réaliser un échange entre deux chaines de caractères.

Il y a une méthode simple qui est de passer par une variable temporaire et non pas de modifier les chaines mais les pointeurs qui vont pointé sur les chaines.
Cette méthode là est ok et est la plus pratique je pense.


Cela dit, j'ai voulu faire une méthode peut être plus logique ; mais malheureusement un peu plus bourrin aussi x)

EN gros, je crée une chaine temporaire.
Je lui donne la taille de la chaine1.
Et je me sert de strcpy pour faire des copies.
Mon code compile bien mais se retrouve avec une exécution strange; j'ai des résultats qui ressemble un peu à la commande système md5Sum qui affiche le chemin d'un fichier et sa signature.
Le tout aboutissant sur une erreur de segmentation.

Voilà à quoi ça ressemble
Les chaines 1 et 2 sont passé en paramètres.
Code: Tout sélectionner
*ch3=calloc((strlen(ch2)+1),sizeof(char));
   if(ch3==NULL)
      {
         fprintf(stderr, "Erreur calloc: échec de l'allocation mémoire de la chaine\n");
          exit(1); //on quitte si le calloc plante
       }
   strcpy(ch3,ch2);//copie de ch2 dans ch3
   int N=strlen(ch1)+1;
   ch2=realloc(ch2,N*sizeof(char)); //ch2 prend taille ch1
   strcpy(ch2,ch1);//copie de ch1 dans ch2
   int N2=strlen(ch3)+1;
   ch1=realloc(ch1,N2*sizeof(char));//ch1 prend taille ch3
   strcpy(ch1,ch3);//copie de c3 dans ch1


Je suis conscient du coté bourrin de ce code; mais je voudrais comprendre ce qui plante quand même.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
fatal_error
Modérateur
Messages: 6610
Enregistré le: 22 Nov 2007, 13:00

par fatal_error » 16 Fév 2014, 03:10

tu devrais déjà commencer par mettre un code complet plutot que nous balancer tes variables dont on ne connait même pas la déclaration.

Ensuite, ben tu peux y aller à coup de printf avant chaque realloc.
Aussi, afficher la taille de tes variables...avant les realloc.

Parenthèse, sizeof(char)==1...
la vie est une fête :)

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 08:03

par ampholyte » 16 Fév 2014, 11:21

Bonjour,

Ton code est assez particulier. Pour simplement faire un échange de chaine de caractère, il te suffit simplement de modifier l'emplacement du pointeur lié à la chaine. Tu n'as donc pas besoin de créer un nouvel espace mémoire pour "stocker" la valeur de la chaine.

Code: Tout sélectionner
void str_swap(char *chaine1, char* chaine2) {
    char *tmp = chaine1; /* On fait pointer tmp sur chaine1 */
    chaine1 = chaine2; /* On fait pointeur chaine1 sur chaine2 */
    chaine2 = tmp; /* On fait pointer chaine2 sur tmp */
}

Avatar de l’utilisateur
fatal_error
Modérateur
Messages: 6610
Enregistré le: 22 Nov 2007, 13:00

par fatal_error » 16 Fév 2014, 11:57

hello Ampholyte,

nan ca marche pas. Les pointeurs sont copiés lors de l'appel de str_swap, en modifiant la valeur de ces pointeurs copiés, on ne modifie pas la valeur des pointeurs passés en paramètres.
de fait, il faut passer l'adresse des pointeurs en argument afin de modifier la valeur pointée par l'adresse (qui est le pointeur que l'on désire voir swappé)

mais bon l'idée reste la même, c'est juste un détail technique

Code: Tout sélectionner
void str_swap2(char **chaine1, char** chaine2){
    char *tmp = *chaine1;
    *chaine1 = *chaine2;
    *chaine2 = tmp;
}
la vie est une fête :)

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 19:42

par Rockleader » 16 Fév 2014, 12:14

fatal_error a écrit:hello Ampholyte,

nan ca marche pas. Les pointeurs sont copiés lors de l'appel de str_swap, en modifiant la valeur de ces pointeurs copiés, on ne modifie pas la valeur des pointeurs passés en paramètres.
de fait, il faut passer l'adresse des pointeurs en argument afin de modifier la valeur pointée par l'adresse (qui est le pointeur que l'on désire voir swappé)

mais bon l'idée reste la même, c'est juste un détail technique

Code: Tout sélectionner
void str_swap2(char **chaine1, char** chaine2){
    char *tmp = *chaine1;
    *chaine1 = *chaine2;
    *chaine2 = tmp;
}



Sa je l'ai déjà et ça fonctionne bien ;) je veux juste comprendre pourquoi l'autre code ne fonctionne pas.

Le début de la fonction est là

Code: Tout sélectionner
void echange(char* ch1,char* ch2)
{
   printf("Chaine 1: %s\n",ch1);
   printf("Chaine 2: %s\n",ch2); //les deux chaines s'affiche bien ici


Pour le reste c'est exactement le code que j'ai mis plus haut à la suite. Je me rappelle avoir fait des tests et il me semble que l'on ne dépasse même pas le premier realloc.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
fatal_error
Modérateur
Messages: 6610
Enregistré le: 22 Nov 2007, 13:00

par fatal_error » 16 Fév 2014, 12:43

ch3 n'est pas déclaré.
Ton code est toujours incomplet. :hum:
Et quand bien même encore heureux que tu passes les arguments comme il faut.
Pourquoi tu ne mets pas tes printf avant chacun de tes realloc!!!

Le problème se trouve dans tes lignes de code, c'est ptet là qu'il faut regarder ce qu'il se passe...
la vie est une fête :)

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 08:03

par ampholyte » 16 Fév 2014, 13:27

Personnellement je pense que ton problème vient de ta ligne :

Code: Tout sélectionner
*ch3=calloc((strlen(ch2)+1),sizeof(char));


Je suppose que tu déclares :
Code: Tout sélectionner
 char *ch3 = NULL


Donc tu devrais plutôt avoir

Code: Tout sélectionner
ch3 = calloc((strlen(ch2)+1),sizeof(char));


Peut-être devrais-tu utiliser la fonction strdup :

Code: Tout sélectionner
 ch3 = strdup(ch2)


Cette fonction alloue une nouvelle chaine et l'initialise avec ch2.

Pour plus d'info man strdup ^^

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 19:42

par Rockleader » 16 Fév 2014, 14:31

En fait, je déclarais ch3 ainsi (effectivement j'avais oublié de le mttre dans mon copié coller; désolé.

Code: Tout sélectionner
char *ch3=ch2; //chaine temporaire


En réalité, ce que j'ai fait ici maladroitement aurait pu se faire avec strdup si j'en crois ton message ?

Dans tous les cas passer par les pointeurs est plus simple =)

Merci !
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 08:03

par ampholyte » 16 Fév 2014, 16:23

Rockleader a écrit:En réalité, ce que j'ai fait ici maladroitement aurait pu se faire avec strdup si j'en crois ton message ?


Tout à fait, en fait la fonction strdup, fait une copie de la chaine passée en paramètre (il ne faut oublier de free à la fin).

Après il y a une multitude de façon de faire.

Peut-être devrais-tu d'abord passer par une version "papier" de ton algorithme, pour vérifier que cela puisse marcher.

 

Retourner vers ϟ Informatique

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 2 invités

Tu pars déja ?



Fais toi aider gratuitement sur Maths-forum !

Créé un compte en 1 minute et pose ta question dans le forum ;-)
Inscription gratuite

Identification

Pas encore inscrit ?

Ou identifiez-vous :

Inscription gratuite