Je pense que j'ai un problème pour comprendre les chaînes et les chaînes littérales.
C'est ce que j'ai appris de ma classe, en passant à une fonction, const char * indique qu'il s'agit d'une chaîne littérale, tandis que char * indique une chaîne.
Supposons que j'ai une déclaration struct:
strcpy(input_node->name, input_name);// Suppose it's safe in this case.
et une fonction, voici la fonction que je veux implémenter:
input_node->name = input_name;
Cette fonction est censée affecter input_name au nom de membre de la structure.
Ma confusion vient de là. Dans le corps de load_buffer, dois-je écrire:
void load_buffer(struct node *input_node, char *input_name);
Ou dois-je utiliser strcpy / strncpy pour faire cela?
struct node{ char *name; struct node *next; };
Pour résumer, je ne sais pas si je devrais utiliser l'affectation directe ou les fonctions de la famille strcpy pour attribuer une chaîne / chaîne littérale au membre de ma structure.
Merci pour votre aide. :)
3 Réponses :
En cas d'assignation de pointeur, les pointeurs de chaque nœud pointeront vers le même emplacement. Ainsi, les nœuds pointeront toujours vers la valeur mise à jour. Si vous avez l'intention de faire en sorte que chaque nœud contienne une entrée
différente, cette approche ne répond pas à vos besoins.
input_node->name = malloc(strlen(input_name)+1); //Allocate memory first. strcpy(input_node->name, input_name);// Suppose it's safe in this case.
Dans le cas de strcpy
, les pointeurs de chaque nœud pointeront vers un emplacement différent. Avant cela, vous devez créer de la mémoire pour chaque pointeur.
input_node->name = input_name;
vous faites malloc ()
, vous devez free ()
.
... lors du passage à une fonction,
const char *
indique qu'il s'agit d'un littéral de chaîne, tandis quechar *
indique une chaîne.Pas exactement.
const char *
déclare que la fonction n'essaiera pas de modifier la chaîne. Il convient donc parfaitement aux chaînes littérales car elles ne peuvent pas être modifiées.Pour votre question, la réponse est cela dépend de vos besoins réels . Mais simplement stocker le pointeur passé s'il est dangereux si la structure peut persister après la fonction et si la chaîne peut être modifiée dans l'appelant. Regardons le code suivant:
void load_buffer(struct node *input_node, const char *input_name) { input_node->name = strdup(name); // allocation errors should be tested... }Les deux objets
node
auront leur membrename
pointant vers la chaîne buf de l'appelant et pointeront tous les deux sur"bar"
(le contenu debuf
à la fin de la boucle)!Si vous souhaitez conserver la valeur de la chaîne au moment de l'appel, vous devez la copier dans la mémoire allouée:
void load_buffer(struct node *input_node, const char *input_name) { input_node->name = name; } struct node nodes[2]; char buf[4]; const char *data[] = { "foo", "bar"}; for (int i=0; i<2; i++) { strcpy(buf, data[i]); // suppose it is read from somewhere (file, stdin, socket) load_buffer(node + i, buf); }Mais vous devez alors libérer le
nom code> membre, lorsque le nœud n'est plus utilisé ...
D'abord à aborder une certaine terminologie:
"Je suis une chaîne littérale"
char *
(aka pointeur vers char) const char *
(aka pointer to constant char) char *
: char * str
const char *
: const char * cstr
Un pointeur n'est pas une chaîne littérale. Un pointeur peut pointer sur une chaîne littérale, un tableau, juste sur un seul élément ou peut être nul.
En C
, une chaîne est un tableau de caractères terminé par null. P >
En C
, vous pouvez affecter une variable char *
à un littéral de chaîne, mais la modification du littéral de chaîne est illégale, il est donc fortement conseillé de ne jamais le faire. La raison pour laquelle cela est autorisé est historique.
char* a = "asd"; // allowed, but frowned upon // a points to a string literal, so we can say a is a string // a is not a string literal char b = 'x'; char* c = &b; // c points to a single char // we cannot say c is a string char d[10] = "asd"; // d is a char array. Its content is a string, so we can say d is a string. // d is not a string literal // the string literal is copied into the array d char* e = d; // or equivalent char* e = &d[0]; // e points to a string char f[4] = {'a', 's', 'd', '\0'}; // f is an array. Its content is a string, so we can say f is a string char* g = f; // g points to a string. We can say g is a string char h[3] = {'a', 's', 'd'}; // h is an array. Its content is NOT a string, because the char array is not null terminated char* i = h; // i is not a string
Et maintenant, revoyez tout ce qui précède, mais ne remplacez pas char
par const char
et tous les commentaires sont toujours valables (sauf que `const char * a =" asd "est maintenant ok).
Et maintenant au problème en cours.
Il existe deux scénarios:
Chaque nœud a sa propre chaîne et "possède" cette chaîne. Chaque nœud est responsable de l'allocation de mémoire pour la chaîne et de la libération de cette mémoire. La chaîne vit aussi longtemps que le nœud vit. Dans ce cas, utilisez malloc
et strcpy
pour créer une chaîne pour chaque nœud. N'oubliez pas de libérer
la chaîne lorsque le nœud est détruit. C'est le scénario le plus courant et probablement ce que vous voulez.
Un nœud ne possède pas sa propre chaîne, mais pointe plutôt vers une chaîne externe. Il n'est pas permis d'allouer ni de libérer de la mémoire pour cette chaîne. Il existe une autre entité chargée de gérer la durée de vie de cette chaîne et de s'assurer que la chaîne est active au moins tant que le nœud est actif. La chaîne peut survivre au nœud sans fuite de mémoire.
Par exemple, considérez ce scénario:
input_node-> name = input_name;
devrait convenir, étant donné que leinput_name
ne change pas plus tard.Cela dépend de la sémantique que vous souhaitez: la
struct
doit-elle posséder la chaîne référencée, et comment doit-elle être allouée?Si vous avez un pointeur, vous devez le faire pointer vers un endroit valide avant d'utiliser
strcpy
. Quant à savoir lequel utiliser, cela dépend vraiment. Utiliserez-vous toujours des chaînes littérales? Avez-vous besoin de modifier les chaînes? Ajouter à eux?Non, je n'ai pas besoin de modifier la chaîne, la "chaîne" que j'utiliserai est lue à partir d'un fichier, cela indique-t-il que je devrais utiliser l'affectation directe au lieu des fonctions de la famille strcpy?
"string" sera-t-il le même pour tous les nœuds?
Non, la raison pour laquelle j'utilise des guillemets doubles pour inclure une chaîne est que je ne sais pas si je dois utiliser une chaîne ou une chaîne littérale pour décrire cette "chaîne". La chaîne / chaîne littérale réelle est par ligne qui se trouve dans mon fichier, mais cela ne fait pas partie de cette question de toute façon.
Si vous lisez une chaîne dans un fichier, vous ne pouvez pas simplement faire des affectations, car les affectations feront simplement pointer tous les pointeurs vers le même tampon (le tampon que vous lisez). Vous devez allouer de la mémoire pour chaque chaîne. Soit dynamiquement, soit transformez vos pointeurs en tableaux.