2015-07-26 2 views
0

J'ai un projet, et on m'a donné un fichier d'en-tête qui contient:C Copie à un const char *

typedef struct User_struct { 
    const char *name; 
    Friends amigos; 
} User; 

Amis est un autre struct qui ne sont pas dans le cadre de ma question

En un fichier source que je dois créer, je fait une variable globale struct et ultérieure:

typedef struct UserList{ 
     User *user; 
     struct UserList *next; 
}UserList; 

static UserList *users; 

Il y a une fonction d'initialisation create_amigonet dans laquelle j'allouer de la mémoire à users et un Autre attribution à users->user. Mon problème est avec cette fonction:

void addUser(const char *name) 
{ 
     UserList *new_users; 
     UserList *iter; 

     if(users->user->name == NULL) 
     { 
       users->user->name = malloc(strlen(name)); 
       strncpy((users->user->name,name,strlen(name)); 
       return; 
     } 

     for(iter = users; iter != NULL; iter = iter->next) 
     { 
       if(iter->user->name == name) 
         return; 
     } 

     new_users = malloc(sizeof(UserList)); 
     if(new_users != NULL) 
     { 
       new_users->user = malloc(sizeof(User)); 
       new_users->user->name = malloc(sizeof(name)+1); 
       strncpy(new_users->user->name,name,sizeof(name)+1); 
       new_users->user->amigos = NULL; 
       new_users->next = users; 
       users = new_users; 
     } 
     return; 
} 

J'ai besoin de copier un const char * dans un const char *, et je ne suis pas autorisé à modifier la définition de la structure de l'utilisateur ou la fonction. Je ne sais pas comment je suis censé copier/initialiser les noeuds dans ma structure. Je peux changer UserList, qui est une structure que j'ai créée comme une liste liée des «utilisateurs».

+4

'sizeof (nom) + 1' n'est pas la longueur de la chaîne, utilisez' strlen (nom) + 1' – ryanpattison

+0

Merci. Je l'ai déjà remarqué et changé, mais c'est très apprécié! – mmf1102

Répondre

2

Cela va conduire à un problème:

users->user->name = malloc(strlen(name)); 
strncpy((users->user->name,name,strlen(name)); 

Il semble que vous ne connaissez pas terminaison null. Imaginez que vous voulez lire plus tard sur users->user->name. Comment saurez-vous quand le nom se termine? Vous n'avez pas enregistré les informations strlen(name) n'importe où.

Pour cette raison, les chaînes dans C ont un marqueur à la fin de celles-ci. Ce marqueur est un octet nul (octet de valeur 0). Ensuite, les fonctions de gestion de chaîne savent où se trouve la fin de la chaîne (et généralement, la fin de la mémoire allouée).

Vous avez donc besoin d'allouer un octet supplémentaire, et utiliser une fonction de copie correcte:

users->user->name = malloc(strlen(name) + 1); 
strcpy(users->user->name, name); 

En règle générale, ne jamais utiliser strncpy. La fonction strcpy ou snprintf est plus appropriée. strncpy est une relique de jadis.

Vous avez un similaire (mais pire, puisque vous avez utilisé sizeof sans vraiment comprendre ce que fait sizeof) plus tard dans votre programme. J'espère que vous pouvez maintenant régler cela aussi, après avoir lu ma réponse.

Je dois copier un const char * en const char *,

Vous devez cesser de penser à un pointeur comme "contenant" quoi que ce soit. Les pointeurs pointent vers d'autres parties de la mémoire qui doivent, en elles-mêmes, exister.

Vous devez copier des octets d'un endroit à un autre, où vous avez des pointeurs vers les deux emplacements.

Maintenant, vous ne pouvez pas écrire à un emplacement via un const char *. C'est pour cela que const est pour. Cependant, l'emplacement est et non en mémoire morte: vous venez de le mettre en place. Donc, l'emplacement est certainement sûr d'écrire.Vous avez juste besoin de réorganiser votre code afin de passer un pointeur non-const à la fonction d'écriture. Une façon de le faire serait:

char *new_name = malloc(strlen(name) + 1); 
strcpy(new_name, name); 
users->user->name = new_name; 

Une autre façon, si vous êtes sur un système POSIX, serait:

users->user->name = strdup(name); 

qui a le même effet.

+0

'strdup' ne fera pas non plus de copie quand' malloc' échoue, ce qui est une vérification de l'OP manqué. – ryanpattison

+0

Ceci est probablement faux: 'if (iter-> user-> name == name)'. Il devrait utiliser 'strcmp (3)' à la place. –

+0

Merci. Je connais déjà sizeof et le caractère nul. J'ai accidentellement mis en place le code avant de le changer, et je suis conscient des différences, juste une faute de faire des choses stupides avec mon code. Vous avez cependant répondu à ma question sur la copie. – mmf1102