web-dev-qa-db-fra.com

Comment créer un tableau de chaînes en C?

J'essaie de créer un tableau de chaînes en C. Si j'utilise ce code:

char (*a[2])[14];
a[0]="blah";
a[1]="hmm";

gcc me donne "warning: assignation de type de pointeur incompatible". Quelle est la bonne façon de faire cela?

edit: Je suis curieux de savoir pourquoi cela devrait donner un avertissement au compilateur puisque si je fais printf(a[1]);, il affiche correctement "hmm".

221
Charles

Si vous ne voulez pas changer les chaînes, vous pouvez simplement faire

const char *a[2];
a[0] = "blah";
a[1] = "hmm";

Lorsque vous le faites comme ceci, vous allouez un tableau de deux pointeurs à const char. Ces pointeurs seront alors définis sur les adresses des chaînes statiques "blah" et "hmm".

Si vous voulez pouvoir changer le contenu de la chaîne, vous devez faire quelque chose comme:

char a[2][14];
strcpy(a[0], "blah");
strcpy(a[1], "hmm");

Cela allouera deux tableaux consécutifs de 14 chars chacun, après quoi le contenu des chaînes statiques sera copié dans ceux-ci.

199
Mikael Auno

Il existe plusieurs façons de créer un tableau de chaînes en C. Si toutes les chaînes doivent avoir la même longueur (ou au moins la même longueur maximale), il vous suffit de déclarer un tableau à 2 dimensions et de l'attribuer si nécessaire:

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1];
...
strcpy(strs[0], aString); // where aString is either an array or pointer to char
strcpy(strs[1], "foo");

Vous pouvez également ajouter une liste d'initialisateurs:

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1] = {"foo", "bar", "bletch", ...};

Cela suppose que la taille et le nombre de chaînes de l'initialiseur correspondent aux dimensions de votre tableau. Dans ce cas, le contenu de chaque littéral de chaîne (qui est lui-même un tableau de caractères à zéro terminal) est copié dans la mémoire allouée à strs. Le problème avec cette approche est la possibilité de fragmentation interne; si vous avez 99 chaînes de 5 caractères ou moins, mais 1 chaîne de 20 caractères, 99 chaînes auront au moins 15 caractères inutilisés; c'est un gaspillage d'espace.

Au lieu d'utiliser un tableau 2-d de caractères, vous pouvez stocker un tableau 1-d de pointeurs pour char:

char *strs[NUMBER_OF_STRINGS];

Notez que dans ce cas, vous avez uniquement alloué de la mémoire pour contenir les pointeurs sur les chaînes; la mémoire des chaînes elles-mêmes doit être allouée ailleurs (sous forme de tableaux statiques ou en utilisant malloc () ou calloc ()). Vous pouvez utiliser la liste d'initialisation comme dans l'exemple précédent:

char *strs[NUMBER_OF_STRINGS] = {"foo", "bar", "bletch", ...};

Au lieu de copier le contenu des constantes de chaîne, vous stockez simplement les pointeurs sur celles-ci. Notez que les constantes de chaîne peuvent ne pas être accessibles en écriture; vous pouvez réaffecter le pointeur, comme suit:

strs[i] = "bar";
strs[i] = "foo"; 

Mais vous ne pourrez peut-être pas modifier le contenu de la chaîne. c'est à dire.,

strs[i] = "bar";
strcpy(strs[i], "foo");

peut ne pas être autorisé. 

Vous pouvez utiliser malloc () pour allouer de manière dynamique le tampon pour chaque chaîne et copier dans ce tampon:

strs[i] = malloc(strlen("foo") + 1);
strcpy(strs[i], "foo");

BTW, 

char (*a[2])[14];

Déclare un tableau de pointeurs à 2 éléments en tableaux de caractères à 14 éléments. 

153
John Bode

Ack! Chaînes constantes:

const char *strings[] = {"one","two","three"};

Si je me souviens bien.

