2 votes

L'affectation d'un élément de données char*[] struct donne lieu à un avertissement

J'ai une structure qui contient une valeur de type char*[]. Elle est définie comme suit :

struct background_element
{
    pid_t pid;
    int number;
    char *full_command[MAX_ARGS];
};

J'ai également une variable globale char*[], args.

char *args[MAX_ARGS];

J'essaie de créer une nouvelle variable de type struct background_element et d'y affecter la valeur full_command comme suit :

struct background_element bg_elem = { .pid = child, .number = num_background, .full_command = args};

Cependant, l'affectation des args à .full_command semble provoquer cet avertissement : "Avertissement : initialisation à partir d'un type de pointeur incompatible".

J'ai essayé d'utiliser strcpy, mais comme il ne s'agit pas de char[] mais de char*[], cela ne semble pas fonctionner. Je suis un peu perdu sur la façon d'assigner cela. Toute aide serait appréciée.

2voto

ejohnso49 Points 377

Comme l'a dit @user3386109, c'est parce que char *full[MAX_ARGS] ne peut pas être affecté. Il y a deux chemins à partir d'ici, selon votre scénario. Si args ne va pas être modifié, que ce soit par un autre code ou par la libération de ses éléments de chaîne, alors nous pouvons simplement pointer les éléments de full_command vers eux comme ceci :

struct background_element bg_elem = {.pid = child, .number = num_background};
for (unsigned int i = 0; i < MAX_ARGS; i++) {
    bg_elem.full_command[i] = args[i];
}

Si toutefois vous devez copier les chaînes, vous devrez utiliser malloc pour créer de l'espace pour les chaînes, puis strcpy pour copier les données :

for (unsigned int i = 0; i < MAX_ARGS; i++) {
    int str_len = strlen(args[i]);
    bg_elem.full_command[i] = malloc((str_len + 1) * sizeof(char));
    strcpy(bg_elem.full_command[i], args[i]);
}

La boucle for ci-dessus en premier lieu :

  1. Obtenir la longueur du ième arg
  2. Allouer suffisamment de mémoire au ième pointeur de bg_elem.full_command
    • Nous avons besoin str_len + 1 car nous avons besoin d'espace pour le caractère nul
  3. Copier la chaîne de caractères de args dans bg_elem.full_command

Enfin, si vous avez besoin de copier les chaînes de caractères de args, n'oubliez pas d'itérer et de libérer la mémoire à la fin lorsque vous avez terminé.

for (unsigned int i = 0; i < MAX_ARGS; i++) {
    free(bg_elem.full_command[i]);
}

Note : Si vous avez besoin que la mémoire que vous copiez soit mise à zéro, calloc serait préférable. Cependant, comme nous utilisons strcpy, malloc fonctionne parfaitement.

1voto

AndreyT Points 139512

En C, les objets de type tableau sont limités à deux types d'initialisateurs :

  1. {} c'est-à-dire une paire d'initialisateurs fermés. {} avec des initialisateurs individuels pour les éléments du tableau à l'intérieur de
  2. Caractères littéraux de la chaîne de caractères pour char [] tableaux.

Votre initialisateur n'entre dans aucune de ces catégories. Il n'est pas valide. Vous ne pouvez pas initialiser un tableau par un autre tableau (sauf dans le cas 2 ci-dessus).

Formellement, vous pouvez l'énoncer explicitement

struct background_element bg_elem = 
{ 
  .pid = child, 
  .number = num_background, 
  .full_command = { args[0], args[1], /* ... and so on */ }
};

mais cette approche n'est pas vraiment viable. Une bien meilleure idée serait

struct background_element bg_elem = 
{ 
  .pid = child, 
  .number = num_background
};

static_assert(sizeof bg_elem.full_command == sizeof args, "");
memcpy(bg_elem.full_command, args, sizeof args);

bien qu'il puisse souffrir un peu du problème de la "double initialisation".

P.S. Ce que vous essayez de faire s'appelle l'initialisation , pas affectation . L'affectation est une chose très différente en C.

0voto

Kamil Cuk Points 11578
char *args[MAX_ARGS];

