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 :

J'aimerais comprendre ....


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 73
    Points : 41
    Points
    41
    Par défaut J'aimerais comprendre ....
    Bonjour,

    ayant besoin de recuperer les lecteurs "actifs" sous windows, j'ai récupéré ce code sur le net.
    Il fonctionne.

    Cependant je souhaiterais aussi le comprendre (afin de re-utiliser ou modifier).

    J'ai mis les commentaires qui me semblais juste mais je ne comprends pas vraiment la globalité. Comment fonctionne cette boucle ?

    Si quelqu'un peut eclairer un peu ma lanterne...j'en serais ravi.

    Merci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    char szBuffer[1024]; 						//initialisation de la taille du buffer (Nb de caracteres = 2 octets par caracteres)
    GetLogicalDriveStrings(1024, szBuffer);		//appel de l'API windows (taille du Buffer,variable recevant les données)
    char *pch = szBuffer;						//definition du pointeur pour acceder aux éléments du tableau
    while (*pch) {  							//tant que....???
    printf("%s\n", pch);						//affiche la valeur de PCH convertion type char (chaine)
    pch = &pch[strlen(pch) + 1];				//nouvelle valeur PCH (prend la valeur du contnu du pointeur PCH ) = longueur de chaine PCH+1 a chaque boucle
    }

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    94
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 94
    Points : 82
    Points
    82
    Par défaut
    [Je pense ne pas me tromper, mais s'il y a des membres plus expérimentés qui veulent me rectifier, qu'ils n'hésitent pas ]

    Voici une explication ligne par ligne :

    char szBuffer[1024];
    Ceci est suffisamment explicite, je pense ...

    GetLogicalDriveStrings(1024, szBuffer);
    Cette fonction, d'après ce que j'ai compris, stocke les lettres des lecteurs (je suppose C:, D: etc...) dans le tableau de caractères fourni. Elle ajoute un caractère nul (\0) à la fin de chaque lecteur. Ceci est essentiel pour la suite.

    char *pch = szBuffer;
    C'est une transformation de tableau en pointeur - exemple typique. Le pointeur est donc dirigé sur le premier caractère du tableau, et surtout on ne connaît plus la taille de ce dernier ! Ce qui va permettre au travers des manipulations qui suivent, de tromper les fonctions printf et strlen ...

    while (*pch) {
    Le début de la boucle. Tant que pch pointe sur un emplacement valide, c'est-à-dire que le caractère pointé n'est pas nul -> explications plus tard.

    printf("%s\n", pch);
    Ici, on affiche une chaîne de caractères. Une chaîne étant définie comme terminée par un caractère nul, la fonction est trompée par le caractère nul d'espacement qu'insère GetLogicalDriveStrings entre la lettre de chacun des lecteurs. Ceci permettant de pouvoir enregistrer tous les lecteurs sans avoir besoin d'un tableau à 2 dimensions, peu pratique à manipuler en utilisant tableaux et pointeurs C.

    pch = &pch[strlen(pch) + 1];
    C'est la ligne clé de la boucle. On déplace le pointeur pch, le but de la manipulation étant qu'il pointe sur le lecteur suivant.
    Pour effectuer ceci, on dispose de deux informations à exploiter :
    1. La taille d'un nom de lecteur, à savoir 2 caractères (cette information va néanmoins être récupérée dynamiquement avec strlen)
    2. On sait qu'un caractère nul sépare chaque nom de lecteur
    En utilisant strlen, on tombe sur 2, puisque cette fonction, comme printf, s'arrête au premier caractère nul. On ajoute ensuite 1 à cette longueur pour passer outre le caractère nul.
    Cela fait avancer le pointeur de 3 caractères ... on se retrouve sur la première lettre du lecteur suivant, dont aucune des fonctions C ne soupçonnait l'existence !!

    } // la fin de la boucle
    Expliquons en quoi la condition *pch fonctionne : sur les systèmes Windows, on est limité à 26 lecteurs (autant que de lettres). Au maximum, cela fait donc 26 * (2 caractères + 1 nul) = 26*3 = 78 caractères. La quantité allouée, 1024 caractères, garantit donc qu'il restera des caractères nuls en fin de chaîne. Arrivé au dernier lecteur, l'itération se poursuit mais tombe sur un caractère nul. Cette valeur correspondant à 0, la boucle se termine.

    Voilà, j'espère que tu as apprécié mon roman
    C'était un petit peu long, mais je pense que j'ai tout dit ....

    Enjoy C++ & Qt
    Kwakanar

  3. #3
    Membre averti
    Avatar de Strab
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 338
    Points : 330
    Points
    330
    Par défaut
    Tout d'abord, un caractère (ASCII) ne fait pas 2 octets mais un seulement.

    Cette boucle imprime à l'écran toutes les chaines de caractères contenues dans le buffer, une chaine de caractère étant une suite d'octets suivie du caractère '\0'.
    La boucle se termine à la première chaine vide, c.a.d. dès qu'elle rencontre dans le buffer deux '\0' consécutifs (ou un seul si c'est le premier octet du buffer).

    Ca va mieux ?

  4. #4
    Membre averti
    Avatar de Strab
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 338
    Points : 330
    Points
    330
    Par défaut
    Bon en fait, kwakanar m'a devancé d'une minute

    Ce n'est pas plus mal, car son explication est beaucoup plus complète. Néanmoins, j'aimerais apporter une rectification.

    Citation Envoyé par kwakanar
    char *pch = szBuffer;
    C'est une transformation de tableau en pointeur - exemple typique. Le pointeur est donc dirigé sur le premier caractère du tableau, et surtout on ne connaît plus la taille de ce dernier ! Ce qui va permettre au travers des manipulations qui suivent, de tromper les fonctions printf et strlen ...
    En fait, on a autant d'informations sur la taille de pch que sur celle szBuffer, puisqu'ils ont la même valeur ! Il ne s'agit pas d'une transformation, il faut bien comprendre que pointeur et tableau c'est exactement la même chose.
    Déclarer un tableau, c'est déclarer un pointeur et lui allouer en même temps une certaine quantité de mémoire.

    Donc ces deux instructions sont équivalentes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    char szBuffer[1024];
    char * pch = (char *) malloc(1024 * sizeof(char); //Version C
    char * pch = new char[1024]; //Version C++
    On remarque d'ailleurs la similitude des déclaration en C++.

    Et ce qu'on appelle la taille d'un tableau, c'est la mémoire qui lui a été allouée, et on ne la connait que si on a écrit nous même la déclaration/allocation ou si elle est dans une variable, sinon on a aucun moyen d'y avoir accès.


    Et puis, je n'aime pas trop l'utilisation de l'expression "tromper les fonctions". Tu ne les trompes pas, elles font exactement ce qu'elles sont censés faire : compter le nombre d'octets précédant '\0'. Mais bon, ça c'est une histoire d'appellation, si tu préfères penser que tu les as trompées... libre à toi de le faire.

    Voilà, j'espère que les précision apportées sont utiles (et justes !).
    Strab

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    94
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 94
    Points : 82
    Points
    82
    Par défaut
    "Tout d'abord, un caractère (ASCII) ne fait pas 2 octets mais un seulement. "

    Je crois qu'il y a le " : " qui suit la lettre du lecteur (c'est pas C mais C: pour le disque dur) ??

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 73
    Points : 41
    Points
    41
    Par défaut
    whouaou !!

    vraiment tres sympa !!

    en fait le format de sortie est :
    A:\
    C:\
    etc...

    il me semblait avoir compris que un caractere faisait 2 octets et 1 pour le reste.

    bref

    merci encore c'etait un plaisir de vous lire !!

  7. #7
    Membre éclairé
    Homme Profil pro
    Consultant ERP
    Inscrit en
    Février 2004
    Messages
    644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant ERP

    Informations forums :
    Inscription : Février 2004
    Messages : 644
    Points : 785
    Points
    785
    Par défaut
    Vérifie tout de même que le tableau est initialisé avec des caractères nuls, sinon, tu va direct au crash.
    Nul ne peut mieux connaitre la connaissance qu'elle-même.

  8. #8
    Membre averti
    Avatar de Strab
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 338
    Points : 330
    Points
    330
    Par défaut
    Citation Envoyé par kwakanar
    Je crois qu'il y a le " : " qui suit la lettre du lecteur (c'est pas C mais C: pour le disque dur) ??
    Oui, un nom de lecteur fait 2 caractères (voire trois apparemment), mais un caractère fait un octet. Son buffer fait 1024 caractères, donc 1024 octets, mais 1024 / 3 ~= 340 lecteurs.

    Citation Envoyé par barbarello
    il me semblait avoir compris que un caractere faisait 2 octets et 1 pour le reste.
    Pas du tout en fait. Pour les types les plus courants, sur une machine 32 bits :
    char = 1 octet
    short = 2 octets
    int = 4 octets
    long = 8 octets
    pointeur = 4 octets
    Pour les nombres flottants, je ne suis pas sûr mais je crois que c'est :
    float = 4 octets
    double = 8 octets

    Désolé si je n'avais pas été clair.
    Strab

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    94
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 94
    Points : 82
    Points
    82
    Par défaut
    Ah tiens, à propos (je viens d'y penser ) ...

    Ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pch = &pch[strlen(pch) + 1];
    peut s'écrire plus joliment comme ça il me semble :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pch += strlen(pch) + 1;
    Ce qui pait davantage ressortir le fait qu'on décale le pointeur de quelques octets vers la droite.

    Voilou ...

  10. #10
    Membre averti
    Avatar de Strab
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 338
    Points : 330
    Points
    330
    Par défaut
    Très juste.

    J'en profite pour rappeler barbarello de penser à cliquer sur le bouton résolu si les réponses qu'il a obtenues le satisfont.

    Strab

  11. #11
    Membre éclairé Avatar de reggae
    Profil pro
    Inscrit en
    Août 2005
    Messages
    773
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Août 2005
    Messages : 773
    Points : 795
    Points
    795
    Par défaut
    while (*pch) {
    Le début de la boucle. Tant que pch pointe sur un emplacement valide, c'est-à-dire que le caractère pointé n'est pas nul -> explications plus tard.
    ou bien encore que l'objet qui est pointé par pch contient la valeur true non?

  12. #12
    Membre éclairé
    Homme Profil pro
    Consultant ERP
    Inscrit en
    Février 2004
    Messages
    644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant ERP

    Informations forums :
    Inscription : Février 2004
    Messages : 644
    Points : 785
    Points
    785
    Par défaut
    Toute valeur différente de 0 est équivalent à true.

    #define FALSE 0
    #define TRUE !FALSE
    Nul ne peut mieux connaitre la connaissance qu'elle-même.

  13. #13
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 73
    Points : 41
    Points
    41
    Par défaut
    C'est bien evidement RESOLU merci encore de votre aide.

    Je n'ai plus qu'a trouver ce bouton RESOLU !

    Merci

  14. #14
    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 519
    Points
    41 519
    Par défaut
    strab: tu t'es gouré, un long fait 4 octets sur une machine 32 bits (comme un int).
    C'est le long long qui en fait 8...
    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.

  15. #15
    Membre éclairé
    Homme Profil pro
    Consultant ERP
    Inscrit en
    Février 2004
    Messages
    644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant ERP

    Informations forums :
    Inscription : Février 2004
    Messages : 644
    Points : 785
    Points
    785
    Par défaut
    Tout à la fin du thread, tu devrais avoir un bouton "RESOLU".
    Nul ne peut mieux connaitre la connaissance qu'elle-même.

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

Discussions similaires

  1. [AC-2010] ODBC : USER DSN VS SYSTEM DSN, j'aimerais comprendre.
    Par Geache dans le forum Access
    Réponses: 3
    Dernier message: 18/12/2013, 09h47
  2. J'aimerais comprendre pourquoi ça ne fonctionne pas
    Par JamesBond002 dans le forum Débuter avec Java
    Réponses: 13
    Dernier message: 28/05/2013, 15h49
  3. J'aimerai comprendre ce qu'est VPN
    Par andrianiaina dans le forum Hardware
    Réponses: 2
    Dernier message: 02/10/2010, 08h12
  4. J'aimerais comprendre ces messages
    Par BuzzLeclaire dans le forum Débuter
    Réponses: 4
    Dernier message: 16/10/2008, 13h46
  5. [Procédure][java] A n'y rien comprendre
    Par Stessy dans le forum SQL
    Réponses: 2
    Dernier message: 18/03/2004, 15h05

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