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 :

Passer un char** par référence


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé Avatar de Nightmare Theater
    Homme Profil pro
    Ingénieur après-vente
    Inscrit en
    Juin 2007
    Messages
    127
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Ingénieur après-vente
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 127
    Par défaut Passer un char** par référence
    Bonjour,

    J'essaie en ce moment d'écrire une DLL pour faire divers tests - notamment sur le passage d'arguments par référence. Sur des valeurs numériques, ca fonctionne parfaitement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    extern "C" int __stdcall fonctionDivision (float& dz1, float& dz2)
    {
       dz1 = dz1/2;
       dz2 = dz2/2;
       RETURN 1,
    }
    les changements appliqués à dz1 et dz2 sont bien passés à la variable utilisé comme argument.

    J'ai commencé à avoir mon premier problème avec un char*... Du moins jusqu'à ce que je réalise qu'il ma fallait utiliser strcpy(); pour que les chqngements sur l'argument soient pris en compte lors de l'appel de la fonction.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    extern "C" int __stdcall HelloWorld (char* Hello)
    {	
    	strcpy(Hello, "HelloWorld");
    	return 1; 
    }
    Jusqu'ici tout va bien.

    Les vrais soucis commencent depuis que j'essaie de passer un char**.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    extern "C" int __stdcall StringArray (char** Array)
    {
    	char* temp[5];
    	temp[0] = "Demo Tool";
    	temp[1] = " ";
    	temp[2] = "v1";
    	temp[3] = "r2.504";
    	Array = temp;
    	return 1;
    }
    Bien entendu, dans le code ci-dessus, aucun changement n'est pris en compte et si je lis la variable donnée en argument après l'appel de la fonction, elle est identique à son état précédent cet appel. Strcpy ne fonctionne pas non plus. J'ai essayé strcpy(*Array, temp[0]); mais je me retrouve avec une chaine aléatoire de caractères en sortie.

    Quekqu'un squrqit-il m'expliquer comment construire mq fonction pour que la valeur char** Array soit passée à la variable utilisée pour l'appel de la fonction?

    Merci d'avance

  2. #2
    Membre Expert
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2011
    Messages
    1 255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2011
    Messages : 1 255
    Par défaut
    Je crois que tu as compris que temp est déclaré localement, donc une affectation Array = temp ne marche que lorsque tu es dans la fonction. Vu que temp est déclaré localement, donc dans la pile de la fonction, lorsque tu sors de celle-ci, la pile "disparait" et donc les données à l'ancienne adresse de temp ne sont plus viables.

    Par contre, ton souci strcpy me surprend.

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 60
    Par défaut
    Comment déclares-tu ton char** Array avant l'appel de la fonction ?
    Est ce un tableau statique char Array[][] ? Ne déclares-tu pas un tableau trop petit ?

    Ou est il déclaré comme un char ** ? Alloues-tu suffisamment de mémoire avec malloc ?

  4. #4
    Membre éprouvé Avatar de Nightmare Theater
    Homme Profil pro
    Ingénieur après-vente
    Inscrit en
    Juin 2007
    Messages
    127
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Ingénieur après-vente
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 127
    Par défaut
    @mala952: oui, j'ai bien compris le fait que la déclaration locale de temp fait que celui ci disparrait apres l'appel de la fonction. J'ai juste laissé Array = temp; dans l'exemple pour illustrer le fait que je cherche à passer le contenu de temps dans Array. Toutefois, merci d'avoir pris la peine de re-clarifier ce point

    Citation Envoyé par DeathMixer Voir le message
    Comment déclares-tu ton char** Array avent l'appel de la fonction ?
    Est ce un tableau statique char Array[][] ? Ne déclare-stu pas un tableau trop petit ?

    Ou est il déclaré comme un char ** ? Alloues-tu suffisamment de mémoire avec malloc ?
    DeathMixer: J'appelle la fonction depuis LabVIEW, ce qui rend la déclaration un peu différente. Je décrale un tableau de U8 (unsigned 8 bit integer) de 200 élément (ou 4*50, les deux donnant le même résultat). Je récupère ensuis de tableau de U8 que je trqduis en cqrqctères ASCII. Ca fonctionne sans souci avec ma fonction HelloWorld(); . Lá, que mon tqblequ qit une ou deux dimensions, le résultat est aux fraises.

    J'ai aussi fait quelques tqtonnements (qllouer un espqce mémoire pour Array dans la fonction (char ** Array = (char**)malloc(200)) et employer la methode brutale (memmove(Array, temp, 200) mais je me trouve quand même avec une chaine de caractère étrange en sortie("lUÝjhUÝjdUÝj\") qui me fqit pensé qu'il me retrourne juste des adresses mémoires (3*32bits).

    J'ai aussi essayé strcpy(Array[0], temp[0]); mais quelque soit l'adresse mémoire alloué, il me renvoi une erreur de mémoire insuffisante.

    Bref, je tâtonne. Il est aussi possible que l'erreur vienne de mon appel sous labVIEW, j'explore les deux pistes en parallèle. Cependant, je pense qu'une fois que je suis sûr qure mq fonction est bien écrite en C, il est plus simple de me concentrer sur l'appel de ladite fonction.

    Merci à vous deux

  5. #5
    Membre Expert
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2011
    Messages
    1 255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2011
    Messages : 1 255
    Par défaut
    Tu as alloué un tableau de pointeurs de 200 pointeurs.
    Ton souci c'est que tu n'as pas alloué la zone mémoire de ces 200 pointeurs.
    Ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	char **p;
    	p = (char**)malloc(10);
    	for(int i = 0; i < 10; i++)
    		p[i] = (char*)malloc(100);

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 60
    Par défaut
    L'exemple d'allocation que tu as mis est complètement faux !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char ** Array = (char**)malloc(200)
    Dans une telle déclaration, tu déclares Array comme un tableau à deux dimensions, autrement dit un pointeur de pointeurs vers des caractères.
    Alors que l'allocation que tu fais, alloues 200 octets, mais va considérer ces 200 octets comme un tableau de pointeurs !!! Si tu es sur une machine 32 bits, les pointeurs seront sur 4 octets, donc en faisant Array[0], tu vas récupérer les 4 premiers octets qui vont former une adresse, qui sera très certainement indéterminée !!

    Pour allouer correctement un tableau à deux dimensions, il faut faire comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char ** Array = (char **) malloc(4 * sizeof(char*));
    for (int i = 0; i < 4; i++){
        Array[i] = (char*) malloc(50 * sizeof(char));
    }
    De cette manière tu déclareras un tableau à deux dimensions de taille 4*50.

    Autrement dit, tu déclareras un tableau de 4 chaines de caractères, de 50 caractères chacune...

  7. #7
    Membre éprouvé Avatar de Nightmare Theater
    Homme Profil pro
    Ingénieur après-vente
    Inscrit en
    Juin 2007
    Messages
    127
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Ingénieur après-vente
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 127
    Par défaut
    Ach sooooooooooo.

    J'essaie ca de suite et vous tient au courrant, mais ca pourrait expliquer beaucoup de chose

  8. #8
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    - Ceci n'est pas du C : il n'y a pas de référence en C

    -
    J'ai juste laissé Array = temp;
    1- cela ne copie pas le tableau temp mais ne fait que modifier la variable locale Array
    2- et faire *Array = temp reviendrait à renvoyer l'adresse d'une variable locale ce qui est dans tous les cas une erreur

    -
    Je décrale un tableau de U8 (unsigned 8 bit integer) de 200 élément (ou 4*50, les deux donnant le même résultat).
    Dans ce cas, le type du paramètre ne peut pas être char**, mais U8* (ou U8 (*)[50] pour 4*50)

    -
    employer la methode brutale (memmove(Array, temp, 200) mais je me trouve quand même avec une chaine de caractère étrange en sortie("lUÝjhUÝjdUÝj\") qui me fqit pensé qu'il me retrourne juste des adresses mémoires (3*32bits).
    C'est normal, temp est un tableau d'adresses et tu copies ces adresses

    -
    J'ai aussi essayé strcpy(Array[0], temp[0]); mais quelque soit l'adresse mémoire alloué, il me renvoi une erreur de mémoire insuffisante.
    Là, tu copies bien la première chaine mais où ? à l'adresse contenue dans Array[0] et on revient à : comment as-tu déclaré et créé la variable utilisée lors de l'appel ?

    Tout ça est trop brouillon. La première chose à faire est de préciser l'interface et le fonctionnement de la fonction : je communique à la fonction quelles informations précisément (type des arguments, comment les arguments seront-ils créés ?), ce qu'elle fait et ce qu'elle renvoie.

  9. #9
    Membre éprouvé Avatar de Nightmare Theater
    Homme Profil pro
    Ingénieur après-vente
    Inscrit en
    Juin 2007
    Messages
    127
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Ingénieur après-vente
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 127
    Par défaut
    Citation Envoyé par diogene Voir le message
    -
    1- cela ne copie pas le tableau temp mais ne fait que modifier la variable locale Array
    2- et faire *Array = temp reviendrait à renvoyer l'adresse d'une variable locale ce qui est dans tous les cas une erreur
    Ce point est clair depuis le début. Mais merci de la précision.


    Citation Envoyé par diogene Voir le message
    - Dans ce cas, le type du paramètre ne peut pas être char**, mais U8* (ou U8 (*)[50] pour 4*50)
    Mon but est d'étudier l'utilisation de char** sous labVIEW. C'est pour ca que je souhaite avoir une fonction simple dans un DLL. Ce que la fonction fait n'a en soit pas beaucoup d'importance, mais il est important que je m'assure qu'elle est correctement programmée avant de chercher un moyen de l'utiliser sous labVIEW. En l'état, je ne sais pas si l'erreur viens de ma programmation en C ou de mon appel sous LabVIEW. A partir du moment où il est admis que la fonction "devrait fonctionner", je laisse le C de coté pour me concentrer sur l'appel sous LabVIEW.

    Citation Envoyé par diogene Voir le message
    C'est normal, temp est un tableau d'adresses et tu copies ces adresses
    Merci, je n'avais pas compris cette fonction de cette manière.

    Citation Envoyé par diogene Voir le message
    Là, tu copies bien la première chaine mais où ? à l'adresse contenue dans Array[0] et on revient à : comment as-tu déclaré et créé la variable utilisée lors de l'appel ?
    Je réserve un tableau de 4*50 octets qui sont compris par la DLL comme des caracteres ASCII.

    Citation Envoyé par diogene Voir le message
    Tout ça est trop brouillon. La première chose à faire est de préciser l'interface et le fonctionnement de la fonction : je communique à la fonction quelles informations précisément (type des arguments, comment les arguments seront-ils créés ?), ce qu'elle fait et ce qu'elle renvoie.
    L'idée est de communiquer un char** (peu importe qu'il soit vide ou plein) et que la DLL en change la valeur (dans mon essai, je donne en argument 4*50 espaces et attend en sortie au moins la chaine de caractére "Demo Tool".

    Comme dit précédement, j'etudie l'appel de fonctions utilisant char** comme argument sous labVIEW. Ce que la fonction fait m'est - au final - égal. Ecrire 4 chaines de caractéres me semblait etre une fonction suffisemment simple pour mon test.

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 60
    Par défaut
    Ton souci c'est que tu n'as pas alloué la zone mémoire de ces 200 pointeurs.
    Ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     
    	char **p;
    	p = (char**)malloc(10);
    	for(int i = 0; i < 10; i++)
    		p[i] = (char*)malloc(100);
    Attention !! Tu alloues 10 octets pour ton char** p !! Et non la mémoire nécessaire pour 10 pointeurs !! Pour ce faire, il faut écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    char ** p = (char **) malloc(10 * sizeof(char *));
    //...

  11. #11
    Membre Expert
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2011
    Messages
    1 255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2011
    Messages : 1 255
    Par défaut
    Citation Envoyé par DeathMixer Voir le message
    Attention !! Tu alloues 10 octets pour ton char** p !! Et non la mémoire nécessaire pour 10 pointeurs !! Pour ce faire, il faut écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    char ** p = (char **) malloc(10 * sizeof(char *));
    //...
    Oui, désolé, j'ai fait mon test comme un porc.

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

Discussions similaires

  1. Réponses: 9
    Dernier message: 09/12/2010, 16h33
  2. [PowerShell] Comment passer une string "par référence" dans une fonction ?
    Par Plageman dans le forum Scripts/Batch
    Réponses: 7
    Dernier message: 11/11/2010, 15h01
  3. Est-il possible de passer des paramètres par référence en VB 6 ?
    Par beegees dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 21/09/2008, 14h02
  4. passer une variable par référence
    Par roblescriso dans le forum Requêtes et SQL.
    Réponses: 0
    Dernier message: 04/04/2008, 17h05
  5. [JACOB] Comment passer un objet par référence à une méthode
    Par zlavock dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 21/03/2005, 18h28

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