modifier un char *

modifier un char * - C - Programmation

Marsh Posté le 28-09-2017 à 01:47:30    

Bonsoir,
Question de débutant mais qui m'intrigue pas mal ...
si je dis genre char * x = 'blabla' ; puis x[0] ='g' j'ai une erreur de segmentation... normal je peux pas modifier parce que j'utilise un pointeur pour déclarer ma variable.
Mais si je le fais sur un argument de la ldc qui pourtant est aussi un char * là ça marche je peux modifier ...  
Comment ça s'explique ?
 

Reply

Marsh Posté le 28-09-2017 à 01:47:30   

Reply

Marsh Posté le 28-09-2017 à 14:15:07    

nanataw a écrit :

normal je peux pas modifier parce que j'utilise un pointeur pour déclarer ma variable.

"blabla" est une constante, donc effectivement tu peux pas modifier.
(Entre parenthèses, si tu as vraiment utilisé des guillemets simples tu devrais te prendre une erreur de compilation, je suppose que c'est une faute d'inattention en écrivant ton message.)
 

Citation :

Mais si je le fais sur un argument de la ldc qui pourtant est aussi un char * là ça marche je peux modifier ...  
Comment ça s'explique ?

ldc? Donne un exemple pour que ce soit clair (code le plus court possible mais complet et qu'on peut compiler/exécuter).

Reply

Marsh Posté le 29-09-2017 à 01:03:55    

Citation :

Mais si je le fais sur un argument de la ldc qui pourtant est aussi un char * là ça marche je peux modifier ...  
Comment ça s'explique ?
 ldc? Donne un exemple pour que ce soit clair (code le plus court possible mais complet et qu'on peut compiler/exécuter).


 ligne de commande, je veux dire au lieu de dire char * chaine = "blabla" je lance le code compilé avec un argument (qui est aussi un char * on est d'accord, donc un const, donc normalement non modifiable)
 
 
là ça marche, je vais pouvoir remplacer le premier caractère du 2eme argument de la ligne de commande :

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. int modif(char *) ;
  5. int main(int k, char * ldc[])
  6. {
  7. puts(ldc[1]) ;
  8. if (modif(ldc[1])) {puts(ldc[1]);}
  9. else puts("pb" );
  10. return 0 ;
  11.                            }
  12. int modif(char * chaine)
  13. { chaine[0] ='h' ; 
  14.  return 1;
  15.                            }


 
Mais là ça ne marche pas (erreur segmentation) :
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. int modif(char *) ;
  5. int main()
  6. {
  7. char * test = "blabla" ;
  8. puts(test) ;
  9. if (modif(test)) {puts(test);}
  10. else puts("pb" );
  11. return 0 ; }
  12. int modif(char * chaine)
  13. { chaine[0] ='h' ; 
  14.  return 1;}


Pourtant ma variable test est de même nature que args, ce sont des char * donc pourquoi je peux modifier quand ça vient de la ldc ?
 
J'espère avoir été clair et court.
Merci beaucoup en tout cas.

Message cité 1 fois
Message édité par nanataw le 29-09-2017 à 01:08:40
Reply

Marsh Posté le 29-09-2017 à 01:38:57    

(edit: connerie :o )

nanataw a écrit :

là ça marche, je vais pouvoir remplacer le premier caractère du 2eme argument de la ligne de commande :

Pas chez moi (sous Windows), le programme se plante. J'ai pas envie de vérifier vu l'heure, mais il me semble que le standard dit qu'on peut pas modifier les arguments passés en ligne de commande, si on veut faire ça il faut faire une copie avant (exemple sur demande).
 
 
De manière générale, quelque remarques:
-Tu utilises des noms de variables inhabituels pour main. C'est pas faux, mais en principe (par convention) c'est toujours int main(int argc, char **argv) ou char * argv[], ça revient au même. Mais ce que tu fais n'est pas faux, libre à toi de modifier les noms!
-Attention à la mise en forme du code! Indentation etc. C'est important de partir sur des bonnes bases dès le début, sinon ça devient vite le bazar. :o  
-Ton code est un peu étrange, modif retournera toujours 1, en cas d'erreur de segmentation le programme est stoppé net, il n'est plus question de if et de return alors.
-C'est bien d'avoir écrit un prototype de fonction comme il faut! :)

Message cité 1 fois
Message édité par rat de combat le 29-09-2017 à 16:46:43
Reply

Marsh Posté le 29-09-2017 à 16:33:21    

rat de combat a écrit :

Pas chez moi (sous Windows), le programme se plante. J'ai pas envie de vérifier vu l'heure, mais il me semble que le standard dit qu'on peut pas modifier les arguments passés en ligne de commande, si on veut faire ça il faut faire une copie avant (exemple sur demande).
 
De manière générale, quelque remarques:
-Tu utilises des noms de variables inhabituels pour main. C'est pas faux, mais en principe (par convention) c'est toujours int main(int argc, char **argv) ou char * argv[], ça revient au même. Mais ce que tu fais n'est pas faux, libre à toi de modifier les noms!
-Attention à la mise en forme du code! Indentation etc. C'est important de partir sur des bonnes bases dès le début, sinon ça devient vite le bazar. :o  
-Ton code est un peu étrange, modif retournera toujours 1, en cas d'erreur de segmentation le programme est stoppé net, il n'est plus question de if et de return alors.
-C'est bien d'avoir écrit un prototype de fonction comme il faut! :)


 
Merci pour tes remarques. oui code un peu étrange mais c'est juste parce que j'ai juste isolé la question que je me pose qui est que d'après ce que j'ai compris je peux pas modifier un char *  mais on peut modifier un char x[]  
Tu lances bien le code compilé avec un argument ? genre moi avec mon premier exemple quand "nomduscript argument", moi si je fais ça j'obtiens bien "argument hrgument"
Faudrait que je teste sous windows pour voir.
Du coup si ça marche pas sous windows, la solution serait de copier char * argv dans un char copieargvs[] de la taille de char * argv pour pouvoir le modif tranquillement ?

Reply

Marsh Posté le 29-09-2017 à 16:45:33    

nanataw a écrit :

Tu lances bien le code compilé avec un argument ?

Je devrais vraiment pas poster à 1h du mat'. J'avais pas mis d'argument, avec argument ça marche. Et en tout cas en C99 on peut modifier les arguments à priori: https://stackoverflow.com/questions [...] modifiable
 
Désolé pour les conneries de ma part. :o :o :o

Reply

Marsh Posté le 29-09-2017 à 16:55:29    

rat de combat a écrit :

Je devrais vraiment pas poster à 1h du mat'. J'avais pas mis d'argument, avec argument ça marche. Et en tout cas en C99 on peut modifier les arguments à priori: https://stackoverflow.com/questions [...] modifiable
 
Désolé pour les conneries de ma part. :o :o :o


 
Aucun souci !  Mais alors pourquoi ça marche ? Alors que pourtant c'est bien un char * ? et pourtant ça marche pas si je déclare mon char * dans le code ? Tu sais ?

Reply

Marsh Posté le 29-09-2017 à 17:15:52    

Pour répondre à tes questions, en espérant ne pas me tromper cette fois... :o  

Citation :

d'après ce que j'ai compris je peux pas modifier un char *  mais on peut modifier un char x[]

Non. Tu peux modifier toute chaîne de caractère ("string" ) qui n'est pas un "literal", autrement dit constant (ou déclaré comme tel). La différence entre char* et char[] c'est que c'est pas la même chose: char* est un pointeur, tu réserves donc de la place en mémoire pour y placer une adresse, mais pas de place pour mettre des chars (caractères). Avec char x[42] tu réserves au contraire de la mémoire à une adresse qui sera placée dans x. x est un tableau mais peut devenir un pointeur (quand on le passe comme argument à une fonction p.ex.). Si je passe x à une fonction je "reçois" un char* - mais je peux bien sûr modifier la chaîne de caractère vers laquelle pointe x!

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. void modif(char *);
  4. void pas_modif(char const *);
  5. int main(int argc, char **argv)
  6. {
  7.     char *constant="abc123"; //constant contient l'adresse mémoire où se trouve "abc123". C'est un "string literal", on ne peut pas modifier.
  8.    
  9.     //constant[0]='A'; //BOUM!
  10.    
  11.     char pas_constant[]="abc123"; //pas_constant est un tableau, un "bout" de mémoire (de taille 7 octets d'ailleurs, il y a un '\0' à la fin du string!) qui est initialisé avec "abc123" et qu'on peut modifier comme on veut. pas_constant peut devenir un pointeur et contient alors l'adresse de ce bout de mémoire.
  12.    
  13.     pas_constant[0]='A'; //ok
  14.     printf("%s\n", pas_constant);
  15.    
  16.     char *pointeur=pas_constant; //pointeur contient l'adresse mémoire de notre espace réservé en haut. On peut modifier cet espace en utilisant pointeur.
  17.    
  18.     printf("adresses: %p %p\n", pas_constant, pointeur);
  19.     pointeur[0]='B'; //ok
  20.     printf("%s %s\n", pointeur, pas_constant); //même adresses mémoire -> même affichage
  21.    
  22.     modif(pas_constant); //pas_constant devient un pointeur, on aurait pû écrire modif(pointeur) aussi.
  23.    
  24.     printf("%s\n", pas_constant);
  25.    
  26.     return 0;
  27. }
  28. void modif(char *pointeur)
  29. {
  30.     pointeur[0]='X';
  31. }
  32. void pas_modif(char const * pointeur)
  33. {
  34.     //pointeur[0]='X'; //pas bon - on a dit que le contenu de la mémoire vers lequel pointe notre pointeur ne sera pas modifié (const), donc là le compilateur râle. C'est une sécurité, si on veut pas modifier le contenu on peut dire au compilateur de faire attention et de refuser le boulot si on se trompe et on qu'on essaye de faire une modification par accident. Par contre on pourrait modifier le contenu de pointeur qui est une adresse. Il ne faut pas confondre ce que contient pointeur (une adresse) et ce vers quoi pointe pointeur (un espace mémoire identifié par cette adresse).
  35. }


 
En espérant ne pas créer de confusion supplémentaire... :o Les pointeurs etc c'est pas forcément évident mais très important en C.
 
Autre chose, tu as activé les warnings sur ton compilateur? Très utile et je dirais même obligatoire, surtout pour un débutant! Pour GCC: Rajouter -Wall en ligne de commande (voire -Werror aussi pour s'arrêter au moindre problème).

Reply

Marsh Posté le 29-09-2017 à 17:18:04    

nanataw a écrit :

Aucun souci !  Mais alors pourquoi ça marche ? Alors que pourtant c'est bien un char * ? et pourtant ça marche pas si je déclare mon char * dans le code ? Tu sais ?

Voir ma réponse juste au dessus. Il ne faut pas se fixer sur char* et char[]. Les arguments du programme ne sont pas considérés comme des "literal", donc on peut (à priori, cf lien avec la citation du standard C99) les modifier. Certes tu as un char* (qui en soit est un pointeur qui ne "réserve" pas de place pour des chars en mémoire) pour les arguments mais il y a bien de la place mémoire réservée quelque part et qui contient les arguments, c'est automatique quand on lance le programme (et ton char* pointe vers cet espace mémoire).

 

(Sachant que on a en fait un double pointeur pour argc ou un tableau de pointeurs si on veut, car on a / peut avoir plusieurs arguments.)

Message cité 1 fois
Message édité par rat de combat le 29-09-2017 à 17:22:27
Reply

Marsh Posté le 01-10-2017 à 01:48:47    

rat de combat a écrit :

Voir ma réponse juste au dessus. Il ne faut pas se fixer sur char* et char[]. Les arguments du programme ne sont pas considérés comme des "literal", donc on peut (à priori, cf lien avec la citation du standard C99) les modifier. Certes tu as un char* (qui en soit est un pointeur qui ne "réserve" pas de place pour des chars en mémoire) pour les arguments mais il y a bien de la place mémoire réservée quelque part et qui contient les arguments, c'est automatique quand on lance le programme (et ton char* pointe vers cet espace mémoire).
 
(Sachant que on a en fait un double pointeur pour argc ou un tableau de pointeurs si on veut, car on a / peut avoir plusieurs arguments.)


 
J'ai compris ! Merci beaucoup pour ces explications claires et détaillées, et tous tes conseils.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed