Bonjour à tous,

Si vous avez manqué les cours précédents, commencez par ceux-ci et revenez ici ensuite :

Cours 0 : Pré-requis et premier programmeConsulter
Cours 1 : DialogueConsulter
Cours 2 : Types de données et appels de fonctionsConsulter
Cours 3 : Opérateur ternaire et masquageConsulter
Cours 4 : Switch et premiers tableauxConsulter
Cours 5 : Incrémentation, boucles et tri de tableauConsulter
Cours 6 : Les fichiersConsulter
Cours 7 : Tableaux et matricesConsulter
Cours 8 : Chaînes de caractèresEn cours
Cours 9 : Introduction à la programmation objetConsulter




Attention : Du fait des limitations actuelles la communauté, il n'est pas possible d'afficher un code correct, c'est pourquoi je vous fournis ce fichier ZIP contenant l'ensemble des codes de ce cours. Décompressez le dans votre dossier MinGW/code/.

Cours8.zip (1.24 KB, Downloads: 1)

Rappel : Pour pouvoir compiler les fichiers, utilisez l'instruction suivante dans votre Invite de commandes où vous remplacerez bien sûr les 2 ''nom de fichier''.

  1. gcc -ansi -Wall -pedantic -o nomdefichier.exe nomdefichier.c
Copy the Code


Une chaîne de caractères c'est quoi ?

Derrière ce nom un peu barbare se cache tout simplement un texte, une phrase, un mot, une lettre, ... Tout simplement une suite de plusieurs caractères, une chaîne.

Ainsi, si on prend le mot ''Xiaomi'', on a à faire à une chaîne de 6 caractères. Par contre en C ANSI comme dans beaucoup de langages, une chaîne de caractères est ponctué par un caractère spécial afin de spécifier qu'il s'agit du fin de la chaîne. En C ANSI, ce caractère est ''\0''. Vous me direz c'est deux caractères mais l'anti-slash annonce ici un caractère spécial, on a donc bien un seul caractère. La chaîne de caractères ''Xiaomi'' occupera donc la taille de 7 caractères dans notre mémoire.

Opérations sur les chaînes

Pour une fois, je vais vous demander de réinventer la poudre. Il existe de nombreuses fonctions de manipulations des chaînes de caractères : copie, concaténation, calcul de la longueur, etc...

Notre première approche va être de considérer ces chaînes comme des tableaux de caractères.

char str[10] = {'X','i','a','o','m','i','\0'};

Toutefois, vous voyez que ça va être très fastidieux d'écrire des phrases de cette manière, donc on va utiliser la notation suivante :

char str[10] = "Xiaomi";

Notez bien qu'avec cette notation, on n'a pas besoin d'indiquer le caractère de fin ''\0'' mais il sera bien ajouté automatiquement.
Je vais quand même vous donner l'exemple d'une fonction : ''strcpy'' qui va tout simplement copier une chaîne dans une autre.

mistrcpy.c
  1. #include ˂stdio.h˃
  2. #include ˂stdlib.h˃
  3. #include ˂string.h˃

  4. char * mi_strcpy(char * s1,char * s2)
  5. {
  6.    int i;
  7.    int fin = 0;
  8.         
  9.    while(s2[fin] != '\0')
  10.       fin++;
  11.         
  12.    for(i = 0;i  fin;i++)
  13.       s1[i] = s2[i];
  14.         
  15.    return s1;
  16. }

  17. int main(void)
  18. {
  19.    char str1[10] = ʺXiaomiʺ;
  20.    char str2[10] = ʺAppleʺ;
  21.    char str3[10] = ʺXiaomiʺ;
  22.    char str4[10] = ʺAppleʺ;

  23.    printf(ʺNos 2 chaines :\n(%s) : (%s)\nʺ,str1,str2);
  24.    printf(ʺCopie avec notre fonction :\n(%s)\n\nʺ,mi_strcpy(str2,str1));

  25.    printf(ʺNos 2 chaines :\n(%s) : (%s)\nʺ,str3,str4);
  26.    printf(ʺCopie avec la fonction C existante :\n(%s)\nʺ,strcpy(str4,str3));  
  27.    
  28.    return 0;
  29. }
Copy the Code


