les chaînes de passer par référence en C
J'ai de la difficulté à comprendre comment les chaînes de passer en arrière à travers les paramètres d'une fonction. Je suis nouveau en programmation, donc j'imagine que c'est probablement une question de débutant. Toute aide que vous pourriez donner le plus apprécié. Ce code seg défauts, et je ne sais pas pourquoi, mais je donne mon code pour montrer ce que j'ai jusqu'à présent.
J'ai fait un wiki de la communauté, alors n'hésitez pas à modifier.
P. S. C'est pas devoirs.
C'est la version originale
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void
fn(char *baz, char *foo, char *bar)
{
char *pch;
/* this is the part I'm having trouble with */
pch = strtok (baz, ":");
foo = malloc(strlen(pch));
strcpy(foo, pch);
pch = strtok (NULL, ":");
bar = malloc(strlen(pch));
strcpy(bar, pch);
return;
}
int
main(void)
{
char *mybaz, *myfoo, *mybar;
mybaz = "hello:world";
fn(mybaz, myfoo, mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
}
Mise à JOUR Voici une version mise à jour avec quelques-uns des suggestions de mise en œuvre:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINE 1024
void
fn(char *baz, char **foo, char **bar)
{
char line[MAXLINE];
char *pch;
strcpy(line, baz);
pch = strtok (line, ":");
*foo = (char *)malloc(strlen(pch)+1);
(*foo)[strlen(pch)] = '\n';
strcpy(*foo, pch);
pch = strtok (NULL, ":");
*bar = (char *)malloc(strlen(pch)+1);
(*bar)[strlen(pch)] = '\n';
strcpy(*bar, pch);
return;
}
int
main(void)
{
char *mybaz, *myfoo, *mybar;
mybaz = "hello:world";
fn(mybaz, &myfoo, &mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
free(myfoo);
free(mybar);
}
pour votre strtok erreur de regarder ma suggestion ci-dessous
OriginalL'auteur |
Vous devez vous connecter pour publier un commentaire.
Première chose, ceux mallocs devrait être pour
strlen(whatever)+1
octets. C cordes ont un caractère 0 pour indiquer la fin, appelé le NUL de terminaison, et il n'est pas inclus dans la longueur mesurée par strlen.Prochaine chose, strtok modifie la chaîne que vous êtes à la recherche d'. Vous êtes en passant un pointeur vers une chaîne qui vous n'êtes pas autorisé à modifier (vous ne pouvez pas modifier les chaînes littérales). Que pourrait être la cause de l'erreur de segmentation. Donc, au lieu d'utiliser un pointeur pour les non-modifiable littéral de chaîne, vous pouvez le copier sur votre propre, modifiable tampon, comme ceci:
Ce que ce fait est de mettre une taille 12 char tableau sur la pile, et de copier les octets de la chaîne de caractères littérale dans ce tableau. Cela fonctionne parce que le compilateur sait, au moment de la compilation, combien de temps la chaîne est, et de faire de la place en conséquence. Cela permet d'économiser à l'aide de malloc pour cette copie.
Le problème que vous avez avec les références, c'est que vous êtes en train de passer le valeur de mybaz, myfoo, et mybar dans votre fonction. Vous ne pouvez pas modifier l'appelant variables, sauf si vous passez un pointeur à myfoo et mybar. Depuis myfoo est un char*, un pointeur, c'est un char**:
La modification de foo dans la fonction dans votre code n'a absolument aucun effet sur
myfoo
.myfoo
est non initialisée, donc, si aucune des deux premières choses qui est à l'origine, l'erreur est plus probable que se produise lorsque vous venez à imprimer à l'aide que non initialisée pointeur.Une fois que vous avez fondamentalement de travail, vous voudrez peut-être ajouter quelques erreurs de manipulation.
strtok
peut retourner la valeur NULL s'il ne trouve pas le séparateur, il est à la recherche pour, et vous ne pouvez pas appelerstrlen
avec la valeur NULL.malloc
peut retourner la valeur NULL si il n'y a pas assez de mémoire, et vous ne pouvez pas appelerstrcpy
avec la valeur NULL.Oui, désolé. J'ai seulement remarqué que mon "deuxième chose" après le premier couple de versions de ma réponse. J'espère que je l'ai expliqué.
OriginalL'auteur
Une chose que tout le monde est sur, c'est que vous êtes d'appel strtok sur un tableau stocké dans const mémoire. strtok écrit au tableau de passer alors assurez-vous de le copier dans un tableau temporaire avant d'appeler strtok ou allouer l'original comme:
Ensemble, nous sommes l'Uber-esprit! Aucune question ne peut résister à la participation citoyenne, le puissant inter... c'était quoi, ça, intneglect? Eh bien, quelque chose comme ça.
LOL! Je voulais dire comme un tackon. Il y avait quelques choses de mal que tout le monde est noté 🙂
OriginalL'auteur
En C, vous passent par référence à l'passant 1) un pointeur du premier élément du tableau, et 2) la longueur du tableau.
La longueur de la matrice peuvent être omises parfois si vous êtes sûr de votre taille de la mémoire tampon, et l'on pouvait connaître la longueur de la chaîne à la recherche d'un null caractère (personnage avec la valeur de 0 ou
'\0'
.Il semble à partir de votre exemple de code que vous tentez de définir la valeur de ce pointeur pointe. Donc, vous voulez probablement un
char**
pointeur. Et vous voulez passer l'adresse de votrechar*
variable(s) que vous souhaitez définir.OriginalL'auteur
Ooh oui, petit problème.
En règle générale, si vous allez être de manipulation de chaînes de caractères à partir de l'intérieur d'une fonction, le stockage de ces chaînes avaient mieux être en dehors de la fonction. La façon simple d'y parvenir est de déclarer des tableaux à l'extérieur de la fonction (par exemple, dans
main()
) et de passer les tableaux (qui deviennent automatiquement des liens vers leurs débuts) à la fonction. Cela fonctionne très bien tant que vos chaînes de résultat ne déborde pas de l'espace alloué dans les tableaux de.Que vous avez passé le plus polyvalent, mais un peu plus difficile de la route: Vous utilisez
malloc()
pour créer de l'espace pour vos résultats (bon pour l'instant!) et puis essayez d'attribuer le malloc avait de l'espace pour les pointeurs que vous transmettez. Qui, hélas, ne fonctionnera pas.Le pointeur à venir est une valeur; vous ne pouvez pas le changer. La solution est de passer un pointeur vers un pointeur, et de l'utiliser à l'intérieur de la fonction à modifier ce que le pointeur pointe.
Si vous l'avez compris, la grande. Si non, veuillez demander plus de précisions.
Droit vous, fixe!
OriginalL'auteur
Vous êtes désireux de passer à 2 pointeurs. Si vous avez besoin de l'appeler avec une paire de pointeurs sur des pointeurs. Quelque chose comme ceci:
malloc()
! BOO-JE DIRE!Vous savez, j'ai fait que de sortir de l'habitude depuis si longtemps, j'avais cessé de penser à elle. Merci pour le coup de coude de revoir ce peu de connaissances.
OriginalL'auteur
le code susceptible de segmentation parce que vous êtes l'allocation de l'espace pour la chaîne, mais en oubliant qu'une chaîne est un octet supplémentaire sur la fin, le terminateur null.
Aussi, vous êtes seulement en passant un pointeur. Depuis un pointeur est une valeur de 32 bits (sur une machine 32 bits) vous êtes tout simplement en passant la valeur de la unitialised le pointeur dans le "fn". De la même manière, vous ne serait pas expact un entier passé dans une fonction pour être retourné à l'appel de la fonction (sans explicitement le retour) vous ne pouvez pas s'attendre à un pointeur à faire de même. Donc les nouvelles valeurs de pointeur sont jamais retournée à la fonction principale. Habituellement, vous faites cela en passant un pointeur vers un pointeur dans C.
Aussi, ne pas oublier de libérer la mémoire allouée dynamiquement!!
OriginalL'auteur
D'autres réponses décrivent comment résoudre votre réponse à la de travail, mais d'une manière facile à accomplir ce que vous moyen à faire est de strdup(), qui alloue de la mémoire de la taille et de la copie les caractères corrects.
Encore besoin pour résoudre l'affaire avec char* vs char**, bien que. Il n'y a aucun moyen de contourner cela.
OriginalL'auteur
Le problème essentiel est que, bien que le stockage est jamais alloué (avec
malloc()
) pour les résultats que vous essayez de revenir en tant quemyfoo
etmybar
, les pointeurs vers ces allocations ne sont pas renvoyés àmain()
. En conséquence, l'appel ultérieur pourprintf()
est tout à fait susceptible de vider de base.La solution est de déclarer les arguments ponter de pointeur de
char
, et de transmettre les adresses demyfoo
etmybar
àfn
. Quelque chose comme ceci (non testé) devrait faire l'affaire:N'oubliez pas le gratuit chaque chaîne alloué à un moment plus tard, ou vous allez créer des fuites de mémoire.
À faire à la fois la fonction malloc() et la fonction strcpy() dans un appel, il serait préférable d'utiliser
strdup()
, comme il se souvient aussi d'allouer de la place pour la résiliation de NUL qui vous gauche de votre code écrit.*foo = strdup(pch)
est beaucoup plus claire et plus facile à entretenir que les autres. Depuisstrdup()
est POSIX et pas en C ANSI, vous pourriez avoir besoin pour mettre en œuvre vous-même, mais l'effort est bien remboursé par la clarté pour ce type d'utilisation.L'autre de façon traditionnelle pour retourner une chaîne de caractères à partir d'une fonction en C pour l'appelant d'allouer du stockage et de fournir son adresse à la fonction. C'est la technique utilisée par
sprintf()
, par exemple. Il souffre du problème qu'il n'y a aucun moyen de faire un tel appel site complètement sûr contre la saturation de la mémoire tampon de bugs causés par la fonction appelée en supposant de plus d'espace a été alloué que ce qui est réellement disponible. La réparation traditionnelles pour résoudre ce problème est d'exiger que la longueur de la mémoire tampon argument également être transmis, et soigneusement valider à la fois l'affectation réelle et la longueur revendiquée sur le site d'appel dans l'examen du code.Edit:
Les réels erreur que vous obtenez est susceptible d'être à l'intérieur de
strtok()
, pasprintf()
parce que votre échantillon, comme l'écrit est d'essayer de passer une chaîne de caractères constante destrtok()
qui doit être en mesure de modifier la chaîne. C'est officiellement un Comportement Indéfini.Le correctif de ce problème est de faire en sorte que
bybaz
est déclaré comme un tableau initialisé, et non pas comme un pointeur verschar
. L'initialisation de tableau sera situé dans l'écriture de la mémoire, tandis que la constante de chaîne est susceptible d'être situé dans le mémoire en lecture seule. Dans de nombreux cas, les constantes de chaîne sont stockés dans la même partie de la mémoire utilisée pour contenir le code exécutable lui-même, et des systèmes modernes de tous les essayer pour le rendre plus difficile pour un programme pour modifier son propre code en cours d'exécution.Dans les systèmes embarqués je travaille pour vivre, le code est susceptible d'être stocké dans une ROM d'une certaine sorte, et ne peut pas être physiquement modifiés.
OriginalL'auteur