Gestion dynamique de la mémoire [Résolu]

Signaler
Messages postés
6
Date d'inscription
lundi 1 juin 2009
Statut
Membre
Dernière intervention
4 novembre 2010
-
Messages postés
3813
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
12 juin 2020
-
Bonjour, j'apprends le C en autodidacte et je bloque sur strcmp et les pointeurs. Mon code marche bien sans pointeur, mais il y a un truc qui m'échappe des que je rajoute l'*'.Quand à accéder au tableau dans REP, je ne sais pas comment faire. Pouvez-vous m'aider? Merci d'avance

struct REP
{
char nom[21];
int nbtel;
int TNUM[3];
};

void main()
{
REP *TAB[30];
int ind=0;
int i;
char nomlu[21];
printf("Entrez le nom :");
gets(nomlu);
while(nomlu[0]!='*')
{
for(i=0; i<=ind && (strcmp(nomlu, TAB[i]->nom)!=0); i++);
{
if(i>ind)
{
strcpy(TAB[ind]->nom, nomlu);
printf("ENREGISTREMENT EFFECTUER %s\n", TAB[ind]->nom);
ind+=1;
}
else
printf("NOM DEJA ENREGISTRE\n");
}
printf("Entrez le nom :");
gets(nomlu);
}
system ("pause");
}

9 réponses

Messages postés
3813
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
12 juin 2020
109
ind était bien initialisé, c'était une erreur de copier-coller de ma part :)
system est utile est en debug, pas de souci.

_____________________________________________
Historique de mes créations, et quelques articles:[ http://0217021.free.fr/portfolio
http://0217021.free.fr/portfolio]
Messages postés
3813
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
12 juin 2020
109
Tu dois allouer de la mémoire, tout simplement, ce n'est pas automatique. Ou alors tu retires l'étoile qui n'est pas très utile ici.

Voici un cours sur les pointeurs:
http://0217021.free.fr/Cours/pointeurs.pdf

Une petite lecture de celui-ci te permettra, je pense, de comprendre ton erreur et de la corriger :)

_____________________________________________
Historique de mes créations, et quelques articles:[ http://0217021.free.fr/portfolio
http://0217021.free.fr/portfolio]
Messages postés
29
Date d'inscription
samedi 1 décembre 2007
Statut
Membre
Dernière intervention
11 avril 2010

Bonjour, il est vrai que la notion de pointeur est très abstraite, je te fais un bref descriptif, pour faire simple nous mettrons de coté, Allocation sur la pile et sur le tas, système 32-bit et 64-bit et pour finir alignement.

Que contient réellement une variable?
-une variable contient l'emplacement mémoire du premier octet représentant la donnée.

Par Exemple.
pour une variable "int val" situé à l'adresse mémoire 0x632A1 par exemple.
Si tu fais val=5, c'est la zone mémoire partant de 0x632A1 à 0x632A4 représentant 4 octets (taille d'un entier) qui sera affectée.
dans le cas de ta structure "REP", si on a une variable "REP MyRep" qui obtient l'adresse 0xCF650 par exemple pendant l'exécution et que tu fais
MyRep.nbTel=12. on prendrait l'adresse de base à savoir 0xCF650 auquel on rajoute 21 pour passer la zone représentant "nom",on affecterait alors la zone allant de 0xCF665 à 0xCF669.(fais pas trop attention au emplacement qui sont noté en hexadécimal)

- C'est quoi un pointeur?
c'est tout simplement une variable qui sert à stocker des adresses mémoire, pour information sur un système 32-bit, un pointeur occupe une zone mémoire de 4octects tout comme un entier, tu verras par la suite que tu peux aussi stocker des adresses mémoires dans un entier non-signé et utilisé des Cast afin de manipuler la donnée qu'il contient.

Par Exemple
j'ai une variable "int *val", jusqu'ici "val" n'est pas très différent du "val" de tout à l'heure, admettons que val se trouve à l'adresse 0xED004, il s'étale de la zone 0xED004 à 0xED008 puisqu'un pointeur ou du moins une adresse est contenu sur 4 octets, Sauf que la zone du val plus haut contenait 5; et celui-ci doit contenir une valeur représentant l'adresse mémoire d'un entier, mais lequel?
soit on place dans val une adresse mémoire existante, soit il nous faut en créer un nouveau. On décide d'en créer un nouveau avec l'opérateur new ;val= new int, met dans val la valeur de l'emplacement nouvellement créer soit 0X33AAC par exemple.
pour affecter une valeur à val on fait un déférencement soit *val=45; et en quoi consiste-il? il s'agit d'aller à l'emplacement de val soit 0xED004, de lire la valeur qu'il y a à cet emplacement c'est à dire 0X33AAC, d'aller à l'adresse 0X33AAC et de finalement écrire notre valeur.
Pour schématiser on pourrait dire qu'un pointeur est une variable qui contient l'emplacement mémoire d'une autre variable.


