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 :

Passage par adresse d'un triple pointeur


Sujet :

C++

  1. #1
    Candidat au Club
    Inscrit en
    Novembre 2013
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Novembre 2013
    Messages : 3
    Points : 2
    Points
    2
    Par défaut Passage par adresse d'un triple pointeur
    Bonjour,

    J'essaye de faire un wrapper d'une lib C++ pour du C#, et dans ce cadre j'ai besoin de convertir un vector<string> en char***.
    Pour cela, j'utilise une fonction avec le vector<string> et le char*** en paramètre, le problème étant qu'au retour de cette fonction je perd les données pointées par mon char***, voici l exemple:
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    int main() {
        cout << "Start of the program" << endl;
     
        vector<string> vStr = vector<string>();
        vStr.push_back("ABC");
        vStr.push_back("DEF");
        vStr.push_back("GHI");
        vStr.push_back("JKL");
        vStr.push_back("MNO");
        vStr.push_back("PQR");
     
        char*** pStr = new char**();
        int* pLength = new int();
     
        cout << " > before export" << endl;
     
        exportVector(vStr, pStr, pLength);
     
        cout << " < after export" << endl;
     
        cout << "\t pLength value = " << *pLength << endl;
     
        for (unsigned int i = 0 ; i < vStr.size(); i++)
        {
            cout <<"\t pStr "<< i << ": " << vStr[i] << " to ";
            for(unsigned int j = 0; j < 3; ++j)
            {
                cout << "-" << pStr[0][i][j];
            }
            cout << "-"<< endl;
        }
     
        cout << "End of the program" << endl;
     
        delete pStr;
        delete pLength;
     
        return 0;
    }
     
    void exportVector(vector<string> vect, char*** pData, int* pSize)
    {
        vector<char*> charVect = vector<char*>(vect.size());
        //cout << "\t charVect.size() = " << charVect.size() << endl;
     
        // Copy and cast elements of given vector into chars
        for(unsigned int i = 0; i < vect.size() ; i++)
        {
            charVect[i] = const_cast<char*>(vect[i].c_str());
        }
     
        *pData = &charVect[0];
        *pSize = vect.size();
     
        cout << "\t pSize = " << *pSize << endl;
        for (unsigned int i = 0 ; i < vect.size(); i++)
        {
            cout <<"\t pData "<< i << ": ";
            for(unsigned int j = 0 ; j < 3 ; ++j)
            {
                cout << "-" << pData[0][i][j];
            }
            cout << "-"<< endl;
        }
    }
    En executant, on obtient:
    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
    Start of the program
     > before export
         pSize = 6
         pData 0: -A-B-C-
         pData 1: -D-E-F-
         pData 2: -G-H-I-
         pData 3: -J-K-L-
         pData 4: -M-N-O-
         pData 5: -P-Q-R-
     < after export
         pLength value = 6
         pStr 0: ABC to -Ä- -i-
         pStr 1: DEF to - - -i-
         pStr 2: GHI to -G-H-I-
         pStr 3: JKL to -J-K-L-
         pStr 4: MNO to -M-N-O-
         pStr 5: PQR to -P-Q-R-
    End of the program
    Je pense que le problème vient du fait que charVect est local à la fonction et est donc détruit en revenant de celle-ci, si c est bien le cas, comment faire alors?

    Merci de votre aide.

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Convertir un vector<string> en char***, intuitivement, ça fait une étoile de trop (on passe d'un tableau à une dimension de chaînes -- alias, tableau à deux dimensions de caractères -- à un tableau à deux dimensions de chaînées (alias, tableau à trois dimensions de caractères).
    Il y a quelque chose qui cloche, à moins qu'il y ait un passage "par référence" qui se perde.

    Peux-tu donner le prototype de la fonction que tu dois appeler, et sa documentation concernant le paramètre en question?

    À moins que exportVector() soit la fonction que tu dois appeler? Ça me parait improbable, vu que tu lui passes un char*** non-rempli...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 963
    Points
    32 963
    Billets dans le blog
    4
    Par défaut
    Salut,

    je pense que tu as déjà trop de new et trop d'inutiles.
    Et trop de *
    string = char*
    vector = ...*
    vector<string> = char**
    alors pourquoi tu as du char*** ?
    le int de taille, pourquoi l'allouer ?

    export devrait avoir une signature plus proche de export(const std::vector<std::string>& _vec, const char**& _out, int* _outSize)Pour l'utiliser, quelque chose comme ça devrait être bien suffisant et plus simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    std::vector<std::string> monVec;
    // balbla on le peuple
    const char** monTab = NULL;
    int size = 0;
    Export(monVec, monTab, &size);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    void Export(const std::vector<std::string>& _vec, const char**& _out, int* _outSize)
    {
     *_outSize = _vec.size();
     if (_vec.size() == 0)
      return;
     _out = new const char*[_vec.size()];
     for (int i = 0; i < _vec.size(); ++i)
     {
       _out[i] = _vec[i].c_str();
     }
    }
    Attention, ça ne copie pas le contenu des chaînes, donc le contenu de out est totalement dépendant de la durée de vie de monVec.
    Mais ajouter une copie des chaînes n'est pas compliqué, ça ajoute juste de la gestion mémoire plus loin, quand tu en auras fini avec out.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Candidat au Club
    Inscrit en
    Novembre 2013
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Novembre 2013
    Messages : 3
    Points : 2
    Points
    2
    Par défaut
    Le problème est que ce code C++ doit être appelé en C#, voici l'idée:

    Coté C#:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    IntPtr arrayPtr = IntPtr.Zero;
    Int arraySize = 0;
     
    DLL.call_GetData(ref arrayPtr, ref arraySize);
    string[] = Marshall.Copy(arrayPtr, arraySize);
    Coté C++:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void call_GetData(char*** arrayPtr, int* arraySize)
    {
      vector<string> strVec = vector<string>();
        vStr.push_back("ABC");
        vStr.push_back("DEF");
        vStr.push_back("GHI");
        vStr.push_back("JKL");
        vStr.push_back("MNO");
        vStr.push_back("PQR");
     
      exportVector(strVec , arrayPtr, arraySize);
    }
    Ainsi, comment implémenter la fonction exportVector ayant le prototype suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void exportVector(vector<string> vect, char*** pData, int* pSize)

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Ça ne marchera jamais comme ça, tu auras des problèmes pour désallouer etc.

    Le plus sûr pour convertir des tableaux et des strings en C#, c'est le SAFEARRAY de BSTR.

    Par contre, pour faire une BSTR à partir de caractères "étroits", ce n'est pas trivial:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    BSTR SysAllocStringA(const char *strA)
    {
    	int cchBufferSize = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0);
    	if(cchBufferSize <= 0)
    		return NULL;
    	BSTR ret = SysAllocStringLen(NUL, cchBufferSize);
    	if(ret == NULL)
    		return NULL;
    	MultiByteToWideChar(CP_ACP, 0, strA, -1, ret, cchBufferSize);
    	return ret;
    }
    Fort de cette fonction, tu peux allouer un SAFEARRAY de BSTR, et préciser à C# comment on s'en sert avec l'attribut MarshalAs.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    En gros, le code C++ devrait ressembler à ça
    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    SAFEARRAY* StringVectorToSafeArray(vector<string> const &strVec)
    {
    	SAFEARRAY* pArray = SafeArrayCreateVector(VT_BSTR, 0, strVec.size();
    	if(pArray==NULL)
    		return NULL;
     
    	for(int i=0 ; i<strVec.size() ; i++)
    	{
    		BSTR bs = SysAllocStringA(strVec[i].c_str());
    		LONG index = i;
    		SafeArrayPutElement(pArray, &i, bs);
    		//Note: SafeArrayPutElement ne s'approprie pas la chaîne, mais la copie
    		// http://stackoverflow.com/questions/1456400/#comment1326897_1456400
    		SysFreeString(bs);
    	}
    	return pArray;
    }
     
    extern "C" __declspec(dllexport) void call_GetData(SAFEARRAY** arrayPtr)
    {
    	vector<string> strVec = vector<string>();
    	vStr.push_back("ABC");
    	vStr.push_back("DEF");
    	vStr.push_back("GHI");
    	vStr.push_back("JKL");
    	vStr.push_back("MNO");
    	vStr.push_back("PQR");
     
    	*arrayPtr = StringVectorToSafeArray(vStr);
    }
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    static class DLL
    {
    	[DllImport("dvp.dll", EntryPoint = "call_GetData", CallingConvention =  CallingConvention.Cdecl)]
    	public static extern void call_GetData(
    		[Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR)] out string[] strArray
    	);
    }
     
    ...
     
    string[] strArray;
    DLL.call_GetData(out strArray);
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Candidat au Club
    Inscrit en
    Novembre 2013
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Novembre 2013
    Messages : 3
    Points : 2
    Points
    2
    Par défaut
    Merci beaucoup, cela fonctionne à merveille, merci encore.

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

Discussions similaires

  1. Réponses: 12
    Dernier message: 26/01/2008, 20h23
  2. Pointeur et passage par adresse
    Par turbo_chess dans le forum C
    Réponses: 9
    Dernier message: 07/09/2007, 13h38
  3. Passage par valeur / passage par adresse
    Par jeje99 dans le forum C++
    Réponses: 13
    Dernier message: 16/02/2006, 10h29
  4. passage par adresse
    Par cari dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 01/02/2006, 11h33
  5. [Debutant(e)]passage par adresse?
    Par cap2fosse dans le forum Langage
    Réponses: 4
    Dernier message: 24/09/2004, 10h05

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