Oh, et vous voulez utiliser strcpy pour l’affectation, pas l’opérateur =. strcpy_s est plus sûr, mais ce n’est ni dans les normes C89 ni dans les normes C99.

char arr[MAX_NUMBER_STRINGS][MAX_STRING_SIZE]; 
strcpy(arr[0], "blah");

Mise à jour:Thomas dit que strlcpy est la voie à suivre.

79
mpen

Voici certaines de vos options:

char a1[][14] = { "blah", "hmm" };
char* a2[] = { "blah", "hmm" };
char (*a3[])[] = { &"blah", &"hmm" };  // only since you brought up the syntax -

printf(a1[0]); // prints blah
printf(a2[0]); // prints blah
printf(*a3[0]); // prints blah

L'avantage de a2 est que vous pouvez ensuite effectuer les opérations suivantes avec des littéraux de chaîne.

a2[0] = "hmm";
a2[1] = "blah";

Et pour A3, vous pouvez faire ce qui suit:

a3[0] = &"hmm";
a3[1] = &"blah";

Pour a1, vous devrez utiliser strcpy même lorsque vous affectez des littéraux de chaîne. La raison en est que a2 et a3 sont des tableaux de pointeurs et que vous pouvez faire en sorte que leurs éléments (pointeurs) pointent vers n’importe quel stockage, tandis que a1 est un tableau de 'tableau de caractères' et que chaque élément est un tableau qui "possède" son son propre stockage (c’est-à-dire qu’il est détruit quand il est hors de portée) - vous ne pouvez copier que des éléments dans son stockage.

Cela nous amène également à l’inconvénient d’utiliser a2 et a3, car ils renvoient à un stockage statique (où sont stockés des littéraux de chaîne) dont le contenu ne peut pas être modifié de manière fiable (à savoir un comportement indéfini), si vous souhaitez affecter des littéraux autres que des chaînes. aux éléments de a2 ou a3 - vous devez d'abord allouer dynamiquement suffisamment de mémoire, puis faire pointer leurs éléments vers cette mémoire, puis y copier les caractères - et vous devez ensuite être sûr de libérer de la mémoire lorsque vous avez terminé.

Bah - C++ me manque déjà;)

p.s. Faites-moi savoir si vous avez besoin d'exemples.

11
Faisal Vali

En ANSI C:

char* strings[3];
strings[0] = "foo";
strings[1] = "bar";
strings[2] = "baz";
10
Noldorin

Ou vous pouvez déclarer un type de structure, qui contient un caractère arry (1 chaîne), les créer un tableau des structs et donc un tableau multi-éléments

typedef struct name
{
   char name[100]; // 100 character array
}name;