Vous voyez que j'ai inclus la librairie string.h afin de pouvoir utiliser la fonction strcpy et vérifier que ma fonction mi_strcpy effectue exactement la même chose.

Exercice 1/2 - Reproduire des fonctions

A vous maintenant de coder et de redéfinir des fonctions, vous avez le choix :
  • strlen : retourne la longueur d'une chaîne de caractère ;
  • strchr : cherche la première occurrence d'un caractère et retourne une chaîne composée de ce caractère ainsi que tous les caractères suivants (pour faire simple, on supprime tout ce qu'il y a avant le caractère) ;
  • strpos : celle-ci n'existe pas en C mais elle retourne la position de la première occurrence d'un caractère dans une chaîne de caractère ;
  • strcat : fait la concaténation de 2 chaînes de caractères (''Xiaomi'' et ''Apple'' deviennent ''XiaomiApple'') ;
  • etc ...

Vous pouvez aussi inventer des fonctions, pourquoi pas une fonction ''compare'' qui retourne 1 si le chaîne 2 est plus courte que le chaîne 1, sinon elle retourne 0.

Voici un code de départ si besoin :

fctchaines.c
  1. #include ˂stdio.h˃
  2. #include ˂stdlib.h˃
  3. #include ˂string.h˃

  4. int compare(char * s1,char * s2)
  5. {

  6. }

  7. long mi_strlen(char * s)
  8. {

  9. }

  10. char * mi_strchr(char * s, int c)
  11. {

  12. }

  13. int mi_strpos(char * s,int c)
  14. {

  15. }

  16. char * mi_strcat(char * s1,char * s2)
  17. {

  18. }

  19. char * mi_strcpy(char * s1,char * s2)
  20. {
  21.    int i;
  22.    int fin = 0;
  23.         
  24.    while(s2[fin] != '\0')
  25.       fin++;
  26.         
  27.    for(i = 0;i  fin;i++)
  28.       s1[i] = s2[i];
  29.         
  30.    return s1;
  31. }

  32. int main(void)
  33. {
  34.    char str1[15] = ʺXiaomiʺ;
  35.    char str2[15] = ʺAppleʺ;
  36.         
  37.    printf(ʺ(%s) : (%s)\nʺ,str1,str2);
  38.    /* TEST compare */
  39.    printf(ʺ\n%d\nʺ,compare(str1,str2));
  40.    /* TEST strlen */
  41.    printf(ʺ\n(%ld) : (%ld)\nʺ,strlen(str1),my_strlen(str1));
  42.    printf(ʺ(%ld) : (%ld)\nʺ,strlen(str2),my_strlen(str2));
  43.    /* TEST strchr, strpos */
  44.    printf(ʺ\n(%s) : (%s)\nʺ,str1,str2);
  45.    printf(ʺ(%s) : (%s) : (%d)\nʺ,mi_strchr(str1,'o'),strchr(str1,'o'),mi_strpos(str1,'o'));
  46.    printf(ʺ(%s) : (%s) : (%d)\nʺ,mi_strchr(str2,'o'),strchr(str2,'o'),mi_strpos(str2,'o'));
  47.    /* TEST strcpy */
  48.    printf(ʺ\n(%s) : (%s)\nʺ,str1,str2);
  49.    printf(ʺ(%s) : (%s)\nʺ,strcpy(str2,str1),mi_strcpy(str2,str1));
  50.    /* TEST strcat */
  51.    printf(ʺ\n(%s) : (%s)\nʺ,str1,str2);
  52.    printf(ʺ(%s) : (%s)\nʺ,strcat(str2,str1),mi_strcat(str2,str1));
  53.         
  54.    return 0;
  55. }
Copy the Code


Si vous avez besoin d'indices pour savoir comment écrire vos fonctions n'hésitez pas à utiliser les commentaires !

Les pointeurs

Il est temps de vous dire un secret, cela fait plusieurs cours que je met des étoiles dans votre code sans même vous dire à quoi elles servent : ''char *'', ''int *''. Vous voyez de quoi je parle ? Eh bien ces étoiles servent en fait à préciser que l'on utilise un ''pointeur''.