Pour finir:

-Toutes variables déclarées dans une fonction est créée dans la pile, même le val de notre "int *val" est créé dans la pile, c'est la valeur de l'emplacement qu'il contient qui doit être valide ou bien alloué par le programmeur, si on essaye d'écrire dans une zone non-alloué c'est le plantage assuré.

Pourquoi passer par les pointeur puisqu'il s'agit d'une variable tampon?
- parce qu'à la fin d'une fonction toutes les variables créées sur la pile sont détruites, et pour gérer des données en mémoires mm à la fin des fonctions il faut passer par la création d'éléments dans le tas, et pour ce faire on est obligé de passer par les pointeurs.

Ceci ne répond pas à ton problème mais peut t'aider à sa résolution.

pour te donner un coup de pouce, tu déclares un tableau de 30 pointeurs, mais ces dernier doivent contenir des emplacements mémoires invalides.
Surtout n'oublies pas de détruire tout allocation initié par new.

Au départ les pointeurs ne sont pas évident, mais après c'est le fun.

Salut, En espérant t'avoir aider.
Messages postés
6
Date d'inscription
lundi 1 juin 2009
Statut
Membre
Dernière intervention
4 novembre 2010

Merci pour vos réponses express, j'ai rajouté
TAB[ind]=(REP*)malloc(sizeof(REP));
avant strcmp et ça marche!! Après j'ai transformé "nom" en "*nom" dans ma struct et la ça ne marche plus du nouveau, pourtant j'ai mis
TAB[ind]->nom=strdup(nomlu);
a la place de strcpy. Il me sembait pourtant d'avoir compris avec vos explications.
J'ai cherché new dans la bible C, c'est pas plutôt du c++?
Merci d'avance
Messages postés
29
Date d'inscription
samedi 1 décembre 2007
Statut
Membre
Dernière intervention
11 avril 2010

oui en effet new c'est avec le C++; tu remplaces "char nom[21]" par "char *nom" tu rencontres le mm problème car tu n'as pas alloué l'espace mémoire pour ton "nom". avec "char nom[21]" ta structure à une taille de 37 octets soit: 21 pour "nom", 4 pour nbtel et 12=4*3 pour TNUM( on ne prend pas en compte l'alignement) Alors qu'avec "char*nom" la taille est : 20 soit 4 pour nom, 4 pour nbtel et 12 pour TNUM. soit tu alloues de la mémoire dont tu mets l'adresse dans "nom" ou soit tu laisses la première version dans laquelle l'espace pour représenter ton nom y est déjà.

Prends le temps de comprendre les pointeurs, car tu y gagneras beaucoup par la suite, à cause des erreurs à la con qu'on commet des fois.
Messages postés
3813
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
12 juin 2020
109
Envoie nous ton code complet qu'on puisse voir où est l'erreur.

TAB[ind]->nom=strdup(nomlu);

@goodboy21: strdup fait l'allocation, donc son problème ne vient pas de là.


