promenade dans un const * char (débutant) - C - Programmation
Marsh Posté le 01-12-2017 à 03:02:34
Je devrais pas répondre à cette heure ci, j'espère ne pas raconter de conneries...
Plusieurs choses:
Ton typedef est très mal choisi et je dirais même il est faux: Un string c'est un tableau, pas un pointeur. La différence est que pour un tableau il y a de la place pour les caractères réservés en mémoire, pour un pointeur non. Mais tu ne peux pas dire typedef char string[] car il faut indiquer une taille, hors pour un truc générique tu ne connais pas celle-ci par avance. Les typedef c'est très bien pour les trucs complexes genre pointeur de fonction, mais pour les bricolages avec les strings c'est à éviter je dirais. En plus si on lit un code avec des typedef faut toujours aller voir ce qui se cache derrière d'abord, c'est pénible et dans notre cas vraiment inutile.
*a++ correspond à *(a++), autrement dit tu incrémentes le pointeur et ensuite tu le déréférences mais tu ne fais rien avec le résultat. L'étoile est donc inutile et si tu as activé les warnings de ton compilateur (TRÈS important!) ce dernier te le dirait: warning: value computed is not used [-Wunused-value]
(Pour GCC: rajouter -Wall)
Ce que tu as écrit signifie que le pointeur est constant, pas la chaîne de caractères vers laquelle il pointe (mais dans notre cas celle-ci sera forcément constante aussi car c'est un string literal). Il faut mettre le const entre le "char" et l'étoile dans le typedef (si tu insistes là-dessus, voir ma remarque en haut): typedef char const * string;
Pour finir voici un petit exemple concernant cette promenade:
Code :
|
ou avec un tableau (string modifiable):
Code :
|
ou alternative avec un tableau et un index:
Code :
|
Tu remarquera la différenciation au niveau nom des variables entre string et pointeur (ptr).
Bon, ça fait beaucoup, j'espère ne pas avoir aggravé la confusion...
Marsh Posté le 01-12-2017 à 11:03:41
nanataw, la forme correcte de ton programme serait:
Code :
|
*a est un const char donc a est un pointeur sur un const char.
Et c'est très bien ainsi, car quand on fait
Code :
|
dans les faits, a pointe en réalité des const char et vouloir modifier la valeur d'un caractère pointé par a va déclencher une run-time error.
Alors que ce sera détecté à la compilation si l'on déclare a comme un pointeur sur un const char.
C'est toute la différence avec ce qui est fait ici:
Code :
|
a est un tableau qui initialisé par copie de la zone contenant "test". C'est le seul cas ou on n'a pas besoin de donner sa taille au tableau, RdC, car le compilateur la calcule avant de créer le tableau, à partir de la taille de ce qui doit être copié. a est ici un char[5].
De ce fait, son contenu est modifiable.
Donc
char *a = "test"; // a pointe en fait sur des chars non modifiables (dans une zone créée a la compilation), et on ne le dit pas, dangereux
const char (*a) = "test"; // a pointe en fait sur des chars non modifiables, et on le dit, OK
char a[] = "test"; // a est un char[5] créé a l'exécution, qui contient une copie de "test", donc modifiable, OK
Noter que dans tous les cas, on est la merci d'un run-time error par dépassement de la taille du tableau. Donc faire un test if (*p) avant d'avancer son pointeur peut être utile.
Dans la pratique:
J'ai une chaine "test" utilisée uniquement en lecture: const char (*a) = "test";
J'ai une chaine "test" dont certains caractères peuvent être modifié: char a[] = "test"; c'est un cas assez rare
J'ai une chaine initialisée à "test" complètement modifiable, même en taille: char *a = strdup("test'); qu'on oubliera pas de libérer avec un free après utilisation, et on fait du realloc si sa taille devient insuffisante.
Et... bien souvent
J'ai une chaine initialisée à "test" complètement modifiable, même en taille, mais dont je sais qu'elle ne sera jamais plus grande que TAILLE_MAX
char a[TAILLE_MAX+1] = "test";
(ici le compilo crée le tableau avec la taille donnée, puis fait la copie (éventuellement avec troncature si la taille du tableau est trop petite)).
L'avantage de cette technique, c'est que c'est le programme qui va gérer automatiquement la libération du tableau lorsqu'il sort du scope.
A+,
Marsh Posté le 30-11-2017 à 23:22:23
Bonsoir,
Voici le code qui m'interroge :
Si j'enlève le const ça fonctionne. *a++ m'amène à la case suivante et le printf de test l'affiche bien le char 'e'.
Quand je mets le const, j'obtiens à la compilation l'erreur suivante :
Quand j'incrémente en faisant *a++ je modifie ma chaine ? Je pensais que je me déplaçais juste dedans... normal que ça marche pas quand c'est un const ?
D'avance merci