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 :

quelques questions concernant le pointeur de type char et le caractère nul


Sujet :

C

  1. #1
    Futur Membre du Club
    Homme Profil pro
    amateur
    Inscrit en
    Mars 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : amateur

    Informations forums :
    Inscription : Mars 2015
    Messages : 13
    Points : 9
    Points
    9
    Par défaut quelques questions concernant le pointeur de type char et le caractère nul
    salut à tous et à toutes
    j'ai défini une variable pointeur:
    char *mot;
    je voudrais faire l'allocation dynamique de la mémoire pour stocker le mot "salut". je me doute de cases mémoires que je devrais allouer.
    5 cases mémoires pour les lettres composants le mot "salut" ou 5 cases mémoires + le caractère nul '\0' qui marque la fin d'une chaîne de caractères dans la mémoire.
    une dernière chose:
    lorsqu'on définit 2 pointeurs de type char:
    char *chaine1 et char *chaine2
    et on alloue de la mémoire pour chacun d'eux à l'aide de la fonction malloc, 50 octets pour chacun. on remplit chaine2 à moitié (25 octets utilisés seulement). lorsqu'on copie chaine2 dans chaine1 avec la fonction strcpy. est ce que seulement 25 octets est copié ou toute l'espace allouée (50 octets). est ce qu'il est préférable de se servir du caractère nul '\0' dans chaine2 pour marquer la fin de la chaîne et pour déterminer la quantité d'octets qu'on veut copier dans chaine1 (25 octets + le caractère nul)
    si quelqu'un peut nous aider à comprendre tous cela, soyez le bienvenu
    merci beaucoup mes amis
    cordialement,

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par math25 Voir le message
    5 cases mémoires pour les lettres composants le mot "salut" ou 5 cases mémoires + le caractère nul '\0' qui marque la fin d'une chaîne de caractères dans la mémoire.
    voici la documentation de l'entête string.h, lien cplusplus.com en anglais
    En C++, les entêtes n'ont pas d'extension et commencent par c : donc l'entête cstring c'est la même entête mais pour le C++.

    Sans vérifier, mais toutes les fonctions de la librairie standard travaillent avec le caractère sentinelle '\0'.
    Donc si tu ne mets pas ce caractère, tu ne pourras pas utiliser ces fonctions parce qu'il va y avoir des débordements
    Il faudra des fonctions qui travaillent avec la taille que tu devras soit fournir en paramètre en + soit encapsuler avec ta chaîne de caractères dans ta propre structure.

    Je ne pense pas qu'il y ait d'autre choix


    Citation Envoyé par math25 Voir le message
    et on alloue de la mémoire pour chacun d'eux à l'aide de la fonction malloc, 50 octets pour chacun. on remplit chaine2 à moitié (25 octets utilisés seulement). lorsqu'on copie chaine2 dans chaine1 avec la fonction strcpy. est ce que seulement 25 octets est copié ou toute l'espace allouée (50 octets). est ce qu'il est préférable de se servir du caractère nul '\0' dans chaine2 pour marquer la fin de la chaîne et pour déterminer la quantité d'octets qu'on veut copier dans chaine1 (25 octets + le caractère nul)
    La fonction strcpy (<- lien vers la documentation en anglais) utilise la caractère sentinelle '\0'.
    Donc, elle copiera jusqu'à la sentinelle soit 25 et inclura la sentinelle (d'après la documentation)

    Sinon, tu peux utiliser la fonction strncpy ou la fonction memmove pour copier le nombre de caractères que tu veux (<- 2 liens vers la documentation en anglais)

  3. #3
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 446
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 446
    Points : 43 090
    Points
    43 090
    Par défaut
    Si tu dois allouer de la mémoire pour une chaine de caractères, il faut réserver de la mémoire pour le caractère NULL (\0) marquant la fin.

    et on alloue de la mémoire pour chacun d'eux à l'aide de la fonction malloc, 50 octets pour chacun. on remplit chaine2 à moitié (25 octets utilisés seulement). lorsqu'on copie chaine2 dans chaine1 avec la fonction strcpy. est ce que seulement 25 octets est copié ou toute l'espace allouée (50 octets).
    26 caractères seront copiés, strcpy s'arrêtant au caractère de fin \0 et le copiant dans la destination pour marquer la fin de la chaine.

    Il faut comprendre que strcpy ne se préoccupe pas de la taille de la destination, tu ne dois l'utiliser que si tu es sûr que la destination aura la place pour recevoir la copie, sinon il faut utiliser strncpy ou la copie se fera sur n caractères ou atteinte de \0. La doc précise que dans le cas ou la chaine de destination est plus grande que la source, elle sera remplie de \0 pour le restant. Et attention si dans les n caractères copiés, il n'y a pas caractère de terminaison,dans les x caractères copiés de la source la chaine de destination ne sera pas "fermée" par un \0.
    Pour pallier ce dernier point, il existe une fonction moins connue : strlcpy. Celle-ci vient de BSD mais est dispo sous Linux via l'en-tête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #include <bsd/string.h>
    mais tu peux considérer ceci comme non standard.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  4. #4
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    Il y a quelques règles simples à suivre :

    Règles concernant l'initialisation de pointeurs

    Quand tu déclares un pointeur comme dans char *p par exemple, tu ne peux pas l'utiliser avant de l'avoir correctement initialisé. Un pointeur correctement initialisé est

    • soit un pointeur initialisé à NULL (p=NULL) pour indiquer qu'il ne pointe nulle part. La seule chose valide que tu peux faire avec un pointeur NULL c'est le tester pour voir s'il est NULL ou non (p==NULL ou p!=autre_pointeur) ;
    • soit un pointeur initialisé avec l'adresse d'une autre variable/zone mémoire valide →
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      int a;
      int *pointeur_valide_sur_int = &a;
      int array[5]={0,1,2,3,4};
      int *pointeur_valide=array+2; // identique à &array[2]
      int *pointeur_valide_aussi = autre_pointeur_valide;
      int *pointeur_invalide=array+42; // out of bound
      int *pointeur_invalide_aussi=a+1;
      int *pointeur_invalide_tant_qu_on_fait_pas_de_l_embarqué = 0xdeadbeef;
    • soit un pointeur initialisé avec une fonction d'allocation de mémoire comme malloc → struct foo *p_foo = malloc( sizeof(struct foo) );


    Utiliser un pointeur non initialisé conduit à erreurs. Attention toutefois à ne pas oublier qu'un pointeur correctement initialisé ne le restera que tant que ce qui est pointé existe … un pointeur correctement initialisé n'est valide

    Une des règles de l'allocation dynamique

    À chaque malloc doit correspondre un et un seul free.
    «Toujours par deux ils vont, ni plus, ni moins».

    Les chaîne de caractères en C

    En C, contrairement à d'autres langages, il n'y a pas de type chaînes de caractères. Une string en C, un c-string ou nul terminated string ou zstring ou …, c'est simplement par convention un tableau de char dont on ne connaît pas a priori la longueur de la chaîne mais dont on sait que la fin marquée par le caractère NUL, soit celui de code ascii 0 aussi noté '\0'. La bibliothèque standard propose des fonctions qui permettent de manipuler ces c-string. Ce sont toutes les fonctions que tu trouve dans string.h et dont le nom commence par str. Elles sont nombreuses et comme te le conseille à juste titre foetus, tu les apprendras principalement en les utilisant et en lisant la doc.
    C'est en quelque sorte une facilité offerte par la bibliothèque standard.
    Il y a une sous-famille de fonctions : strn. Le n indiquant qu'on manipule des c-string en spécifiant une taille limite de travail. Il faut faire attention à la manière dont est traité NUL. À nouveau il n'y a qu'un moyen : utiliser et lire la doc.

    Dans la littérature on fait une différence entre taille et longueur (et oui, ça compte). La longueur d'une chaîne est le nombre de char qui la compose sans compter le NUL, elle est donnée par strlen si la chaîne est correctement initialisée. La taille d'une chaîne est la taille de la zone mémoire qui lui est allouée, statiquement dans le type ou dynamiquement par malloc:

    La taille d'une chaîne doit donc impérativement être au moins égale à la longueur de la chaîne plus 1 (le fameux caractère NUL).


    Il y a toute une autre famille de fonctions proposées dans string.h, celles dont le nom commence par mem. Ces fonctions ressemblent parfois aux fonctions de la famille str mais elles sont différentes. En effet, elles ne supposent jamais que la fin d'une zone mémoire est marquée par un NUL. Il faut toujours leur donner une taille.
    Ces fonctions traitent les blocs mémoire pour ce qu'ils sont : une suite de bytes dont on connaît le début et la taille. On peut aisément manipuler des données contenant le caractère NUL, ce qui est impossible avec les fonctions de la famille str.


    Avertissement

    Il ne faut pas confondre NULL (avec deux ell) et NUL (avec un seul ell).
    NULL est un pointeur valide mais ne pointant nulle part.
    NUL est un caractère ascii dont le code est nul, c'est un entier qui vaut 0 et dont le type est char.


    Visualiser ce qui se passe

    Il existe des sites qui te permettront de visualiser ce qui se passe quand du code est exécuté. Par exemple sur C Tutor tu peux voir l'exécution d'un code simple comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    int main() {
      char mot[50]="Hello world !";
      char *mot1=malloc(50);
      char *mot2=mot;
     
      strcpy(mot1, mot2);
     
      return 0;
    }
    Tu peux aussi utiliser un debuger, mais pour les codes simples C Tutor est plus facile d'accès.

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par math25 Voir le message
    5 cases mémoires pour les lettres composants le mot "salut" ou 5 cases mémoires + le caractère nul '\0' qui marque la fin d'une chaîne de caractères dans la mémoire.
    Le point de départ à ne pas oublier, c'est que la chaine "salut" contient réellement 6 caractères 's', 'a', 'l', 'u', 't' et '\0' (le 6°, bien qu'invisible, existe quand-même). Tu veux stocker la chaine dans un pointeur, tu dois allouer alors l'espace pour stocker cette chaine dans son intégralité car malloc() ne connaissant pas le but de cette allocation ne le fera pas à ta place.

    Citation Envoyé par math25 Voir le message
    on remplit chaine2 à moitié (25 octets utilisés seulement). lorsqu'on copie chaine2 dans chaine1 avec la fonction strcpy. est ce que seulement 25 octets est copié ou toute l'espace allouée (50 octets).
    Déjà strcpy() s'arrête au premier '\0' trouvé dans chaine2. Donc déjà il faut absolument que chaine2 contienne un '\0' et donc tout dépend de quelle manière tu as rempli chaine2. Si tu as utilisé une fonction de remplissage de type str (ex sprintf(), strcpy(), fgets()) alors la fonction aura positionné le '\0' dans chaine2. Puis tu copies chaine2 dans chaine1 par strcpy() alors strcpy(), s'arrétant au '\0', ne copie alors que les 25 caractères se trouvant avant ce '\0', puis place un '\0' final pour terminer chaine1.
    Et si tu as rempli chaine2 manuellement (cela peut arriver) alors tu dois positionner le '\0' toi-même (tu en as le droit).

    Citation Envoyé par math25 Voir le message
    est ce qu'il est préférable de se servir du caractère nul '\0' dans chaine2 pour marquer la fin de la chaîne et pour déterminer la quantité d'octets qu'on veut copier dans chaine1 (25 octets + le caractère nul)
    Il est impératif que chaine2 contienne un '\0'. Si tu n'as pas la garantie qu'il y est, alors tu peux/tu dois le mettre toi-même.

    Citation Envoyé par math25 Voir le message
    si quelqu'un peut nous aider à comprendre tous cela, soyez le bienvenu
    Pour résumer: une chaine c'est une suite de caractères contenant un '\0' qui permet de détecter sa fin. Toute fonction de création de chaine mettra elle-même ce '\0' (à l'exception de strncpy() et strncat() quand "n" est atteint mais tu n'es pas obligé d'utiliser ces fonctions immédiatement). Et toute fonction de lecture de chaine cherchera ce '\0'. Ainsi la boucle est bouclée. Chaque création de chaine mettra le '\0' où il faut et chaque lecture de chaine cherchera ce '\0', tout s'emboite parfaitement.
    Les seuls soucis seront toi de
    1. t'assurer qu'il y la place pour y mettre ce '\0'
    2. mettre ce '\0' si tu as créé ta chaine manuellement depuis une fonction qui, elle, n'étant pas faite pour créer des chaines, ne l'aura pas fait elle-même (ex memcpy(), read(), fgetc(), ...). Et dans ce cas, comme il y aura à la place le nombre de caractères manipulés (soit par un paramètre passé à la fonction, soit par la valeur retournée par la fonction), cette indication te permettra de déterminer où mettre ce '\0'. Ex char chaine[10]; memcpy(chaine, "Hello", 5); chaine[5]='\0' => c'est parce que je copie seulement 5 caractères que je sais que le '\0' ira à l'indice 5. Et je suis même pas obligé de rester dans le sens "logique", ex: char chaine[10]; chaine[5]='\0'; memcpy(chaine, "Hello", 5)


    Citation Envoyé par WhiteCrow Voir le message
    Il existe des sites qui te permettront de visualiser ce qui se passe quand du code est exécuté. Par exemple sur C Tutor tu peux voir l'exécution d'un code simple
    Pas mal du tout ce site
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

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

Discussions similaires

  1. Quelques questions concernant le tuto Java - TP Calculatrice
    Par klgui4 dans le forum Débuter avec Java
    Réponses: 7
    Dernier message: 11/04/2012, 11h36
  2. Quelques questions concernant un Userform
    Par rickgoz dans le forum Macros et VBA Excel
    Réponses: 8
    Dernier message: 31/10/2008, 16h51
  3. Quelques questions concernant un exo de BD
    Par dudule65 dans le forum Requêtes et SQL.
    Réponses: 4
    Dernier message: 17/01/2008, 14h25
  4. Quelques questions concernant PDCurses
    Par Electroniktor dans le forum C
    Réponses: 3
    Dernier message: 16/09/2007, 16h44
  5. quelques questions concernant g_free, g_malloc
    Par bit_o dans le forum GTK+ avec C & C++
    Réponses: 25
    Dernier message: 26/03/2007, 20h36

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