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 :

Erreur de segmentation lors d'accès à un tableau


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné Avatar de humitake
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2010
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2010
    Messages : 399
    Par défaut Erreur de segmentation lors d'accès à un tableau
    Bonjour,

    Je dispose d'une base de données avec des numéros de téléphone, je souhaite récupérer ces numéros depuis mon programme c++. J'ai donc créer une fonction callback que j'utilise lors de l'appel de sqlite3_exec.

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    int SMS::setRecipients(){
        char** recipients;
        recipients = (char**) malloc(128*sizeof(char*));
        for(int i = 0; i < 128; i++)
            recipients[i] = (char*) malloc(16 * sizeof(char));
        recipients[0] = "1";
        bd.setSql("SELECT tel FROM Sms WHERE etat = 1");
        sqlite3_exec(bd.getConnection(), bd.getSql().c_str(), callbackGetRecipients, recipients, NULL);
        std::cout << "requete : ok" << std::endl;
        for(int i = 1; i < atoi(recipients[0]); i++){
            this->recipients += "*";
            this->recipients += recipients[i];
        }
        std::cout << this->recipients << std::endl;
    }

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int callbackGetRecipients(void *recipients, int nbCol, char** res, char** name){
        char **temp = (char **)recipients;
        int i = atoi(temp[0]);
        strcpy(temp[i], res[0]);
        i++;
        char buffer[16];
        memset(buffer, 0, 16);
        sprintf(buffer, "%d", i);
        strcpy(temp[0], buffer);
        return 0;
    }

    La fonction callback est appelée pour chaque ligne retournée par la base de données. Afin de savoir quel ligne je suis en train de traiter j'incrémente la variable i et je stock son résultat dans la case 0 du tableau "recipients". A chaque passage dans la fonction callback je récupère la valeur contenu dans recipients[0] afin de savoir dans quel case je dois stocker le résultat.

    L'erreur intervient sur la ligne 10 de la fonction callback : "Erreur de segmentation".
    Cependant si je remplace strcpy(temp[0], buffer); par strcpy(temp[1], buffer); (en changeant de case), je n'ai plus cet erreur.
    Je ne peux donc pas avoir accès à la même case que celle que j'ai utilisé pour la récupération de l'index (i).

    Je ne comprend pas à quoi est dû cet erreur, si quelqu'un peut m'aider ...

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Pourquoi, en C++, utilises-tu des pointeurs de pointeurs et des malloc ?

  3. #3
    Membre émérite Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Par défaut
    Bonjour,
    Je ne vois pas pourquoi tu as cette erreur, mais je vais faire quelques remarques sur ton code.
    (Et, avec un peu de chance, ça résoudra ton problème... )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char** recipients;
    recipients = (char**) malloc(128*sizeof(char*));
    for(int i = 0; i < 128; i++)
        recipients[i] = (char*) malloc(16 * sizeof(char));
    Tu fais du C++, utilise les instructions C++...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char** recipients;
    recipients = new char*[128];
    for(int i = 0; i < 128; i++)
        recipients[i] = new char[16];
    Quoique vu qu'il n'y a que des constantes...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char recipients[128][16];
    Ça t'évitera de faire des delete à la fin de la fonction.


    Aïe !
    Là tu perds l'adresse de la mémoire que tu viens d'allouer...
    (Le problème vient peut-être de là, finalement... )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    std::strcpy(recipients[0], "1");
    //********//
    recipients[0][0] = '1';
    recipients[0][1] = '\0';

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char **temp = (char **)recipients;
    Ah...
    Encore l'héritage du C...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char **temp = reinterpret_cast<char **>( recipients );

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char buffer[16];
    memset(buffer, 0, 16);
    sprintf(buffer, "%d", i);
    strcpy(temp[0], buffer);
    Hum...
    Quel est donc l'intérêt de passer par une variable auxiliaire...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::sprintf(temp[0], "%d", i);
    Ce n'est pas mieux comme ça ?


    Ceci étant dit, je me pose des questions quant à l'utilisation de char * et de tableaux.
    Héritage du C, ou réel besoin ?
    Parce que d'après ce que tu as posté, on peut très bien faire la même chose avec des std::string et std::vector.
    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
    #include <sstream>
    #include <vector>
     
    int SMS::setRecipients()
    {
        std::vector<std::string> recipients(128, std::string()); // ou recipients(128, "");
        recipients[0] = "1";
        (...)
        sqlite3_exec(bd.getConnection(), bd.getSql().c_str(), callbackGetRecipients, &recipients, NULL);
        (...)
        std::istringstream iss(recipients[0]);
        int max;
        iss >> max;
        for (int i = 0; i < max; i++) {
            (...)
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <sstream>
    #include <vector>
     
    int callbackGetRecipients(void *recipients, int nbCol, char** res, char** name){
        std::vector<std::string>& temp = *reinterpret_cast<std::vector<std::string>*>( recipients );
        std::stringstream ss(temp[0]);
        int i;
        ss >> i;
        temp[i] = res[0];
        ss.str("");
        ss << ++i;
        temp[0] = ss.str();
        return 0;
    }
    Et voilà.
    C'est-y pas mieux comme ça ?
    Si tu as des questions, n'hésite pas.

  4. #4
    Membre émérite Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Par défaut
    En y réfléchissant, ce n'est peut-être pas la peine de remplir le vector à la création...
    J'avais dû lire ton code un peu trop vite.

    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
    int SMS::setRecipients()
    {
        std::vector<std::string> recipients;
        (...)
        sqlite3_exec(bd.getConnection(), bd.getSql().c_str(), callbackGetRecipients, &recipients, NULL);
        (...)
        for (std::vector<std::string>::iterator it = recipients.begin(); it != recipients.end(); ++it) {
            this->recipients += "*";
            this->recipients += *it;
        }
        (...)
    }
     
     
    int callbackGetRecipients(void *recipients, int nbCol, char** res, char** name){
        std::vector<std::string>& temp = *reinterpret_cast<std::vector<std::string>*>( recipients );
        temp.push_back(res[0]);
        return 0;
    }
    Et hop !
    Même plus besoin de conserver l'index de la ligne à traiter !
    Le vector grossit au fur-et-à-mesure des ajouts, toujours en fin.

    C'est tout de même plus simple, non ?

  5. #5
    Membre chevronné Avatar de humitake
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2010
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2010
    Messages : 399
    Par défaut
    Houla, effectivement je crois que je vais devoir me repencher sur mes cours de c++

    Désolé de répondre si tardivement, j'étais tellement penché sur le problème que j'en avais complètement oublié ce post
    Au final j'ai découvert qu'il y avait un moyen pour récupérer les résultats sans passer par des fonctions callback, ce qui au final est un petit plus puisque cela m’évitera d'avoir d'innombrable fonction callback Et qui permet en plus de simplifier le code

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int SMS::setRecipients(){
        sqlite3_stmt *stmt = NULL;
        bd.setSql("SELECT tel FROM Sms WHERE etat = 1");
        int rc = sqlite3_prepare(bd.getConnection(), bd.getSql().c_str(), -1, &stmt, NULL);
        if(rc != SQLITE_OK) exit(-1);
        while(sqlite3_step(stmt) == SQLITE_ROW){
            this->recipients += "*";
            this->recipients += (char *)sqlite3_column_text(stmt, 0);
        }
        sqlite3_finalize(stmt);
        std::cout << this->recipients << std::endl;
    }

    Encore merci

  6. #6
    Membre émérite Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Par défaut
    C'est vrai que c'est plus simple comme ça.
    N'oublie pas pour autant les opérateurs de transtypage C++ !
    F.A.Q. C++: Comment effectuer une conversion de type explicite (cast) ?

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    ligne 4 : c'est vraiment utile, de passer l'adresse d'un pointeur, plutôt que le pointeur directement ?

    Cela ne serait-il pas intéressant d'utiliser un pointeur intelligent ?

    Ta fonction n'est-elle pas supposée renvoyer un entier ?

    Que sont bd et rc ? Des variables globales ? Ou des variables membres ?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Erreur de segmentation lors de la compilation
    Par touzack dans le forum Débuter
    Réponses: 2
    Dernier message: 21/07/2010, 12h17
  2. Réponses: 7
    Dernier message: 12/05/2010, 15h33
  3. Erreur de segmentation lors du rafraichissement d'un ListStore
    Par Difool dans le forum GTK+ avec Python
    Réponses: 1
    Dernier message: 23/02/2010, 16h09
  4. Réponses: 1
    Dernier message: 22/03/2009, 19h44
  5. Réponses: 23
    Dernier message: 08/01/2006, 22h59

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