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 :

Problème de compréhension de scanf


Sujet :

C

  1. #1
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    167
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 167
    Par défaut Problème de compréhension de scanf
    Bonjour,

    Alors voila j'ai une question très simple et je n'arrive pas à trouver de réponse convaincante:

    dans cet exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    long age = 0;
     
    scanf("Veuillez entrer un nombre %ld", &age):
    Pourquoi faut-il fournir l'adresse de la variable "age", pourquoi faut-il le faire précéder du signe '&' ?

    Cela me gêne parce que par exemple pour fgets nous n'avons pas besoin de fournir d'adresse :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fgets(chaine, TAILLE_MAX, fichier);
    Ici on lit maximum TAILLE_MAX caractères du fichier et on stocke le tout dans "chaine" sans pour autant fournir l'adresse de "chaine".

    Dans beaucoup de situation on ne fournit pas d'adresse et je trouve ça logique car j'interprète cela comme une affectation.

    J'ai lu que ce '&' est nécessaire pour pouvoir ranger correctement l'information dans "age" mais je ne considère pas ça comme une réponse suffisante, car dans ce cas là, la morale est qu'il faut l'utiliser partout...

    Voila donc si quelqu'un pouvait m'expliquer l'intérêt de fournir l'adresse à scanf, ça ferait un peu d'ordre à toutes les questions que je me pose.

    Merci d'avance !

    Raiden.

  2. #2
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Raiden1234 Voir le message
    Alors voila j'ai une question très simple et je n'arrive pas à trouver de réponse convaincante:

    dans cet exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    long age = 0;
     
    scanf("Veuillez entrer un nombre %ld", &age):
    Pourquoi faut-il fournir l'adresse de la variable "age", pourquoi faut-il le faire précéder du signe '&' ?
    Parce que scanf() va écrire le résultat de la conversion dans age. Il n'y a pas d'autre choix que de passer l'adresse de la variable de destination.

    http://emmanuel-delahaye.developpez....difie_variable



    Cela me gêne parce que par exemple pour fgets nous n'avons pas besoin de fournir d'adresse :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fgets(chaine, TAILLE_MAX, fichier);
    Ben si. chaine est une adresse.

    chaine est un tableau de char. L'adresse de son premier élément est donc &chaine[0], ce qui s'écrit aussi chaine + 0, donc chaine.

    Ce qu'on passe à fgets() est donc l'adresse du premier élément de chaine. Comme c'est un char, on passe l'adresse de ce char dans un pointeur sur char (char *).

    Dans beaucoup de situation on ne fournit pas d'adresse
    Attention, c'est pas ce qu'il n'y a pas de '&' que ce n'est pas une adresse. Tout dépend de la nature de ce qu'on passe en paramètre.

    J'ai lu que ce '&' est nécessaire pour pouvoir ranger correctement l'information dans "age"
    Oui, parce que age est int, et que scanf() avec %d veut l'adresse d'un int. Donc, on met le & pour avoir l'adresse de cet int. Si on avait eu un pointeur sur int (int*), on n'aurait pas le & (faute grave, sinon !).

    mais je ne considère pas ça comme une réponse suffisante, car dans ce cas là, la morale est qu'il faut l'utiliser partout...
    ce qui n'est pas vrai comme tu le sais maintenant. ce qu'il faut toujours avec scanf(), c'est une adresse. La manière de l'obtenir dépend du contexte.

  3. #3
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    scanf va analyser les caractères saisis au clavier. Il s'attend à ce que les données fournies analysées respecte le format du 1er paramètre.

    En lisant ce 1er paramètre, il s'apercoit qui faut qu'il extraie un nombre (%ld). Une fois que ce nombre est extrait, il faut le ranger quelque part, et ce quelque part, c'est en mémoire, à une certaine adresse fournie pas le programme.

    C'est donc le deuxième paramètre, l'adresse de la variable dans laquelle stocker le nombre extrait.

    Quant à ton 2eme exemple, c'est un petit peu différent
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fgets(chaine, TAILLE_MAX, fichier);
    En effet, chaine est un tableau de caractères (je suppose car je n'ai pas tout le code). En C, un tableau est une adresse et même l'adresse du premier élément du tableau.
    Donc effectivement, on valire le fichier et mettre ce qu'on a lu dans le tableau 'chaine' dont l'adresse de début est 'chaine'.

    C'est un concept un peu délicat à saisir au début du C, un tableau est une adresse.
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  4. #4
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par ram-0000 Voir le message
    C'est un concept un peu délicat à saisir au début du C, un tableau est une adresse.
    Surtout que c'est le 'nom du tableau' et non le tableau lui même qui est une adresse (celle du premier élément du tableau). Il en a la valeur et surtout le type.

    C'est pour ça que sizeof tableau <> sizeof *tableau ...

    Dans le premier cas 'tableau' désigne une variable en mémoire nommé tableau'
    Dans le 2 ème cas, 'tableau' désigne une valeur constante (adresse du premier élément du tableau).

    Les tableaux C sont la chose plus difficile à expliquer de ce langage...

  5. #5
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Surtout que c'est le 'nom du tableau' et non le tableau lui même qui est une adresse.
    Yes sir, c'est plus correct et juste de le dire comme cela
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  6. #6
    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
    Pour résumer :

    Le nom du tableau représente :

    - le tableau lui-même lorsqu'il est associé à l'opérateur unaire & ou à l'opérateur sizeof ;

    - l'adresse du premier élément du tableau (élément pouvant lui-même être un tableau) dans tous les autres cas.

  7. #7
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    Citation Envoyé par Raiden1234 Voir le message
    Pourquoi faut-il fournir l'adresse de la variable "age", pourquoi faut-il le faire précéder du signe '&' ?
    Parce que si tu mets « age » tout seul, c'est le contenu (la valeur) de « age » qui va être transmis à la fonction, ce dont elle n'a rien à faire.

    Pour être plus précis, si une fonction produit une nouvelle valeur, c'est en général la fonction elle-même qui prend cette valeur, c'est-à-dire qu'elle la transmet au porgramme appelant en la renvoyant en tant que code de retour. Mais si tu as plusieurs valeurs à retourner et que tu ne peux pas utiliser une structure pour toutes les renvoyer ensemble, tu es obligé de dire à l'avance, à la fonction, à quel endroit elle doit les mettre. Et le mieux, c'est encore d'aller la stocker directement dans les variables qui doivent les recevoir. Donc, tu passes l'adresse de chacune des variables.

    Cela me gêne parce que par exemple pour fgets nous n'avons pas besoin de fournir d'adresse :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fgets(chaine, TAILLE_MAX, fichier);
    Ici on lit maximum TAILLE_MAX caractères du fichier et on stocke le tout dans "chaine" sans pour autant fournir l'adresse de "chaine".
    Non, parce que « chaine » n'est pas un type de donnée à part entière mais une « chaines d'éléments de type xxxxx ». Tu peux donc avoir une chaîne d'entiers (int), une chaîne de caractères (char), ou même une chaîne de structures ... Tous ces éléments étant stockés consécutivement en mémoire, on te file en plus un pointeur qui contient l'adresse du premier élément (donc le début de la chaîne).

    C'est donc bien, ici, le contenu de « chaine » (soit l'adresse de la chaîne) qui nous intéresse, et pas l'adresse du pointeur lui-même.



    C'est une question importante parce que beaucoup de débutants lachent le C à cause de ce problème d'approche : le C est adapté à la production de programmes en langage machine. Or, même si la gestion proprement dite de la mémoire n'est pas forcément l'objectif final du programmeur, il faudra bien qu'en bout de processus, ce travail soit fait ... et il faut donc un langage pour exprimer cela.

    Après, comme ce n'est pas plus compliqué de taper « &x » que « x », autant connaître directement le fonctionnement de la machine que l'on utilise et éviter d'impliquer des couches intermédiaires pour faire la traduction et qui coûtent des ressources au run-time.

    Cependant, la notion de référence a été introduite en C++ et dans d'autres langages à ces fins (pouvoir désigner la variable elle-même sans avoir à manipuler explicitement son adresse).

  8. #8
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    167
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 167
    Par défaut
    Bonsoir à vous !

    Je vous remercie beaucoup pour vos explications très complètes.

    Tout ceci me semble logique maintenant: si j'ai x=2, le fait de fournir 'x' dans une fonction serait comme lui fournir ici '2'.

    Pour ce qui en ai de "chaine" que j'ai cité au dessus, j'aurais du y penser mais c'est de type char* donc pointeur sur chaine de caractères et ce pointeur pointe déjà sur une adresse .

    Je pense que c'est en effet, en voulant faire un rapprochement avec des langages objets tel que C++ ou Java, où nous utiliserions (dîtes le moi si je me trompe) simplement un nom de variable pour fournir de façon sous entendu une "adresse" ou plutôt devrais-je dire une référence au programme, que je me suis mélangé les ménages et que j'ai eu ce méchant doute sur scanf.

    Voila, je vous remercie beaucoup c'est en effet un point sur lequel on peut vite passer à côté, je viens de m'en rendre compte.

  9. #9
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Romaric Okemba Voir le message
    Raiden bsr ,je te rappelle que ecrire un programme signifie tantot l'écrire en partie ou en totalité pourquoi en partie ,parceque dans certains langages de programmation comme le c certains fonctions sont deja écrits par les concepteurs du langage ,donc il sera plus aisé pour nous de suivre ce que exige les syntaxes exigées par les concepteurs mais un peu de comprehension scanf est une fonction dont le role est de ranger une valeur lue au clavier dans un espace mémoire ( variable ) pour cela il lui faut fournir l'adresse de la dite variable d'ou la présence de "&" devant la variable,or la mémoire centrale est 1 ensemble d'octets et ne comprend que du binaire c'est a dire 1 ou 0,tout ce que nous écrivons est convertit en 0 ou 1 donc une valeur d'une variable quel k soit son type est réprésente en 0 ou 1 pour distinguer les caracteres et les numériques il faut le preciser d'ou le format %d sinon comment l'ordi saura distinguer les nombres aux caracteres
    plus d'info
    si y ,w,z sont de type entieren ecrivant:
    y=scanf("%d%d",&w,&z);
    y prendra 2 quand l'utilisateur aura fournit exactement 2 valeurs
    cette methode te sera peut etre utile pour certains controles de saisie je crois k j'ai fait de mon mieux merci.
    Tu devrais supprimer ce point ...^

  10. #10
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Raiden1234 Voir le message
    Tout ceci me semble logique maintenant: si j'ai x=2, le fait de fournir 'x' dans une fonction serait comme lui fournir ici '2'.
    Oui, c'est ce qu'on appelle un passage de paramètre par valeur ou par copie (le seul possible en C).
    Pour ce qui en est de "chaine" que j'ai cité au dessus, j'aurais du y penser mais c'est de type char* donc pointeur sur chaine de caractères
    Non. char * est le type d'un pointeur sur char. Point.
    et ce pointeur pointe déjà sur une adresse .
    Non. ce pointeur contient une adresse. Il pointe sur le prémier élément du tableau.

    Essaye de ne pas déformer ce qu'on dit. On se tue à utiliser les bons termes, alors fais en autant, sinon, tu ne peux pas comprendre ce qu'on dit.

    Je pense que c'est en effet, en voulant faire un rapprochement avec des langages objets tel que C++ ou Java, où nous utiliserions (dîtes le moi si je me trompe) simplement un nom de variable pour fournir de façon sous entendu une "adresse" ou plutôt devrais-je dire une référence au programme, que je me suis mélangé les méninges et que j'ai eu ce méchant doute sur scanf.
    Il faut oublier ce que font les autres langages... Ne pas oublier que le C est à l'origine de tous ces langages dérivés...

    En C++, la notion de passage par référence (avec & dans me paramètre) est claire.

    En Java, c'est beaucoup moins clair (mais je débute). La notion de pointeur étant carrément absente (mais ça m'étonnerais que new retourne des patates...), on ne sait pas trop ce qui ce passe (ce qui me gène, mais ça doit être normal pour un programmeur C et ce n'est pas le lieu pour en parler...)


    Voila, je vous remercie beaucoup c'est en effet un point sur lequel on peut vite passer à côté, je viens de m'en rendre compte.
    Euh, non. C'est un des fondements du C. Il n'est pas possible de passer à coté si on est formé correctement.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par défaut
    @Emmanuel: Il n'y a pas de passage par référence en java. Par contre, tout ce qui n'est pas un "type primitif" (int, float) est une "référence d'objet".
    En java, tous les objets sont sur le tas, et il est impossible d'avoir directement une structure dans la pile (ou dans une autre structure)

    En C et en C++, c'est différent: Une structure peut être n'importe où, c'est pourquoi la notion de référence ou de pointeur est explicite.

    Et c'est encore plus rigolo en C# ou surtout en C++/CLI, qui donne accès à deux tas différents: Le tas "natif" et le tas "managé"...
    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.

  12. #12
    Membre confirmé
    Inscrit en
    Novembre 2006
    Messages
    167
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 167
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Non. ce pointeur contient une adresse. Il pointe sur le prémier élément du tableau.

    Essaye de ne pas déformer ce qu'on dit. On se tue à utiliser les bons termes, alors fais en autant, sinon, tu ne peux pas comprendre ce qu'on dit.
    Oui c'est vrai, le vocabulaire est strict et je n'ai pas employé le bon mot.
    Autant pour moi, je saisi la différence maintenant qu'on a fait le tour des appellations.

    Citation Envoyé par Emmanuel Delahaye Voir le message
    Euh, non. C'est un des fondements du C. Il n'est pas possible de passer à coté si on est formé correctement.
    Je voulais dire en réalité et non idéalement...

    Merci beaucoup Emmanuel pour ce complément d'informations fort utile !

    Bonne continuation!

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

Discussions similaires

  1. [Débutant] problème de compréhension
    Par Sylvester dans le forum Général Java
    Réponses: 18
    Dernier message: 21/07/2005, 09h16
  2. Réponses: 5
    Dernier message: 11/04/2005, 10h21
  3. [C#] Problème de compréhension de System.Convert ET Provider
    Par papouAlain dans le forum Windows Forms
    Réponses: 5
    Dernier message: 18/11/2004, 21h52
  4. onclipevent (problème de compréhension)
    Par stephane eyskens dans le forum Flash
    Réponses: 8
    Dernier message: 24/09/2003, 15h09
  5. Problème de compréhension des ensembles
    Par Cornell dans le forum Langage
    Réponses: 6
    Dernier message: 07/02/2003, 22h07

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