====== Chaînes de caractères ====== > Après cela, vous devriez comprendre pourquoi Python est à la mode et pourquoi c'est Python que l'on enseigne au lycée et pas C... En Python, on n'a pas grand chose à faire. On écrit directement une chaîne de caractère dans le programme, par exemple : texte = "blablabla" et voilà c'est terminé. En C... c'est plus compliqué. ===== Tableau de char ===== On a dit qu'un [[.:caractères|caractère]] était de type ''%%char%%''. Une chaîne sera un tableau de ''%%char%%''. La chaîne ''%%"Chat"%%'' serait donc contenu dans un tableau sous cette forme ''%%{'C','h','a','t'}%%'' Mais il y a une règle en plus (rien n'est simple !), une chaîne se termine toujours par le caractère spécial ''%%'\0'%%''. Donc le chaîne ''%%"Chat"%%'' sera stockée sous la forme ''%%{'C','h','a','t','\0'}%%'', contient donc 5 éléments. On pourrait déclarer : char texte[5]; // déclaration du tableau. texte[0] = 'C'; texte[1] = 'h'; texte[2] = 'a'; texte[3] = 't'; texte[4] = '\0'; printf("%s\n", texte); // affiche Chat == Déclaration raccourcie == On n'est pas obligé de tout écrire ainsi. On peut déclarer de façon plus compacte : char texte[] = "Chat"; printf("%s\n", texte); // affiche Chat En effet, C va comprendre que l'on veut créer la chaîne avec les caractères ''%%'C','h','a','t'%%'', il ajoute automatiquement ''%%\0%%'' à la fin et il déduit donc qu'il faudra un tableau de 5 cases. Remarquez que char[] texte = "Chat"; est équivalent et que l'on peut aussi écrire char* texte = "Chat'; == C'est un pointeur == Comme l'indique le dernier type déclaration, ''%%texte%%'' sera un pointeur. En effet, comme on l'a dit dans les [[.:tableaux|tableaux]], la variable obtenue suite à la déclaration d'un tableau est un pointeur pointant sur la première case du tableau. Ici, ''%%texte%%'' pointe sur la première case du tableau ''%%{'C', 'h', 'a', 't', '\0'}%%'' et cette première cas contient un ''%%char%%'', ''%%texte%%'' est donc de type ''%%char*%%'', pointeur sur ''%%char%%''. ===== Cas d'un texte dont on ne sait pas d'avance la taille ===== On vient d'envisager la création d'un texte connu d'avance. On pouvait prévoir la place mémoire à réserver : on savait que pour ''%%"Chat"%%'' il faudrait en tout 5 cases. Mais que faire si on ne connaît pas le texte d'avance ? Si on demande un texte au clavier par exemple ? On a dit que l'on devait connaître la taille d'un tableau au moment de la compilation, mais on ne peut pas prévoir ce que l'utilisateur choisira d'écrire... == On prévoit plus grand == char texte[100]; printf("Entrez un mot : "); scanf("%s", texte); On prévoit ainsi une taille de 100 caractères en mémoire. Tenant compte du ''%%\0'%%'', cela nous permet de stocker une chaîne de 99 caractères. Supposons que l'on écrive ''%%"Chien"%%'' dans ce tableau, on obtiendra : ''%%{'C','h','i','e','n','\0', ...}%%''. Les cases suivantes sont laissées inchangées. Lors d'un affichage, C n'ira pas plus loin que ''%%\0%%'' qui marque la fin de la chaîne. Dis autrement, si on s'amuse à changer texte[12] = 'P'; Cela ne servira à rien. == scanf et le texte == Vous avez peut-être remarqué que, contrairement à une [[.:inputs|utilisation précédente]] de ''%%scanf%%'', nous n'avons écrit ici ''%%scanf("%s", texte)%%'', sans le ''%%&%%''. Pourquoi cette différence ? Je rappelle que ''%%&%%'' indique que l'on prend l'adresse de la variable transmise. Or, comme on l'a dit, ''%%texte%%'' est un pointeur, c'est une adresse. ''%%texte%%'' ne contient pas la chaîne de caractères mais l'adresse du début de la chaîne en mémoire. Donc, c'est un peu comme si ''%%&%%'' était déjà intégré. ===== Manipulation de chaînes ===== ==== En Python ==== chaine = "Tomate" n = len(chaine) # renvoie la longueur, ici 6 chaine2 = "Poire" chaine += chaine2 # chaine est modifié en # ajoutant "Poire" donc contient "TomatePoire" ==== En C ==== == longueur de chaîne == char* chaine = "Tomate"; On utilise une fonction présente dans ''%%%%'' (il faut donc penser au `#include `) C'est la fonction ''%%strlen%%'' qui compte le nombre de caractère avant d'atteindre ''%%\0%%''. À noter que le retour de la fonction ''%%strlen%%'' n'est pas de type ''%%int%%'', néanmoins C fait la conversion automatiquement de sorte que le code écrit ci-dessous est valable. int n = strlen(chaine); == concaténation == Pour concaténer ''%%chaine%%'' et ''%%chaine2%%'' et mettre le contenu dans ''%%chaine%%'' il va falloir placer les caractères de ''%%chaine2%%'' à la suite de ''%%chaine%%'' en plaçant ''%%'\0'%%'' à la fin. Il faut pour cela que ''%%chaine%%'' ait été défini en laissant assez de place. La fonction ''%%strcat%%'' de ''%%%%'' permet de le faire. char chaine[20] = "Tomate"; // défini avec de la marge char* chaine2 = "Poire"; strcat(chaine, chaine2); * ligne 1, ''%%chaine%%'' contient ''%%{'T','o','m','a','t','e',''\0', 0, 0, 0, ...}%%'' * suite à la ligne 3, ''%%chaine%%'' contiendra ''%%{'T', 'o', 'm', 'a', 't', 'e', 'P', 'o', 'i', 'r', 'e', '\0', 0, 0 ...}%%'' == comparaison == chaine == chaine2 Comme ''%%chaine%%'' et ''%%chaine2%%'' sont des adresses mémoires, en faisant cela, on compare les adresses, pas les contenus. Si on veut comparer les contenus, il faut parcourir les deux tableaux de caractères (chaînes de caractères) et vérifier s'ils sont les mêmes, en ne tenant compte que de ce qui précède ''%%'\0'%%''. On utilise ''%%strcmp(chaine, chaine2)%%''. == appartenance == Pour savoir si un caractère ''%%c%%'' est contenu dans ''%%chaine%%'', on utilisera strchr(chaine, c) // renvoie l'indice de c dans chaine ou NULL si pas trouvé === Bibliothèque ''%%%%'' === Ce ne sont là que des exemples. Pour en savoir plus il faut consulter le manuel de la bibliothèque. ===== Encodage ===== C reconnaît l'utf8 mais la chaîne étant vue comme un tableau de ''%%char%%'', il peut se produire des comportements surprenants. char texte[100] = "Éléphant"; Les caractères ''%%É%%'' et ''%%é%%'' vont être encodé par 2 octets, donc 2 char. Cela signifie que ces caractères occuperont 2 cases du tableau. D'ailleurs ce code génère une erreur : char c = 'é'; En effet, le codage de ''%%'é'%%'' nécessite deux octets et donc un variable de type ''%%char%%'' ne va pas suffire. == problème avec strlen == La fonction ''%%strlen%%'' ne tient pas compte de l'encodage. Cette fonction ne compte par le nombre de caractères composant la chaîne mais le nombre d'octets, c'est à dire le nombre de ''%%char%%'', or comme on vient de le dire, le caractère ''%%'é'%%'' consomme deux cases, deux ''%%char%%''. Pour coder ''%%"Éléphant"%%'' il faut 10 octets (2 octets pour ''%%'É'%%'' et 2 octets pour ''%%'é'%%'') si bien que ''%%strlen(texte)%%'' renvoie 10 au lieu du 8 que l'on aurait espéré en comptant les lettres. == contenu == Autre situation qui peut surprendre : si on énumère le contenu de ''%%texte%%'' char texte[100] = "Éléphant"; for (int i=0; i<10; i++){ printf("%c\n", texte[i]); } // retourne à l'écran dans l'ordre � � l � � p h a n t On voit apparaître le contenu de ''%%texte%%'' découpé en ''%%char%%'' et comme on peut s'y attendre, ''%%'É'%%'' est découpé en deux ''%%char%%'' qui sont affichés comme des caractères inconnus. On peut aussi afficher les ''%%char%%'' en tant que nombres : char texte[100] = "Éléphant"; for (int i=0; i<10; i++){ printf("%02x\n", (unsigned char)texte[i]); } // retourne à l'écran dans l'ordre c3 89 6c a9 70 68 61 6e 74 Dans ce cas on convertit le ''%%char%%'' en ''%%unsigned char%%'' car on ne veut pas d'un nombre signé et on demande un affichage en hexadécimal ''%%"%02x"%%''. Les deux premiers octets ''%%c3 89%%'' correspondent bien au codage utf8 de ''%%'É'%%'', ''%%6c%%'' code ''%%'l'%%'' et ''%%a9 70%%'' code le ''%%'é'%%'', etc. Heureusement, la fonction ''%%printf%%'' gère le codage utf8 et donc printf("%s\n, texte) affiche le contenu de ''%%texte%%'' sans problème.