args est un tableau de pointeurs MAX_ARGS. args pointe elle-même vers la mémoire du premier pointeur. args contient l'adresse mémoire dans laquelle se trouve le premier pointeur. args[0] est la valeur du premier pointeur. args[0][0] signifie que nous allons dans la mémoire du premier pointeur, puis à l'adresse mémoire pointée par ce pointeur, et que nous obtenons la valeur du premier octet dans cette adresse mémoire.

char *full_command[MAX_ARGS];

Il s'agit également d'un tableau de pointeurs MAX_ARGS. full_command pointe vers la région de mémoire qui est MAX_ARGS * sizeof(char*) octets longueur. full_command[0] est la valeur du premier pointeur à l'intérieur de cette région de mémoire.
Essayons maintenant l'affectation :

full_command = args;

Nous obtenons maintenant la valeur de l'adresse mémoire du premier pointeur dans args et assigner cette valeur à full_command variable. La mémoire de full_command est perdu, il n'est plus accessible par aucune autre poignée. Maintenant, le args[0] = smth uniquement et seulement si full_command[0] = smth . full_command pointe vers la région de mémoire que args pointe vers.
Pour copier les VALEURS d'un tableau, vous devez copier chaque VALEUR du tableau :

for (size_t i = 0; i < MAX_ARGS; ++i) { 
     full_command[i] = args[i];
}

ou en utilisant memcpy :

memcpy(full_command, args, sizeof(full_command));

Après cette opération full_command pointe vers une région différente qui args Les deux sont sizeof(char*) * MAX_ARGS octets. Ils contiennent tous deux les mêmes valeurs.
Vous devez assigner chaque valeur du tableau :

struct background_element bg_elem = {
   .pid = child, 
   .number = num_background, 
   .full_command = { args[0], args[1], args[2], ....<up until MAX_ARGS> }, 
};

Ce n'est pas très utile, il faut le modifier à chaque fois que MAX_ARGS change. Il faut donc utiliser memcpy ou une boucle :

struct background_element bg_elem = {
    .pid = child, 
    .number = num_background, 
};
memcpy(bg_elem.full_command, args, sizeof(bg_elem.full_command));

0voto

lockcmpxchg8b Points 1624

Les réponses ci-dessus sont nombreuses et correctes. Pour faire simple : les tableaux sont bizarres en C. Vous pouvez les initialiser, mais pas les assigner. Vous ne pouvez pas les initialiser individuellement dans un initialisateur de structure, mais vous pouvez les assigner dans le cadre d'une assignation de structure.

#include <string.h>

int main(int argc, char *argv[])
{
  char *test1 [3] = {"a", "b", "c"}; //initialization, not assignment; allowed
  char *test2 [3];

  //test2 = test1; //assignment of arrays; not allowed

  memcpy(test2, test1, sizeof(test1)); //the right way to do a shallow array copy
}

Mais aussi, de manière déroutante :

#include <string.h>

struct _array_holder
{
  char *array[3];
};

int main(int argc, char *argv[])
{
  struct _array_holder test1 = {{"a", "b", "c"}}; //_struct_ initialization; allowed
  struct _array_holder test2;

  test2 = test1; //assignment of _structs_; allowed!

  memcpy(&test2, &test1, sizeof(test1)); //also a fine way to copy a struct
}

Malheureusement, il n'y a pas de façon élégante de faire ce que vous voulez. Voici au moins une façon raisonnablement autonome d'utiliser le fait que les assignations de tableaux à l'intérieur des structures fonctionnent, pour vous éviter d'avoir à écrire plusieurs lignes d'initialisation chaque fois que vous voulez remplir une nouvelle structure :

#include <string.h>
#include <unistd.h>

#define MAX_ARGS 5
struct background_element
{
  pid_t pid;
  int number;
  char *full_command[MAX_ARGS];
};

//something akin to a constructor for the struct
struct background_element init_background_element(pid_t pid, int number, char *full_command[])
{
  struct background_element ret = {.pid = pid, .number=number};
  memcpy(ret.full_command, full_command, sizeof(ret.full_command));
  return ret;
}

int main(int argc, char *argv[])
{
  pid_t child = 1;
  int num_background = 5;
  char *args[MAX_ARGS] = {"a", "b"};

  //use of the constructor-like thing
  struct background_element bg_elem = init_background_element(child, num_background, args);

  return bg_elem.pid;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X