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 :

[char * ptr] peut modifer ou peut pas modifier


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de Biosox
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    298
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2005
    Messages : 298
    Par défaut [char * ptr] peut modifer ou peut pas modifier
    bonjour.

    Voici que je tombe sur un problème cocasse. Pour l'illustrer, j'ai réduit le code au strict minimum. Voici mon code, qui compile sans problèmes sur Ms Visual C++ 6.0

    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
     
    #include <string.h>
     
    int main()
    {
      char *  string1 = "un deux trois quatre";	
      char    string2[21];  
      strcpy(string2,string1);
     
     
      string2[0] = 'A';
      *string1 = 'A';
     
      return 0;
    }
    Mon problème est le suivant: Lors de l'éxécution:
    à la ligne:
    ça marche (string2 pointe alors vers une chaîne qui contient "An deux trois quatre"
    mais à la ligne:
    Le programme plante. ("access violation")

    J'aimerais bien comprendre pourquoi?
    Est-ce que lorse que j'initialise une chaîne directement "codée en dur" elle va se mettre dans une zone de la mémoire dans laquelle mon programme n'a pas les droits en écriture?

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

    Informations forums :
    Inscription : Novembre 2004
    Messages : 57
    Par défaut
    Oui tu es en lecture seule car tu pointes vers la zone de segment data de ton appli au même titre que les constantes par exemple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    char    string2[21];  
    strcpy(string2,string1);
    string2[0] = 'A';
    Ici tu copies string1 dans string2 qui se trouve dans la pile donc pas de soucis pour écrire 'A'

  3. #3
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Par défaut
    Citation Envoyé par Biosox
    J'aimerais bien comprendre pourquoi?
    Est-ce que lorse que j'initialise une chaîne directement "codée en dur" elle va se mettre dans une zone de la mémoire dans laquelle mon programme n'a pas les droits en écriture?
    Normal, string1 pointe sur une constante chaine de caractère que tu ne peux pas modifier. C'est préférable de définir string1 de la manière suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const char *string1 = "un deux trois quatre";
    Par ailleurs, je préfère de manière générale utiliser strncpy au lieu de strcpy. Dans un code aussi simple que celui là où la tailles des chaînes manipulées est connue, cela n'a pas d'importance, mais autant prendre de bonnes habitudes.

    Thierry
    "The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
    "If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow

    FAQ-Python FAQ-C FAQ-C++

    +

  4. #4
    Membre Expert
    Avatar de Gruik
    Profil pro
    Développeur Web
    Inscrit en
    Juillet 2003
    Messages
    1 566
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juillet 2003
    Messages : 1 566
    Par défaut
    D'ailleurs, une option de gcc permet de dire que les chaines litterales sont de type "const char []" et non "char []", ce qui t'empeche de "mettre" une chaine litterale dans "char *".

  5. #5
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Par défaut
    Citation Envoyé par Gruik
    D'ailleurs, une option de gcc permet de dire que les chaines litterales sont de type "const char []" et non "char []", ce qui t'empeche de "mettre" une chaine litterale dans "char *".
    -Wwrite-strings

    Thierry
    "The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
    "If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow

    FAQ-Python FAQ-C FAQ-C++

    +

  6. #6
    Membre éclairé Avatar de Biosox
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    298
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2005
    Messages : 298
    Par défaut
    Et bien merci pour ces précisions!

    En effet, strncpy est préférable, mais en ecrivant un petit code à la va-vite, j'ai hlas encore bien des mauvaises habitudes

    (moi qui était tout fièr d'avoir mis un "int main" plutot qu'un "void main" pour pas me faire taper sur les doigts )

  7. #7
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Par défaut
    Citation Envoyé par Biosox
    Et bien merci pour ces précisions!

    En effet, strncpy est préférable, mais en ecrivant un petit code à la va-vite, j'ai hlas encore bien des mauvaises habitudes

    (moi qui était tout fièr d'avoir mis un "int main" plutot qu'un "void main" pour pas me faire taper sur les doigts )
    Il s'agit juste de prendre de bonnes habitudes, il n'y a aucun problème avec strcpy dans ce court exemple. L'utilisation de strncpy ne prend pas plus temps... Attention toutefois au fait que si string1 est plus longue que string1, strncpy ne mettra pas '\0' à la fin de string2 (je me suis laissé avoir dernièrement):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const char *string1 = "un deux trois quatre";
    char string2[10];
    strncpy(string2, string1, sizeof(string2));
    string2[sizeof(string2)-1] = '\0';
    Thierry
    "The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
    "If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow

    FAQ-Python FAQ-C FAQ-C++

    +

  8. #8
    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 mujigka
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const char *string1 = "un deux trois quatre";
    char string2[10];
    strncpy(string2, string1, sizeof(string2));
    string2[sizeof(string2)-1] = '\0';
    Compliqué...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
       const char *string1 = "un deux trois quatre";
       char string2[10];
       *string2 = 0;
       strncat(string2, string1, sizeof string2 -1);
    Ne pas utiliser strncpy() du tout. Trop dangereux. Le remède est pire que le mal...

  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 Biosox
    Est-ce que lorse que j'initialise une chaîne directement "codée en dur" elle va se mettre dans une zone de la mémoire dans laquelle mon programme n'a pas les droits en écriture?
    Oui, c'est possible.

    http://emmanuel-delahaye.developpez....es.htm#tabchar

    C'est pourquoi je recommande d'utiliser const avec les pointeurs sur chaines littérales.

    Avec mon compilateur, ton code est douteux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Project   : Forums
    Compiler  : GNU GCC Compiler (called directly)
    Directory : C:\dev\forums2\
    --------------------------------------------------------------------------------
    Switching to target: default
    Compiling: main.c
    main.c:4: warning: function declaration isn't a prototype
    main.c: In function `main':
    main.c:5: warning: initialization discards qualifiers from pointer target type
    Linking console executable: C:\dev\forums2\console.exe
    Process terminated with status 0 (0 minutes, 1 seconds)
    0 errors, 2 warnings
    Parce qu'il est réglé pour considérer les chaines comme non modifiables.

    http://emmanuel-delahaye.developpez....tm#cfg_compilo

    Une fois modifié (const) :
    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
     
    #include <string.h>
     
    int main (void)
    {
       char const *string1 = "un deux trois quatre";
       char string2[21];
     
       strcpy (string2, string1);
     
       string2[0] = 'A';
       *string1 = 'A';
     
       return 0;
    }
    l'erreur est détectée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Compiling: main.c
    main.c: In function `main':
    main.c:11: error: assignment of read-only location
    Process terminated with status 1 (0 minutes, 0 seconds)
    1 errors, 0 warnings
    Je pense que VC++6 en 'warning level 4' devrait voir ça, sinon, voir si il y a des options de compilation 'manuelles' à placer sur la ligne de commande à la main...

  10. #10
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    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 395
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    Je pense que VC++6 en 'warning level 4' devrait voir ça, sinon, voir si il y a des options de compilation 'manuelles' à placer sur la ligne de commande à la main...
    Pas à ma connaissance, et j'ai épluché les warnings de Visual pour tenter de trouver une telle option, en vain...
    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.

  11. #11
    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 Médinoc
    Pas à ma connaissance, et j'ai épluché les warnings de Visual pour tenter de trouver une telle option, en vain...
    Alors passer son code à gcc avant VC++6 est une option... (en mode vérification seule, je ne sais plus quel est le flag)

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 17/10/2014, 16h55
  2. Réponses: 1
    Dernier message: 05/10/2012, 02h44
  3. Réponses: 2
    Dernier message: 11/07/2010, 19h56
  4. [GeexBox] Elle peut ou elle peut pas?
    Par artiom dans le forum Autres
    Réponses: 1
    Dernier message: 30/12/2007, 05h15
  5. Utilisateur peut pas modifier la taille
    Par zogo123 dans le forum AWT/Swing
    Réponses: 3
    Dernier message: 27/11/2007, 08h53

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