IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Questions de débutant + Segmentation erreur qu'en boucle


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 8
    Par défaut Questions de débutant + Segmentation erreur qu'en boucle
    Bonjour à tous,

    Dans le cadre de ma formation d'ingénieur spécialisé en simulation numérique, nous faisons beaucoup de calcul scientifique et nous utilisons beaucoup le Fortran. Nous avons été introduits au C++ pour nous faire découvrir la programmation orientée objet et dans le cadre d'un mini projet, je mepose encore quelques questions, car je n'aimerais pas partir sur des bases peu solides.

    1) J'ai trois classes différentes donc 3 fichiers hxx différents, 3 fichiers cxx différents et un main. Comment inclure proprement les dépendences pour chaque fichier? J'ai peur de trop user des #include. Sachant que pour faire simple, ma classe C utilise la classe B qui utilise la classe A.

    2) Est il mieux de déclarer mes classes dépendantes en tant que classes amies ou en tant que classes filles avec héritage public?

    3) Lorsque je définis mes constructeurs, que faut il utiliser entre reallocate et new lorsqu'il s'agit de créer de la mémoire pour un vecteur par exemple?

    4) Dans une des classes, je dois surcharger l'opérateur << pour afficher une matrice, connaissez vous une manière pour l'afficher proprement (même espace alloué à chaque élément de matrice pour que tout soit aligné corrrectement, en gros indiquer au compilateur que je veux automatiquement 4 décimales pour chaque réel)

    Par ailleurs je m'arrache les cheveux sur une erreur de segmentation qui se produit lorsque je veux calculer le premier élément d'un vecteur solution d'un système tridiagonal, et même après avoir vérifié toutes les tailles je ne sais pas d'où ca vient.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    void MatrixTridiag::Solve(vecteur& x)
    {
      unsigned n = x.size();
      vecteur y(n), w(n);
     
      y(0) = x(0);
      for (unsigned i = 1; i < n; i++)
        y(i) = x(i) - alpha(i-1)*y(i-1);
     
      for (unsigned i = 0; i < n; i++)
        w(i) = y(i)/delta(i);
     
      x(n-1) = w(n-1);
     
      for (unsigned i = n-2; i >= 0; i--)
        x(i) = w(i) - alpha(i)*x(i+1);
     
     // x(0) = w(0) - alpha(0)*x(1);
    }
    J'ai essayé de printer w(0), alpha(0) et x(1) et ils me donnent bien le bon résultat. Quand je calcule x(0) dans la boucle, j'ai erreur de segmentation alors que lorsque je le fais hors boucle, ca fonctionne parfaitement (partie commentée)! Je ne comprends pas?

    Merci d'avance pour votre aide.

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut, et bienvenue sur le forum.

    Au cas ou tu n'aurais pas lu ma réponse sur l'autre forum, je te la recopie à peu près ici
    Dans le cadre de ma formation d'ingénieur spécialisé en simulation numérique, nous faisons beaucoup de calcul scientifique et nous utilisons beaucoup le Fortran. Nous avons été introduits au C++ pour nous faire découvrir la programmation orientée objet et dans le cadre d'un mini projet, je mepose encore quelques questions, car je n'aimerais pas partir sur des bases peu solides.

    1) J'ai trois classes différentes donc 3 fichiers hxx différents, 3 fichiers cxx différents et un main. Comment inclure proprement les dépendences pour chaque fichier? J'ai peur de trop user des #include. Sachant que pour faire simple, ma classe C utilise la classe B qui utilise la classe A.
    Il faudrait en savoir plus sur les différentes classes, mais, en gros, tu as deux solutions:
    • soit ta classe tes classes utilisent essentiellement des pointeurs et /ou des références sur la classe qu'elles utilisent, et tu peux alors utiliser la déclaration anticipée dans le fichier d'en-tête (*.h / *.hxx / *.hpp) pour n'inclure le fichier d'en-tête de la classe utilisée que dans le fichier d'implémentation (*.cxx / *.cpp)
    • Soit la dépendance envers la classe utilisée est plus forte (tu utilise une instance de la classe ou tu utilises l'héritage), et tu es alors obligé d'inclure le fichier d'en-tête de la classe utilisée dans le fichier d'en-tête de la classe "dépendante"

    2) Est il mieux de déclarer mes classes dépendantes en tant que classes amies ou en tant que classes filles avec héritage public?
    ans doute ni l'un ni l'autre .

    L'amitié d'une classe envers une autre n'a de sens que si tu envisage que la classe déclarée amie puisse vouloir accéder à quelque chose que tu ne juge pas utile de placer dans l'accessibilité publique. Et il faut de toutes façon toujours préférer l'appel d'une fonction (qu'elle soit publique, protégée ou privée) à l'accès direct à une des donnée membre de ta classe... Car, plus tu auras de fonction qui vont directement manipuler les données membres, plus tu auras du mal à trouver "où est la faille" en cas de problème .

    Et l'héritage public est la relation la plus forte qui puisse exister entre deux classes car c'est une relation que l'on qualifie volontiers de relation EST-UN au sens sémantique du terme (une Voiture EST-UN véhicule ). C'est donc la relation que l'on n'utilise que lorsque l'on a vraiment besoin de profiter de son principal bienfait : la possibilité de faire passer un objet du type dérivé pour étant du type de base (cela s'appelle la substituabilité ) et de son corrollaire les comportements polymorphes.

    Mais, avant de décider de créer cette relation, il faut aussi s'assurer que le LSP (Liskov Substitution Principle ou, si tu préfères le Principe de Substitution de Liskov) sera respecté et que les règles de programmation par contrat sont respectées. Ces règles sont simples :
    • les précondition du type de base ne peuvent pas être affaiblies dans le type dérivé
    • les postconditons du type de bas ne peuvent pas etre renforcées dans le type dérivé
    • les invariants du type de base doivent être respectés dans le type dérivé



    C'est, pour te donner deux exemples concrèts, à cause de ces règles qu'une classe ListeTriée ne peut pas hériter d'une classe Liste (non triée) et inversement ou qu'une classe Carré ne peut pas hériter d'une classe Rectangle ni d'une classe Losange (et inversement), malgré ce que tu as appris en cours de géométrie élémentaire
    3) Lorsque je définis mes constructeurs, que faut il utiliser entre reallocate et new lorsqu'il s'agit de créer de la mémoire pour un vecteur par exemple?
    Sauf cas exceptionnel, ni l'un ni l'autre :la classe vector disponible dans l'espace de noms std par simple inclusion du fichier d'en-tête <vector> (ou la class array, si tu connais la taille du tableau à la compilation, dans le même espace de noms à laquelle tu as acces en C++11 grâce au fichier d'en-tete <array>) sont faite pour gérer les tableaux... c'est elles que tu dois utiliser

    Sauf cas exceptionnel, tu ne dois envisager le recours à l'allocation dynamique de la mémoire que pour les classes qui interviennent dans une hiérarchie de classes (on parle de classe ayant sémantique d'entité), et il y a systématiquement des précaution à prendre (les rendre non copiables et non affectables, utiliser des pointeurs intelligents, ...)
    ar ailleurs je m'arrache les cheveux sur une erreur de segmentation qui se produit lorsque je veux calculer le premier élément d'un vecteur solution d'un système tridiagonal, et même après avoir vérifié toutes les tailles je ne sais pas d'où ca vient. Apparemment le debug sur les dépassements de tableaux en c++ n'existe pas on m'a dit?? Si vous pouvez m'éclairer.. Je vous joints mon code en archive. La fonction source de l'erreur en question est MatrixTridiag::Solve dans spline.cxx.
    Une erreur de segmentation est généralement le symbole que tu as transformé ta mémoire en choucroute (si, si, tu l'as passée à la rape )... La raison en est sans doute l'usage intensif des pointeurs que tu as fait

    Commence à faire du vrai C++ et non du "C with classes", use et abuse des possibilités offertes par la bibliothèque standard (essentiellement std::vector / std::array ), et tu te sentiras tout de suite beaucoup mieux (et ton code itou )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre chevronné
    Profil pro
    Consultant en technologies
    Inscrit en
    Octobre 2013
    Messages
    158
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Consultant en technologies

    Informations forums :
    Inscription : Octobre 2013
    Messages : 158
    Par défaut
    Tiens je savais pas qu'on formait encore des jeunes au Fortran (de mon temps on était la première génération à ne plus faire de Fortran)
    J'ai bien eu quelques codes Fortran entre les mains quand j'étais thesard, mais c'était soit pour les lier à du code C++ (à grand coup de extern) soit pour les porter en C++.

    Pour l'héritage et la conception tu as eu d'excellent réponse plus haut, je rajouterais deux proverbes c'est en forgeant qu'on devient forgeron (donc en te plantant tu feras mieux la prochaine fois) mais aussi qu'il ne faut pas ré-inventer la roue, et qu'il y a pleins de choses dans la librairie standard, dans boost voire dans Qt et d'autres lib haut niveau.

    Pour ton problème je vois un truc dans ton code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void MatrixTridiag::Solve(vecteur& x)
    {
      unsigned n = x.size();
      vecteur y(n), w(n);
     
      y(0) = x(0);
    vecteur c'est une classe où une fonction ? (Je crois que je connais la réponse, réfléchis y)
    car y(0) = x(0) ca m'a pas l'air très orthodoxe.
    Se pourrait-il que tu construise un vecteur y de taille zéro puis que tu le rende égal à un vecteur x de taille 0
    Sans surprise tu aurais alors une Segfault

    Au passage, le meilleur moyen de trouver une Segfault c'est d'utiliser un debugger, sous Linux, gdb est très bien mais un peu lourd,
    au premier niveau ca marche comme ca
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    $gdb monprog 
    #WELCOME TO GDB 
    #... 
    # 
    (gdb) set args argument de monprog 
    (gdb) run 
    #ici gdb va t'afficher tout ce qui se passe lorsque le programme tourne 
    #Message d'erreur pour indiquer que le programme a planté 
    (gdb) backtrace 
    #Ici gdb va te dire où ca a planté
    Il y a des tutos plus complets, mais ca devrait pas mal t'aider

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 8
    Par défaut
    Bonjour et un énorme merci pour vos explications, koala01. Merci aussi à vous _zzyx_.

    Nous avons fait un TP pour se familiariser avec l'allocation dynamique, et nous avons crée une classe vecteur, où les données membres sont la taille (entier) et un pointeur vers les données (data). Nous sommes libres d'utiliser celle là ou la classe vector de la std. Voici nos constructeurs pour cette classe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    private :
      unsigned taille; // taille du vecteur
      double* data; // donnees
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    vecteur::vecteur()
    {
      taille = 0;
      data = NULL;
    }
     
    // vecteur de taille n
    vecteur::vecteur(unsigned n)
    {
      if (n == 0)
        {
          taille = 0;
          data = NULL;
        }
      else
        {
          taille = n;
    #ifdef DEBUG
          try
    	{
    #endif
     
    	  data = new double[n];
     
    #ifdef DEBUG
    	}
          catch (...)
    	{
    	  cout << "Impossible d'allouer le tableau" << endl;
    	  cout << "Taille demandee : " << n << endl;
    	  abort();
    	}
    #endif
        }
    }
    Et voici ce que me donne gdb :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Program received signal SIGSEGV, Segmentation fault.
    0x00000000004014a5 in MatrixTridiag::Solve (this=0x7fffffffde70, x=...)
        at spline.cxx:112
    112	    x(i) = w(i) - alpha(i)*x(i+1);
    (gdb) backtrace
    #0  0x00000000004014a5 in MatrixTridiag::Solve (this=0x7fffffffde70, x=...)
        at spline.cxx:112
    #1  0x0000000000401954 in main () at main.cc:40
    (gdb)
    Il doit y avoir une erreur de mémoire mais j'ai beau chercher, je ne vois pas d'où elle peut venir.

  5. #5
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 487
    Par défaut
    Franchement, utilisez std::vector le plus vite possible. Vous gagnerez beaucoup de temps et de la longévité pour votre cuir chevelu.

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 8
    Par défaut
    Je vais essayer d'utiliser std::vector partout alors!

    Par ailleurs oui on fait encore du Fortran (même avec sa syntaxe archaique) car les grands groupes disposent encore de librairies fortran qui doivent être traduites en C++. Par ailleurs beaucoup de modules de logiciels de mécanique des fluides numériques sont écrits en Fortran.

Discussions similaires

  1. Erreur de Segmentation en fin de boucle
    Par SebHaLEau dans le forum C
    Réponses: 5
    Dernier message: 12/02/2013, 22h37
  2. [MFC] Quelques questions de débutant...
    Par Sephi dans le forum MFC
    Réponses: 4
    Dernier message: 20/02/2004, 17h25
  3. Questions de débutant
    Par J-P-B dans le forum XMLRAD
    Réponses: 12
    Dernier message: 24/07/2003, 15h19
  4. [Débutant][JNI]Erreur de chargement de dll
    Par Agifem dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 24/04/2003, 14h36
  5. [HyperFile] 2 questions de débutant
    Par khan dans le forum HyperFileSQL
    Réponses: 2
    Dernier message: 29/04/2002, 23h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo