Plantage: strchr() avec un char ** - C - Programmation
Marsh Posté le 24-11-2007 à 12:03:40
"&mot" c'est la même chose que "mot", et c'est l'adresse du premier élément du tableau. C'est assimilable à un char *, pas à un char **.
Edit : si tu as besoin de passer par un char ** (je vois pas trop pourquoi dans ton exemple, mais bon), fait toi un variable "char *motptr = mot;" et passes &mot à ta fonction.
Marsh Posté le 24-11-2007 à 12:05:11
Voici une version qui devrait mieux marcher :
Code :
|
Marsh Posté le 24-11-2007 à 12:19:49
matafan a écrit : "&mot" c'est la même chose que "mot", et c'est l'adresse du premier élément du tableau. C'est assimilable à un char *, pas à un char **. |
L'adresse du 1er élément du tableau ne serait-ce pas plutôt: &mot[0] ou mot tout court? Pour moi &mot c'est l'adresse de l'emplacement du pointeur mot. Ce qui serait équivalant à faire:
Code :
|
Je me trompe peut être?
matafan a écrit : Edit : si tu as besoin de passer par un char ** (je vois pas trop pourquoi dans ton exemple, mais bon), fait toi un variable "char *motptr = mot;" et passes &mot à ta fonction. |
Je ne comprend pas en fait là.
olivthill a écrit : Voici une version qui devrait mieux marcher :
|
Oui bien sûr que ça marche. Tu as contourné le problème en le simplifiant.
Le problème c'est que j'ai besoin de modifier le pointeur chaine. Ce petit bout de programme n'est là que pour faire apparaitre l'erreur de manière simple. Donc c'est normal que vous ne voyez pas l'intérêt de passer par un char** au lieu d'un simple char*.
Marsh Posté le 24-11-2007 à 12:23:29
Sinon voilà la vraie fonction:
Code :
|
Marsh Posté le 24-11-2007 à 13:22:30
Voici un exemple utilisant nettoyer_chaine()
Code :
|
Marsh Posté le 24-11-2007 à 13:32:30
Pour enlever le "\n" de fin de chaine, la fonction nettoyer_chaine() serait avantagement remplacée par
int right_trim(char *s) |
L'avantage est qu'il n'y a pas d'appel au realloc() qui est très lourd en ressources. En plus cette fonction enlève aussi les '\r' et les espaces en fin de chaine.
Marsh Posté le 24-11-2007 à 14:24:33
olivthill a écrit : Voici un exemple utilisant nettoyer_chaine()
|
Donc voilà. Pour moi c'est équivalant à ce que j'avais écrit:
Code :
|
Les 2 versions plantent, et pour cause elles sont toutes deux équivalentes à celle du programme de mon 1er post.
olivthill a écrit : Pour enlever le "\n" de fin de chaine, la fonction nettoyer_chaine() serait avantagement remplacée par
L'avantage est qu'il n'y a pas d'appel au realloc() qui est très lourd en ressources. En plus cette fonction enlève aussi les '\r' et les espaces en fin de chaine. |
Elle fonctionne très bien Mais mon but est seulement de transformer une chaine de cette manière:
{'b','l','a',' ','b','l','a','\n','\0'} -> {'b','l','a',' ','b','l','a','\0'}
Je récupère des chaines d'un fichier texte écrit par mon programme (donc bien formatées). Ta fonction fonctionne parfaitement pour obtenir ce résultat mais fait un travail en trop dont je n'ai pas besoin.
J'avais donc fait cette fonction:
Code :
|
Elle remplit bien son rôle et ne plante pas. Le seul problème c'est que ta fonction et cette dernière transforment en réalité les chaines de cette manière:
{'b','l','a',' ','b','l','a','\n','\0'} -> {'b','l','a',' ','b','l','a','\0','\0'}
Alors que je veux raccourcir la chaine:
{'b','l','a',' ','b','l','a','\n','\0'} -> {'b','l','a',' ','b','l','a','\0'}
C'est pour ça que je suis obligé de réallouer ma chaine, donc de la faire passer par un double pointeur pour pouvoir la modifier (sa longueur).
Donc j'en reste au même point:
- Pourquoi ma fonction (1er post) plante?
Marsh Posté le 24-11-2007 à 17:00:51
Je pense que realloc plante car il ne marche que si la chaine a été allouée précedemment par malloc ou par une fonction du même genre. Or dans l'exemple, la chaine n'est pas allouée, elle est définie sur la pile.
Par ailleurs, si vous saviez ce qu'il y a derrière realloc (et malloc aussi), vous comprendriez que c'est une hérésie de l'utiliser pour des chaines de moins de 2000 octets. Ces fonctions utilisent beaucoup de ressources CPU et de resources en mémoire, beaucoup plus que vous ne semblez le penser. Renseignez-vous. Je parle en connaissance de cause, ayant moi-même dû réécrire ce genre de fonctions pour un compilateur.
Marsh Posté le 24-11-2007 à 17:20:22
ngkreator a écrit : L'adresse du 1er élément du tableau ne serait-ce pas plutôt: &mot[0] ou mot tout court? Pour moi &mot c'est l'adresse de l'emplacement du pointeur mot. Ce qui serait équivalant à faire:
|
Oui tu te trompes
En fait le truc c'est que "mot" n'a pas d'adresse. Comme je l'ai dit, "&mot" c'est exactement la même chose que "mot" tout court, ou que "&mot[0]". C'est tout pareil. Il n'y a aucun moyen de récupérer l'adresse à laquelle l'adresse du premier élément est stockée, pour la bonne raison qu'elle n'est stockée nul part, sauf dans la mémoire du compilo puis dans le texte du programe (sous la forme d'un offset par rapport au pointeur de pile dans le cas présent).
Marsh Posté le 24-11-2007 à 17:43:54
olivthill a écrit : Je pense que realloc plante car il ne marche que si la chaine a été allouée précedemment par malloc ou par une fonction du même genre. Or dans l'exemple, la chaine n'est pas allouée, elle est définie sur la pile. |
C'est ce que j'ai pensé au début, mais d'après: http://www.cplusplus.com/reference [...] alloc.html
Citation : In case that ptr is NULL, the function behaves exactly as malloc, assigning a new block of size bytes and returning a pointer to the beginning of it. |
realloc peut être appliqué à un pointeur NULL. Alors du coup j'ai un doute. Mais après réflection, ma fonction simplifié sans realloc plante quand même. Dans les 2 cas ça plante sur strchr. Qu l'utilisation de realloc soit erronée ou pas c'est donc bien strchr qui fait planter la fonction. Mais j'attend de voir d'autre conseils pour realloc.
olivthill a écrit : |
Je veux bien vous croire Que faire alors?
matafan a écrit : |
J'ai de gros doutes là dessus. Surtout pour: &pointeur = pointeur
Par exemple ici sur le tutorial des listes chainées: http://chgi.developpez.com/pile/
Code :
|
Code :
|
Citation : La fonction reçoit comme paramètres la valeur que l'on veut mémoriser mais aussi un pointeur sur le pointeur identifiant la pile. |
Dans cet exemple un pointeur sur une structure de type pile a une adresse puisque qu'ils utilisent un pointeur sur ce pointeur. Comme on le voit il est possible d'écrire &maPile qui est l'adresse du pointeur vers la pile (pas maPile).
Donc même raisonnement avec un pointeur sur un char. Le pointeur de char n'est rien d'autre qu'un emplacement mémoire contenant l'adresse du char. Qui dit emplacement mémoire dit adresse. Donc ce pointeur de char a une adresse.
J'attends vos corrections sur ce que je viens de dire, et surtout une solution mon problème. Bon pour l'instant je continu le programme à coté mais c'est dommage de ne pas comprendre pourquoi ça ne marche pas.
Marsh Posté le 24-11-2007 à 19:36:35
ngkreator a écrit : J'ai de gros doutes là dessus. Surtout pour: &pointeur = pointeur [:pingouino. |
Ah mais j'ai pas dit "&pointeur == pointeur", j'ai dit "&tableau == tableau". Faut pas confondre tableau et pointeur, même si sur bien des points les deux sont assimilables.
Marsh Posté le 24-11-2007 à 20:04:38
matafan a écrit : |
Tu parlais de mot: pour moi mot est un pointeur dans ton post.
C'est quoi un tableau pour toi? Parce qu'un tableau ça n'existe pas en C non?
Marsh Posté le 24-11-2007 à 20:50:56
char *pointer = "bonjour" : pointeur
char array[] = "bonjour" : tableau
* et [] ce ne sont pas deux notations pour la même choses. Ce sont vraiment deux choses différentes.
Marsh Posté le 24-11-2007 à 21:47:49
ngkreator a écrit : L'adresse du 1er élément du tableau ne serait-ce pas plutôt: &mot[0] ou mot tout court? Pour moi &mot c'est l'adresse de l'emplacement du pointeur mot. |
Sauf qu'ici, 'mot' n'est pas un pointeur mais un tableau.
&mot est l'adresse d'un tableau de 8 char, et son type est (char*)[8], ce qui est très différent de char**.
Tu confonds avec :
Code :
|
Là, p est de type char const *. Tu peux passer son adresse (&p) à une fonction avec un paramètre de type char const **, ce qui permet de modifier la valeur du pointeur...
Marsh Posté le 25-11-2007 à 09:43:28
Après vos 2 derniers posts je viens d'apprendre qu'on appelle tableau un pointeur constant. Je ne savait pas que: type tab[] équivalait à type *const tab
Donc je ne peux pas modifier l'adresse d'un tableau. Donc je dois créer un pointeur pmot qui prend l'adresse du tableau. Je passe &pmot à ma fonction pour qu'elle puisse modifier ce pointeur pmot:
Code :
|
Marsh Posté le 25-11-2007 à 10:13:11
ngkreator a écrit :
|
Ca n'a aucun intérêt de raccourcir une chaine. Suite au 'nettoyage' d'une chaine modifiable, le 0 final se trouve placé à un endroit tel que la longueur de la chaine est modifiée (vérifible avec strlen()). Par contren, la taile du tableau de char est inchangée et oui, quelques byes sont inutilisables. C'est grave ?
Mais si tu y tiens, elle doit être allouée dynamiquement (tableau de char : malloc()), initialisée, puis nettoyée et enfin modifiée avec realloc().
Il ne faut lancer ce mécanisme que si ça vaut vraiment le coup (gagner des dizaines de bytes). Si c'est pour gagner 4 bytes, c'est pas la peine... D'ailleurs, il vaut mieux raisonner en, %. En dessous de 20% de gain, je dirais qu'on perd son temps...
Ton code est incomplet :
|
La forme 'canonique' est
Code :
|
Et ça donne :
Press ENTER to continue. |
Il n'y a aucun intérêt à faire plus compliqué que ça... La simplicité est souvent gage de réussite...
Marsh Posté le 25-11-2007 à 10:24:01
Ah mais j'ai oublié string.h! Je fais toujours des erreurs à la con. Ca marche avec. Merci
Mon compilateur doit être mal configuré il ne m'avait pas prévenu: j'ai aussi mingw fournit avec Codeblocks dont j'ai laissé les options par défault. Il faut que je trouve un tuto pour trouver les options à cocher.
Donc finalement tu me dis que c'est inutile de raccourcir la chaine. C'est vrai surtout que c'est une seule chaine utilisé en dehors de toute boucle.
La seule question qui me reste:
Edit: j'avais oublié stdlib aussi, mais je vois que tu les as rajoutés
Marsh Posté le 25-11-2007 à 11:01:21
ngkreator a écrit : La seule question qui me reste:
|
"&tableau == tableau" parce que c'est comme ça, c'est deux notations (avec ou sans le & ) pour désigner la même chose, à savoir l'adresse du premier élément. C'est le C, c'est comme ça et on n'y peut rien.
Ensuite je le répète, un tableau ce n'est pas la même chose qu'un pointer, fût-il conststant. Un tableau c'est une suite d'octets consécutifs en mémoire, dont l'adresse n'est stockée nul part physiquement (en fait elle est hardcodée dans le texte du programe, d'une manière où d'une autre). Un variable de type tableau n'a pas d'adresse. En fait elle n'as même pas d'existance en tant que variable. Il n'y a pas de mot mémoire où est stocké l'adresse du premier élément. Un pointeur au contraire (et le fait qu'il soit const ne change rien à l'affaire), c'est une vraie variable, avec une adresse mémoire.
Tu n'as pas l'air de vouloir me croire, donc fait l'essai toi même :
Code :
|
Et pour enfoncer encore le clou, affiche un sizeof array et un sizeof pointer. Tu verra si tableau c'est la même chose qu'un pointeur.
Marsh Posté le 25-11-2007 à 11:19:12
matafan a écrit : Tu n'as pas l'air de vouloir me croire, donc fait l'essai toi même : |
Si maintenant tu m'as convaincu. Déjà &array == array mais en plus sizeof(array) donne la taille du tableau! J'ai eu du mal mais c'est bon maintenant je te crois
Bon ben tout est limpide, enfin je crois. Un grand merci à tous!
Marsh Posté le 25-11-2007 à 11:42:14
ngkreator a écrit : Ah mais j'ai oublié string.h! Je fais toujours des erreurs à la con. Ca marche avec. Merci |
http://mapage.noos.fr/emdel/codage.htm#cfg_compilo
Citation : |
Euh, je ne vois pas le rapport...
Citation : Edit: j'avais oublié stdlib aussi, mais je vois que tu les as rajoutés |
que j'ai finalement retiré, car mon code ne l'utilise pas...
Marsh Posté le 25-11-2007 à 11:48:39
matafan a écrit :
|
C'est un pe plus subtil que ça. En fait, "&tableau == tableau" est vrai sur le plan de la valeur, mais faux sur le plan du type.
En effet, pout un tableau a de type T et de taille N, a est de type T* (adresse d'un élément), alors que &a est de type (T*)[N] (adresse d'un tableau)
Ca change tout si on utilise l'arithmétique des pointeurs :
Code :
|
Press ENTER to continue. |
Marsh Posté le 25-11-2007 à 12:13:14
Emmanuel Delahaye a écrit :
|
J'ai dit n'importe quoi. J'imaginais que dans une boucle les octets inutilement réservés à la chaine allaient s'accumuler. C'est faux.
Sinon pour les options du compilateurs:
Citation : NOTA : sur les anciennes version de gcc (< 3.4.x), remplacer -Wextra par -W |
J'ai la dernière version de gcc j'imagine puisque j'ai celle qui est fournie avec Codeblocks. Or j'ai -W mais pas -Wextra.
En plus j'ai la plupart de ces flags qui sont inexistants:
Citation : -Wall -Wextra -O -Wwrite-strings -Wstrict-prototypes -Wuninitialized |
Dans ce cas il faut les insérer manuellement dans "other option" dans Codeblocks?
Ah j'avais pas lu la suite qui parle de Codebloacks, désolé.
Marsh Posté le 25-11-2007 à 12:35:41
C'est super les warnings! On est carrément assisté avec tous ces warnings. Mais d'un coté ça m'a aidé à résoudre un problème qui me bloquait depuis hier. A savoir une variable compteur non initialisée à 0 Je fais vraiment des erreurs à la con!
Je pensais pas que les warnings prévenaient de ce genre d'erreur, c'est pas mal.
Marsh Posté le 25-11-2007 à 12:53:14
Merci pour le commentaire sur le type de "array" et "&array", ça m'échappait. En fait ça explique pourquoi array et &array ont la même valeur. C'est pas arbitraire, il y a une raison la dessous, tout est logique
Marsh Posté le 24-11-2007 à 10:57:42
Bonour je vous demande votre aide pour trouver mon erreur. Mon programme plante (fermeture de la console) sur l'utilisation de la fonction strchr().
Voilà un programme qui fait apparaitre l'erreur:
srtchr admet en argument un pointeur sur char et un entier. Dans la fonction:
chaine = pointeur sur un pointeur de char
*chaine = pointeur de char
Je ne comprends pas pour ça plante alors que j'ai bien mis un pointeur de char dans strchr()
Merci d'avance.
Message édité par ngkreator le 24-11-2007 à 11:00:26