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 :

Vider un tableau de char avec '\0'.


Sujet :

C

  1. #1
    Invité
    Invité(e)
    Par défaut Vider un tableau de char avec '\0'.
    Si j'utilise le caractère '\0' pour vider un tableau de char :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    char tab1[2+1]="A1";
    tab1[0]='\0';
    printf("%s",tab1);
    printf("\n");
    printf("%c",tab1[0]);
    printf("\n");
    printf("%c",tab1[1]);
    printf("\n");
    printf("%c",tab1[2]);
    Il n'y a plus de pseudo-string ?? Mais il reste le caractère "1" ??
    Le caractère '\0' marque la fin de quoi au juste, de la pseudo-string mais pas des caractères qui la compose ou plus précisément et dans ce cas, les trois emplacements mémoire de tab1 contiennent chacun dans l'ordre '\0', 1 et '\0'.
    Avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    memset(tab1,0,2);
    //ou
    bzero(tab1,2);
    Tout à l'air clean ou j'ai raté quelque chose en réalité ?
    Et est-il préférable en dernier argument de préciser le nombre total d’octet, '\0' compris soit (tab1,0,3) & (tab1,3) ?
    Les octets \0 valent 0, NULL ou je m’égares ?

    Bonne année à toutes et à tous.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 643
    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 643
    Points : 10 597
    Points
    10 597
    Par défaut
    Le caractère sentinelle '\0' est juste 1 convention de la bibliothèque standard pour dire "fin de chaîne".
    Toutes les fonctions standards strXXX l'utilise.
    Et le type "chaîne de caractères" n'existe pas en C : c'est 1 tableau de caractères (et donc c'est pour cela qu'on a le caractère sentinelle '\0')

    Donc rien de magique
    • char tab1[2+1]="A1"; -> | 'A' | '1' | '\0' | donc "A1"
    • tab1[0]='\0'; -> | '\0' | '1' | '\0' | donc ""
    • memset(tab1,0,2); -> | '\0' | '\0' | '\0' | donc ""

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 717
    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 717
    Points : 31 028
    Points
    31 028
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par MissLoop Voir le message
    Il n'y a plus de pseudo-string ??
    Plus exactement les fonctions dédiées à la traiter ne voient plus rien.

    Citation Envoyé par MissLoop Voir le message
    Mais il reste le caractère "1" ??
    Pourquoi n'y serait-il pas? As-tu tout oublié de tes cours sur les tableaux?? Taper dans tab[0] doit-il avoir un effet quelconque sur tab[1]??? Si c'était le cas le langage tout entier deviendrait inutilisable.
    Ne te focalise pas sur ce '\0', ce n'est qu'une valeur numérique. Elle ne change rien aux bases du C que tu as apprises.

    Citation Envoyé par MissLoop Voir le message
    Le caractère '\0' marque la fin de quoi au juste
    C'est une convention (donc qui ne fonctionne que si tout le monde joue le jeu) indiquant la fin de la chaine dite "utile" (celle dont le programmeur a besoin dans son traitement).

    Citation Envoyé par MissLoop Voir le message
    les trois emplacements mémoire de tab1 contiennent chacun dans l'ordre '\0', 1 et '\0'.
    Très exactement ils contiennent dans l'ordre '\0', '1' et '\0' (je te laisse trouver la différence entre ce que tu as écrit et ma correction)

    Citation Envoyé par MissLoop Voir le message
    Avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    memset(tab1,0,2);
    //ou
    bzero(tab1,2);
    Tout à l'air clean ou j'ai raté quelque chose en réalité ?
    Qu'entends-tu par "clean" ??? En tout cas si tu voulais juste "vider" la string tab1, tu as fait une opération inutile (un seul '\0' suffit, le second ne sert à rien puisque les fonctions s'arrêtent au premier).
    Mais pour faire ce que tu as écrit, les bonnes instructions sont les suivantes...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    memset(tab1, 0, 2 * sizeof(*tab1));
    //ou
    bzero(tab1, 2 * sizeof(*tab1));
    ... indiquant que tu veux remplir 2 cases de taille ayant chacune la taille d'une case de tab1 qui, d'une part, n'est pas obligé d'être du char et aussi où la taille d'un char n'est pas forcément un octet.
    Et aérer ton code (tout comme tu aères ton texte) en facilite la lecture.

    Citation Envoyé par MissLoop Voir le message
    Et est-il préférable en dernier argument de préciser le nombre total d’octet, '\0' compris soit (tab1,0,3) & (tab1,3) ?
    Non. Mais rien ne t'interdit par exemple de mettre le '\0' dans tab[2] avant de remplir tab[0] et tab[1]. L'important c'est qu'il soit présent avant que tab soit lu par une fonction de lecture de string.

    Citation Envoyé par MissLoop Voir le message
    Les octets \0 valent 0, NULL ou je m’égares ?
    De même que 'a' peut aussi s'écrire 97 ou 0x61, ce sont 3 écritures différentes pour la même valeur mathématique. Juste que NULL qui, sans être interdit, s'applique plutôt aux pointeurs qu'aux caractères. Mais ne pas oublier les quotes quand on parle de caractères. C'est '\0' et non \0.
    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]

  4. #4
    Invité
    Invité(e)
    Par défaut
    Dans mes expérimentations et recherches pour vider un tableau de char de ses éléments et donc de libérer son occupation mémoire, je suis tombée sur ce post : https://www.developpez.net/forums/d1...ar/#post753625
    Une chaîne de caractères ou une pseudo-string en C est composée de caractères et par convention on utilise le caractères '\0' qui marque la fin de cette pseudo-string.
    D'où l'idée de vider un tableau de char avec '\0' en index 0 pour signifier au compilateur qu'il n'y a plus de pseudo-string donc (et c'est ce que je pensais) plus de caractères du tout... J'ai sauté à pieds joints dans le mirage.
    Mais cela n'explique pas mon oubli du double quote du 1 ('\0', '1' et '\0'). En tous cas merci pour la correction memset(), bzero().

    Citation Envoyé par Sve@r Voir le message
    Qu'entends-tu par "clean" ???
    Lorsque je reprends ma série de printf() après memset() ou bzero(), tab1[n] ne renvoie plus rien.
    Par contre je ne m’explique pas pourquoi à la suite d'un memset() ou d'un bzero() je me prends une conversion de pointeur en un entier sans utilisation de l'opérateur de conversion lorsque je tente :

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 643
    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 643
    Points : 10 597
    Points
    10 597
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    Lorsque je reprends ma série de printf() après memset() ou bzero(), tab1[n] ne renvoie plus rien.
    Montre le code mais il doit te renvoyer/ retourner '\0'. Mais si tu l'affiches c'est normal qu'il t'affiche rien puisque tu affiches "fin de chaîne".
    Utilise 1 débugger pour voir le contenu de ton tableau : c'est la base (@Sve@r suggère des printf, effectivement mais cela alourdit le code qui faudra nettoyer ensuite)

    Citation Envoyé par MissLoop Voir le message
    Par contre je ne m’explique pas pourquoi à la suite d'un memset() ou d'un bzero() je me prends une conversion de pointeur en un entier sans utilisation de l'opérateur de conversion lorsque je tente :
    C'est l'erreur du débutant En gros (sauf échappement et autres)
    • 'A' (simple quote) c'est 1 seul caractère
    • "B2" (double quote) c'est 1 chaîne de caractères statique (dans .rodata) et donc 1 pointeur

    Donc c'est normal tu mets 1 pointeur (en 64 bits, 8 octets) dans 1 char (1 octet, sizeof(char) sera toujours 1, seule taille octet pour 1 type fixée par la norme)

  6. #6
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par foetus Voir le message
    Montre le code
    https://www.developpez.net/forums/d2.../#post11908121
    tab1[0]='\0'; en commentaire et utilisation de memset(tab1,0,2); //ou bzero(tab1,2); comme décrit dans le post.

    Citation Envoyé par foetus Voir le message
    C'est l'erreur du débutant En gros (sauf échappement et autres)
    • 'A' (simple quote) c'est 1 seul caractère
    • "B2" (double quote) c'est 1 chaîne de caractères statique (dans .rodata) et donc 1 pointeur

    Donc c'est normal tu mets 1 pointeur (en 64 bits, 8 octets) dans 1 char (1 octet, sizeof(char) sera toujours 1, seule taille octet pour 1 type fixée par la norme)
    Certes, mais je déclare et initialise au départ char tab1[2+1]="A1"; comme ceci.
    Je vide tab1[].
    Et j'affecte tab1[2+1] = "B2"; comme cela.
    Donc si je suis bien à la déclaration/initialisation je prends 3o en pseudo-string et après manipulation à l'affectation avec une autre pseudo-string de même longueur je tente de prendre 8o avec un pointeur, isnt it ?

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 643
    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 643
    Points : 10 597
    Points
    10 597
    Par défaut
    SVP va lire 1 cours en C sur les tableaux, chaînes de caractères, ...

    Ce n'est pas compliqué :
    • À la définition d'1 variable on peut l'initialiser avec 1 valeur. int i = 0;, int t1[3] = {1, 2};, int t2[] = {0};, char c1[2] = {0};, char c2[] = "toto";, char c3[10] = {'b', 'a', 'b', 'a', 'r'}
    • tab1[] ne veut rien dire. Mais sérieusement, rien.
    • Vider 1 chaîne de caractère ne veut rien dire. Soit tu mets le caractère sentinelle '\0' au premier caractère (1 affection, mais tu n'effaces pas totalement ta chaîne) soit tu fais 1 memset (X affectations).
    • C est langage procédural qui n'a pas de type "chaîne de caractères"
    • C est langage procédural qui n'a pas de type "chaîne de caractères"
    • 1 chaîne de caractères est 1 pointeur sur le premier élément (comme 1 tableau)
    • 1 chaîne de caractères statique (comme les autres valeurs statiques) sont dans .rodata
    • Donc tu ne peux pas affecter 1 chaîne de caractères comme en objet. Il faut soit copier caractère par caractère soit utiliser la bibliothèque standard : strcpy, strncpy (<- 2 liens en anglais)

  8. #8
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 717
    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 717
    Points : 31 028
    Points
    31 028
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    Dans mes expérimentations et recherches pour vider un tableau de char de ses éléments et donc de libérer son occupation mémoire,
    Première erreur, en informatique une variable (ie un tableau) n'est jamais "vide" car une variable contient toujours une valeur. Donc tu as défini un tableau de 3 caractères ton programme "possède" (utilise, réserve, consomme) 3 caractères en RAM. La valeur de ces caractères n'a aucune importance pour le C.

    Citation Envoyé par MissLoop Voir le message
    Une chaîne de caractères ou une pseudo-string en C est composée de caractères et par convention on utilise le caractères '\0' qui marque la fin de cette pseudo-string.
    Exact. On en a d'ailleurs parlé sur un autre post

    Citation Envoyé par MissLoop Voir le message
    D'où l'idée de vider un tableau de char avec '\0' en index 0 pour signifier au compilateur qu'il n'y a plus de pseudo-string
    Seconde erreur, ce n'est pas le compilateur qui lit une string mais les fonctions de lecture de strings, fonctions écrites en C. Pour le compilateur, lui, un '\0' n'est rien de plus qu'un caractère comme un autre.
    Ok il possède une petite sous-routine qui convertit "babar" en {'b', 'a', 'b', 'a', 'r', '\0'} mais c'est une sous-routine automatique qui ne signifie absolument rien pour lui. Le compilateur ne connait que les types natifs du C (char, int, short, long, float, double) et les strings n'en font pas partie.

    Citation Envoyé par MissLoop Voir le message
    Mais cela n'explique pas mon oubli du double simple quote du 1 ('\0', '1' et '\0').
    Eh oui. Parce que '1' (0x31) ce n'est pas 1 (0x01).

    Citation Envoyé par MissLoop Voir le message
    Lorsque je reprends ma série de printf() après memset() ou bzero(), tab1[n] ne renvoie plus rien.
    Parce que le caractère '\0' n'est pas affichable sur un écran. Tu entres là dans le souci de la "représentation" de tes données, qui est un domaine à part entière en programmation MVC ("V" = "Vue") et dans lequel chacun des 3 composantes "M", "V" et "C" possède ses fonctions dédiées ce qui permet de changer facilement une technologie par une autre.
    Mais tu as le droit d'afficher tab1[n] en format "%d" ou "%x" (après tout, un char ça reste à la base un nombre valant ente 0 et 255...)

    Citation Envoyé par MissLoop Voir le message
    Par contre je ne m’explique pas pourquoi à la suite d'un memset() ou d'un bzero() je me prends une conversion de pointeur en un entier sans utilisation de l'opérateur de conversion lorsque je tente :
    La notation double quotes est une notation string, notation qui dit au compilateur "ceci est un tableau de char" or un tableau peut aussi se voir comme un pointeur.
    Un caractère s'écrit entre quotes simples. Mais "B2" ce n'est pas "un" caractère mais une string (donc pour le compilo un tableau de char). Donc là tu cherches à faire entrer un tableau de char dans un char !!!
    Là le compilateur tente ce qu'il peut en remplaçant la string (le tableau de caractères) par le pointeur qui lui équivaut. Mais comme un pointeur ce n'est pas non plus un char le compilo finit alors par te dire qu'il ne peut pas stocker un pointeur dans un char.

    Citation Envoyé par MissLoop Voir le message
    Certes, mais je déclare et initialise au départ char tab1[2+1]="A1"; comme ceci.
    Je vide tab1[].
    Et j'affecte tab1[2+1] = "B2"; comme cela.
    Donc si je suis bien à la déclaration/initialisation je prends 3o en pseudo-string et après manipulation à l'affectation avec une autre pseudo-string de même longueur je tente de prendre 8o avec un pointeur, isnt it ?
    Attention, l'instruction char xxx[]="string" n'est autorisée qu'au moment de la définition de ta variable (je pense d'ailleurs te l'avoir dit dans un autre post). C'est un raccourci syntaxique dit "de facilité" qui équivaut à char xxx[]={'s', 't', 'r', 'i', 'n', 'g', '\0'} ce qui nous fait retomber dans la syntaxe générale de définition de tableaux.

    Ensuite, si tu veux modifier ton tableau (ta string) tu ne peux le faire qu'avec les instructions autorisées dans le cadre des tableaux, c'est à dire case par case.
    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]

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 643
    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 643
    Points : 10 597
    Points
    10 597
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Mais tu as le droit d'afficher tab1[n] en format "%d" ou "%x" (après tout, un char ça reste à la base un nombre valant ente 0 et 255...)
    Pour 1 ancien projet , j'avais codé 1 fonction pour faire 1 affichage/ dump hexadécimal (pour les chaînes UTF-8)

    Donc, voici 1 petit exemple (pas besoin de comprendre la fonction print_buffer) qui affiche l'hexidécimal et la chaîne de caractères (et les '\0' sont remplacés par _)

    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    #include <stdio.h>
    #include <stdlib.h>
     
     
    void print_buffer(unsigned char* buff, unsigned short buffer_len) {
    //  if (buff == NULL) { return; }
     
        if (buffer_len > 0) {
            int pos2;
            unsigned short pos;
            unsigned char* index = buff;
            unsigned char c;
            unsigned char part1, part2;
     
            for(pos = 0; pos < buffer_len; pos += 16, index += 16) {
                printf("\n");
     
                for (pos2 = 0; ((pos2 < 16) && ((pos + pos2) < buffer_len)); ++pos2) {
                    c = (*(index + pos2));
     
                    part1 =  (c & 0x0F);
                    part2 = ((c & 0xF0) >> 4);
     
                    if (part2 < 10) {
                        printf("%c", (part2 + '0'));
                    } else {
                        printf("%c", (part2 + 'A' - 10));
                    }
     
                    if (part1 < 10) {
                        printf("%c", (part1 + '0'));
                    } else {
                        printf("%c", (part1 + 'A' - 10));
                    }
     
                    if (pos2 <= 15) { printf(" "); }
                }
     
                if ((pos + 16) < buffer_len) {
                    printf("  |  ");
                } else {
                    for (pos2 = (pos + 16 - buffer_len); pos2 > 0; --pos2) { printf("   "); }
                    printf("  |  ");
                }
     
                for (pos2 = 0; ((pos2 < 16) && ((pos + pos2) < buffer_len)); ++pos2) {
                    c = (*(index + pos2));
     
                    if ((c >= 32) && (c <= 126)) {
                        printf("%c", c);
                    } else {
                        if (c != '\0') { printf(" "); } else { printf("_"); }
     
                    }
                }
            }
     
            printf("\n");
        }
    }
     
     
    int main()
    {
        char str[] = " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ligula lacus, tincidunt et accumsan et, tincidunt et quam. 123456789";
     
        str[  0] = '\0';
        str[ 57] = '\0';
        str[123] = '\0';
     
        printf("str:\n>(start  0) %s\n>(start  1) %s\n>(start 58) %s\n\ndump hex:\n", str, (str + 1), (str + 58));
        print_buffer(str, 134);
     
     
        return EXIT_SUCCESS;
    }

  10. #10
    Invité
    Invité(e)
    Par défaut
    Merci beaucoup Sve@r.

    Citation Envoyé par Sve@r Voir le message
    Attention, l'instruction char xxx[]="string" n'est autorisée qu'au moment de la définition de ta variable (je pense d'ailleurs te l'avoir dit dans un autre post).
    Super, je ne comprenais pas l'erreur avec mon tab1[2+1] = "B2";.
    En fait tu m'en avais parlé dans ce post :
    Citation Envoyé par Sve@r Voir le message
    "Seule et unique exception: quand tu déclares ta string, tu peux écrire char s[]="hello". Là le compilateur t'offre un petit cadeau et se charge lui de mettre le '\0'. Ce qui revient à écrire char s[]={'h', 'e', 'l', 'l', 'o', '\0'}.
    Donc non, le caractère de fin n'est pas géré automatiquement, il est juste géré par tous les programmeurs et contributeurs qui t'offrent des fonctions de traitement de chaine déjà toutes faites. "
    Où il était question du caractère de fin et du bien fondé de la gestion personnelle et rigoureuse des tableaux (de char en l’occurrence et en particulier).
    J'ai pensé que la seule et unique exception concernait la prise en charge par le compilo du '\0', pas qu'il s'agissait de la déclaration. Même si en définitive c'est cette forme de déclaration qui oblige le compilo à jouer au Père Noël.

    En parlant de MVC, il n'y a pas grand chose pour le C, je me trompe ?

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 11/06/2012, 16h11
  2. Tableau de char avec valeur incohérente.
    Par bigbobby64 dans le forum Débuter
    Réponses: 4
    Dernier message: 25/05/2012, 14h18
  3. Réponses: 7
    Dernier message: 03/08/2011, 22h49
  4. Réponses: 15
    Dernier message: 22/12/2006, 14h28
  5. Comment vider un tableau de char ?
    Par Battosaiii dans le forum C
    Réponses: 5
    Dernier message: 18/03/2006, 17h42

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