Dans nos téléphones Xiaomi, nous avons souvent 4Go de mémoire vive. 4 Go = 4 096 Mo = 4 194 304 ko = 4 294 967 296 o. Vous vous souvenez, nos types de données occupent de 1 à 10 octets selon le type. Partons du cas des caractères (char), ils n'occupent qu'1 octet en mémoire. Ainsi, si rien ne tourne sur notre téléphone, nous avons un peu moins de 4 294 967 296 octets libres. Imaginez vous dans une mégalopole chinoise avec 4 294 967 296 habitants et vous avez un courrier à distribuer à l'un de ces habitants, vous aurez besoin de son adresse pour le retrouver. Eh bien, un pointeur c'est pareil, c'est l'adresse en mémoire. Le pointeur ne contient donc pas la valeur mais il sait parfaitement où la trouver !

char *s;

Voici la déclaration d'un pointeur s sur une donnée de type caractère. Mais si on a une variable déjà définie, comment connaître son adresse mémoire ?

Je crois qu'il faut que je vous confesse encore quelque chose, vous l'avez déjà utilisé, souvenez vous de la fonction scanf ...

char c = 'a';
char *s = &c;

C'est bien ce ''et commercial'' (&) placé devant une variable qui va nous donner son adresse en mémoire.

Si on s'intéresse maintenant aux tableaux et aux chaînes de caractères.

char tab[10] = {'X','i','a','o'};
char str[10] = ''Mi'';

Que désignent en fait ''tab'' et ''str'' ? Ce sont en fait des pointeurs sur la première valeur du tableau ou de la chaîne. En gros :

*tab = 'X';
*str = 'M';

Donc *tab désigne une adresse mémoire qui contient la valeur 'X' mais où se trouve alors le 'i' ? Tout simplement à l'(adresse mémoire + 1). Donc comment y accéder avec un pointeur ?

*(tab+1) = 'i';

Si vous avez tout compris alors on va pouvoir programmer. Pourquoi ne pas transformer tous nos tableaux utilisés précédemment en pointeurs ? Voici alors ma fonction strcpy transformée :

mipstrcpy.c
  1. #include ˂stdio.h˃
  2. #include ˂stdlib.h˃
  3. #include ˂string.h˃

  4. char * mi_p_strcpy(char * s1,char * s2)
  5. {
  6.    char *os1 = s1;
  7.    while((*s1++ = *s2++));
  8.    return os1;
  9. }

  10. int main(void)
  11. {
  12.    char str1[10] = "Apple";
  13.    char str2[10] = "Xiaomi";

  14.    printf("Copie :\n(%s)\n", mi_p_strcpy(str1,str2));
  15.    
  16.    return 0;
  17. }
Copy the Code


Une version très condensée que je vous explique tout de suite.

1) Je commence par sauvegarder l'adresse de notre chaîne 1 dans un autre pointeur.
2) Tant qu'il y a des caractères dans la chaîne 2 je copie les caractères un à un : *s1 = *s2. On utilise l'incrémentation pour aller à l'(adresse mémoire + 1) à chaque tour de boucle. La boucle va s'arrêter car on va arriver à la fin de la chaîne 2 et au fameux caractère '\0', celui converti en entier vaut tout simplement 0 donc cette valeur stoppe la boucle. Vous avez remarqué qu'après la boucle while il y a directement un point virgule qui signifie que nous n'avons rien à exécuter à chaque tour de boucle.
3) Comme nous avons modifié l'adresse de départ stocké dans s1, en fait nous sommes à (s1+7) : les 6 lettres de Xiaomi + le '\0' final. C'est pourquoi nous avions sauvegardé l'adresse dans le pointeur os1, nous n'avons donc qu'à retourner os1.

Exercice 2/2 - Reproduire les fonctions avec les pointeurs

Et voilà, pour les plus motivés, vous pourrez vous attaquer à la ré-écriture des différentes fonctions que vous avez faite lors de l'exercice 1. Faites des essais, partagez les en commentaires et on pourra en discuter ensemble. Bon courage !




Si vous n'avez pas compris quelque chose n'hésitez pas à poser vos questions en commentaires, entraidez-vous !

Note : pour partager vos codes, utilisez des captures d'écran car malheureusement la communauté n'est pas encore totalement apte à partager facilement du code !