main()
{
   name yourString[10]; // 10 strings
   printf("Enter something\n:);
   scanf("%s",yourString[0].name);
   scanf("%s",yourString[1].name);
   // maybe put a for loop and a few print ststements to simplify code
   // this is just for example 
 }

L'un des avantages de cette méthode par rapport à toute autre méthode est qu'elle vous permet de numériser directement dans la chaîne sans avoir à utiliser strcpy;

10
FutureSci

Si vous ne voulez pas garder trace du nombre de chaînes dans un tableau et que vous voulez les parcourir, ajoutez simplement une chaîne NULL à la fin:

char *strings[]={ "one", "two", "three", NULL };

int i=0;
while(strings[i]) {
  printf("%s\n", strings[i]);
  //do something
  i++;
};
9
Sergey

Les littéraux de chaîne sont const char *s.

Et votre utilisation de la parenthèse est étrange. Vous voulez probablement dire

const char *a[2] = {"blah", "hmm"};

qui déclare un tableau de deux pointeurs sur des caractères constants et les initialise pour pointer sur deux constantes chaîne codées en dur.

8
dmckee

Si les chaînes sont statiques, vous êtes mieux loti avec:

const char *my_array[] = {"eenie","meenie","miney"};

Bien que ne faisant pas partie de la norme ANSI C de base, il est probable que votre environnement prenne en charge la syntaxe. Ces chaînes sont immuables (en lecture seule) et, par conséquent, dans de nombreux environnements, vous utilisez moins de temps système que de créer de manière dynamique un tableau de chaînes. 

Par exemple, dans les petits projets de micro-contrôleurs, cette syntaxe utilise la mémoire programme plutôt que (généralement) une mémoire RAM plus précieuse. AVR-C est un exemple d'environnement prenant en charge cette syntaxe, tout comme la plupart des autres.

8
Bryce

Votre code crée un tableau de pointeurs de fonction. Essayer

char* a[size];

ou

char a[size1][size2];

au lieu.

Voir wikibooks à tableaux et pointeurs

3
Dario

bonjour vous pouvez essayer ce ci-dessous: 

 char arr[nb_of_string][max_string_length]; 
 strcpy(arr[0], "Word");

un bel exemple d'utilisation, tableau de chaînes en c si vous le voulez

#include <stdio.h>
#include <string.h>


int main(int argc, char *argv[]){

int i, j, k;

// to set you array
//const arr[nb_of_string][max_string_length]
char array[3][100];

char temp[100];
char Word[100];

for (i = 0; i < 3; i++){
    printf("type Word %d : ",i+1);
    scanf("%s", Word);
    strcpy(array[i], Word);
}

for (k=0; k<3-1; k++){
    for (i=0; i<3-1; i++)
    {
        for (j=0; j<strlen(array[i]); j++)
        {
            // if a letter ascii code is bigger we swap values
            if (array[i][j] > array[i+1][j])
            {
                strcpy(temp, array[i+1]);
                strcpy(array[i+1], array[i]);
                strcpy(array[i], temp);

                j = 999;
            }

            // if a letter ascii code is smaller we stop
            if (array[i][j] < array[i+1][j])
            {
                    j = 999;
            }

        }
    }
}

for (i=0; i<3; i++)
{
    printf("%s\n",array[i]);
}

return 0;
}
1
Aominé

Il me manquait un tableau de chaînes plus dynamique, où le nombre de chaînes pouvait varier en fonction de la sélection au moment de l'exécution, mais les chaînes devraient sinon être corrigées.

J'ai fini par avoir un extrait de code comme ceci:

#define INIT_STRING_ARRAY(...)          \
    {                                   \
        char* args[] = __VA_ARGS__;     \
        ev = args;                      \
        count = _countof(args);         \
    }

void InitEnumIfAny(String& key, CMFCPropertyGridProperty* item)
{
    USES_CONVERSION;
    char** ev = nullptr;
    int count = 0;

    if( key.Compare("horizontal_alignment") )
        INIT_STRING_ARRAY( { "top", "bottom" } )

    if (key.Compare("boolean"))
        INIT_STRING_ARRAY( { "yes", "no" } )

    if( ev == nullptr )
        return;

    for( int i = 0; i < count; i++)
        item->AddOption(A2T(ev[i]));

    item->AllowEdit(FALSE);
}

char** ev ramasse le pointeur sur les chaînes du tableau et compte la quantité de chaînes à l'aide de la fonction _countof. (Semblable à sizeof(arr) / sizeof(arr[0])).

Et il existe une conversion supplémentaire Ansi vers Unicode à l'aide de la macro A2T, mais cela pourrait être facultatif pour votre cas.

0
TarmoPikaro
char name[10][10]
int i,j,n;//here "n" is number of enteries
printf("\nEnter size of array = ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
    for(j=0;j<1;j++)
    {
        printf("\nEnter name = ");
        scanf("%s",&name[i]);
    }
}
//printing the data
for(i=0;i<n;i++)
{
    for(j=0;j<1;j++)
    {
        printf("%d\t|\t%s\t|\t%s",rollno[i][j],name[i],sex[i]);
    }
    printf("\n");
}

Ici essayez ceci !!!

0
Aditya