_____________________________________________
Historique de mes créations, et quelques articles:[ http://0217021.free.fr/portfolio
http://0217021.free.fr/portfolio]
Messages postés
6
Date d'inscription
lundi 1 juin 2009
Statut
Membre
Dernière intervention
4 novembre 2010

Voici le code complet:

#include "stdio.h"
#include "stdafx.h"
#include "stdlib.h"
#include "string.h"

struct REP
{
char *nom;
int nbtel;
int TNUM[3];
};

void main()
{
REP *TAB[30];
int ind=0;
int i;
char nomlu[21];
printf("Entrez le nom :");
gets(nomlu);
while(nomlu[0]!='*')
{
TAB[ind]=(REP*)malloc(sizeof(REP));
for(i=0; i<=ind && (strcmp(nomlu, TAB[i]->nom)!=0); i++);
{
if(i>ind)
{
TAB[ind]->nom=strdup(nomlu);
printf("ENREGISTREMENT EFFECTUER %s\n", TAB[ind]->nom);
ind+=1;
}
else
printf("NOM DEJA ENREGISTRE\n");
}
printf("Entrez le nom :");
gets(nomlu);
}
system ("pause");
}

Pas de message d'erreur a la compilation mais a l'execution ça bloque sur la ligne strcmp:
- str1 0xcdcdcdcd incorrect unsigned char *
CXX0030: Erreur : impossible d'évaluer l'expression
- str2 0x0a09f9d4 incorrect unsigned char *
CXX0030: Erreur : impossible d'évaluer l'expression

Toujour un probleme d'allocation, je suis dessus depuis ce matin!
Merci pour vos reponses
Messages postés
3813
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
12 juin 2020
109
Plein de petite erreurs:
- ind n'est pas initialisé, donc vaut "aléatoire", et donc tu accèdes à une case invalide.
- Tu utilises sûrement un compilateur C++, parce que ce n'est pas une syntaxe rigoureuse du C (le struct que tu ne précise pas, et le fait de caster ton malloc, ce qui ne devrait pas être obligatoire). Attention C != C++, et tu ne peux pas compiler correctement du C "pure" avec un compilateur C++.
- system est à éviter (sauf system("pause") en débug seulement, qui peut être utile à quelqu'un sous Windows) car il pose des problèmes de compabilité (par exemple, je suis sous Linux et system("pause") ne fonctionnera pas chez moi).
- gets est déprécié. A éviter donc.
- stdafx.h => Pour quoi faire ?

Voici une correction. J'ai ajouter des fonctions pour rendre le code plus modulable et plus clair:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define REP_SIZE 30

typedef struct
{
  char* nom;
  int nbtel;
  int tnum[3];
} Rep;

int exists(Rep* tab[REP_SIZE], const char* name)
{
  int i = 0;
  while (tab[i] != NULL && i < REP_SIZE)
  {
    if (strcmp(name, tab[i]->nom) == 0)
      return 1;
    ++i;
  }

  return 0;
}

int addRecord(Rep* tab[REP_SIZE], const char* name)
{
  int i = 0;

  /*
  ** On recherche la premiere position libre
  */
  while (tab[i] != NULL && i < REP_SIZE)
    ++i;

  if (i >= REP_SIZE)
    return 0;

  tab[i] = malloc(1 * sizeof(Rep));
  tab[i]->nom = strdup(name);

  return 1;
}

void displayTab(Rep* tab[REP_SIZE])
{
  int i = 0;
  for (i = 0; tab[i] != NULL && i < REP_SIZE; ++i)
    printf("%s ", tab[i]->nom);
  printf("\n");
}

void freeTab(Rep* tab[REP_SIZE])
{
  int i = 0;
  for (i = 0; tab[i] != NULL && i < REP_SIZE; ++i)
  {
    free(tab[i]->nom);
    free(tab[i]);
  }
  printf("\n");
}

int main(void)
{
  char nomlu[21] = {0};
  Rep* tab[REP_SIZE] = {0};
  int i = 0;

  while (nomlu[0] != '*')
  {
    printf("Entrez le nom :");
    scanf("%s", nomlu);
    if (nomlu[0] == '*')
      break;
    if (exists(tab, nomlu))
      printf("NOM DEJA ENREGISTRE\n");
    else
    {
      if (addRecord(tab, nomlu))
printf("ENREGISTREMENT EFFECTUE %s\n", tab[i]->nom);
      else
printf("ENREGISTREMENT RATE %s\n", nomlu);
    }
  }

  displayTab(tab);
  freeTab(tab);

  return 0;
}


_____________________________________________
Historique de mes créations, et quelques articles:[ http://0217021.free.fr/portfolio
http://0217021.free.fr/portfolio]
Messages postés
6
Date d'inscription
lundi 1 juin 2009
Statut
Membre
Dernière intervention
4 novembre 2010

Ups, mon code m'a l'air tout minable d'un coup!
En effet, j'ai Visual Studio 2008 et "system" est la pour que je vois l'état de mes variables à la fin de l'exécution, stdafx est la par erreur. J'ai mis ind=0, il faut faire autrement pour l'initialiser? Pour gets je me renseigne, en tout cas maintenant j'ai le week-end pour assimiler la "correction"!! J'ai du boulot, dommage que j'ai la tete dur?
En tout cas merci pour vos réponses, c'est sympa