Initialisation du tableau de caractères C

119

Je ne suis pas sûr de ce qu'il y aura dans le tableau char après l'initialisation des manières suivantes.

1. char buf[10] = "";
2. char buf[10] = " ";
3.char buf[10] = "a";

Pour le cas 2, je pense que buf[0]devrait être ' ', buf[1]devrait être '\0'et de buf[2]à buf[9]sera un contenu aléatoire. Pour le cas 3, je pense que buf[0]devrait être 'a', buf[1]devrait être '\ 0', et de buf[2]à buf[9]sera un contenu aléatoire.

Est-ce exact?

Et pour le cas 1, que sera dans le buf? buf[0] == '\0'et de buf[1]à buf[9]sera un contenu aléatoire?

lkkeepmoving
la source
2
Eh bien, mon compilateur n'accepte pas votre code (corrigé): "le type de tableau 'char [10]' n'est pas assignable".
Martin R
@MartinR maintenant cela fonctionnera ...
lkkeepmoving
1
@lkkeepmoving: char buf[10]; buf = "a";ne compile pas . - Veuillez d'abord essayer, puis copiez / collez votre code réel dans la question. Cela économise beaucoup de travail pour vous et pour tous les lecteurs de votre question.
Martin R
@MartinR Désolé pour ça. Je pensais pouvoir attribuer le buf [] à ce dernier mais il semble que non. Maintenant, le code s'exécute.
lkkeepmoving

Réponses:

222

Ce n'est pas ainsi que vous initialisez un tableau, mais pour:

  1. La première déclaration:

    char buf[10] = "";

    est équivalent à

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. La deuxième déclaration:

    char buf[10] = " ";

    est équivalent à

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. La troisième déclaration:

    char buf[10] = "a";

    est équivalent à

    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};

Comme vous pouvez le voir, pas de contenu aléatoire: s'il y a moins d'initialiseurs, le reste du tableau est initialisé avec 0. C'est le cas même si le tableau est déclaré à l'intérieur d'une fonction.

ouah
la source
47
Pour le bien de la personne qui pose la question, il convient de souligner que le standard C exige que toute initialisation de tableau partiellement complète soit complétée par zéro pour les éléments restants (par le compilateur). Cela vaut pour tous les types de données, pas seulement char.
paddy
4
@ouah pourquoi il n'y a pas de '\ 0' à la fin de buf []?
lkkeepmoving
14
@lkkeepmoving 0et '\0ont la même valeur.
ouah
1
@lkkeepmoving L'initialisation et l'affectation sont deux bêtes différentes, donc C vous permet de fournir une chaîne comme initialiseur pour un tableau de caractères, mais interdit les affectations de tableau (comme ouah l'a dit).
Lorenzo Donati - Codidact.com
3
@Pacerier char buff[3] = "abcdefghijkl";n'est pas valide. char p3[5] = "String";est également invalide. char p[6] = "String";est valide et est identique à char p[6] = {'S', 't', 'r', 'i', 'n', 'g'};.
ouah
28

Edit: OP (ou un éditeur) a silencieusement changé certaines des guillemets simples de la question originale en guillemets doubles à un moment donné après avoir fourni cette réponse.

Votre code entraînera des erreurs de compilation. Votre premier fragment de code:

char buf[10] ; buf = ''

est doublement illégal. Premièrement, en C, il n'y a pas de vide char. Vous pouvez utiliser des guillemets doubles pour désigner une chaîne vide, comme avec:

char* buf = ""; 

Cela vous donnera un pointeur vers une NULchaîne, c'est-à-dire une chaîne à un seul caractère contenant uniquement le NULcaractère. Mais vous ne pouvez pas utiliser de guillemets simples sans rien à l'intérieur - cela n'est pas défini. Si vous devez désigner le NULpersonnage, vous devez le spécifier:

char buf = '\0';

La barre oblique inverse est nécessaire pour lever l'ambiguïté du caractère '0'.

char buf = 0;

accomplit la même chose, mais le premier est un peu moins ambigu à lire, je pense.

Deuxièmement, vous ne pouvez pas initialiser les tableaux une fois qu'ils ont été définis.

char buf[10];

déclare et définit le tableau. L'identificateur de tableau bufest maintenant une adresse en mémoire et vous ne pouvez pas changer où bufpointe par l'attribution. Alors

buf =     // anything on RHS

est illégal. Vos deuxième et troisième fragments de code sont illégaux pour cette raison.

Pour initialiser un tableau, vous devez le faire au moment de la définition:

char buf [10] = ' ';

vous donnera un tableau de 10 caractères, le premier caractère étant l'espace '\040'et le reste étant NUL, c'est-à-dire '\0'. Lorsqu'un tableau est déclaré et défini avec un initialiseur, les éléments du tableau (le cas échéant) après ceux avec les valeurs initiales spécifiées sont automatiquement complétés avec 0. Il n'y aura pas de "contenu aléatoire".

Si vous déclarez et définissez le tableau mais ne l'initialisez pas, comme dans l'exemple suivant:

char buf [10];

vous aurez un contenu aléatoire dans tous les éléments.

verbeux
la source
"Pour initialiser un tableau, vous devez le faire au moment de la définition ..." Ceci, et la ligne suivante rend cela meilleur que la réponse acceptée.
Laurie Stearn
26
  1. Ce sont équivalents

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Ce sont équivalents

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Ce sont équivalents

    char buf[10] = "a";
    char buf[10] = {'a'};
    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};
Steven Penny
la source
8

La partie pertinente de l'initialisation du projet de norme C11 n1570 6.7.9 dit:

14 Un tableau de type caractère peut être initialisé par un littéral de chaîne de caractères ou par un littéral de chaîne UTF-8, éventuellement entre accolades. Les octets successifs du littéral de chaîne (y compris le caractère nul de fin s'il y a de la place ou si le tableau est de taille inconnue) initialisent les éléments du tableau.

et

21 S'il y a moins d'initialiseurs dans une liste entre accolades qu'il n'y a d'éléments ou de membres d'un agrégat, ou moins de caractères dans une chaîne littérale utilisée pour initialiser un tableau de taille connue qu'il n'y a d'éléments dans le tableau, le reste de l'agrégat doivent être initialisés implicitement de la même manière que les objets qui ont une durée de stockage statique.

Ainsi, le '\ 0' est ajouté, s'il y a suffisamment d'espace , et les caractères restants sont initialisés avec la valeur que a static char c;serait initialisée dans une fonction.

Finalement,

10 Si un objet qui a une durée de stockage automatique n'est pas initialisé explicitement, sa valeur est indéterminée. Si un objet qui a une durée de stockage statique ou de thread n'est pas initialisé explicitement, alors:

[-]

  • s'il est de type arithmétique, il est initialisé à zéro (positif ou non signé);

[-]

Ainsi, charétant de type arithmétique, le reste du tableau est également garanti d'être initialisé avec des zéros.

Antti Haapala
la source
3

Fait intéressant, il est possible d'initialiser des tableaux de n'importe quelle manière à tout moment dans le programme, à condition qu'ils soient membres d'un structou union.

Exemple de programme:

#include <stdio.h>

struct ccont
{
  char array[32];
};

struct icont
{
  int array[32];
};

int main()
{
  int  cnt;
  char carray[32] = { 'A', 66, 6*11+1 };    // 'A', 'B', 'C', '\0', '\0', ...
  int  iarray[32] = { 67, 42, 25 };

  struct ccont cc = { 0 };
  struct icont ic = { 0 };

  /*  these don't work
  carray = { [0]=1 };           // expected expression before '{' token
  carray = { [0 ... 31]=1 };    // (likewise)
  carray = (char[32]){ [0]=3 }; // incompatible types when assigning to type 'char[32]' from type 'char *'
  iarray = (int[32]){ 1 };      // (likewise, but s/char/int/g)
  */

  // but these perfectly work...
  cc = (struct ccont){ .array='a' };        // 'a', '\0', '\0', '\0', ...
  // the following is a gcc extension, 
  cc = (struct ccont){ .array={ [0 ... 2]='a' } };  // 'a', 'a', 'a', '\0', '\0', ...
  ic = (struct icont){ .array={ 42,67 } };      // 42, 67, 0, 0, 0, ...
  // index ranges can overlap, the latter override the former
  // (no compiler warning with -Wall -Wextra)
  ic = (struct icont){ .array={ [0 ... 1]=42, [1 ... 2]=67 } }; // 42, 67, 67, 0, 0, ...

  for (cnt=0; cnt<5; cnt++)
    printf("%2d %c %2d %c\n",iarray[cnt], carray[cnt],ic.array[cnt],cc.array[cnt]);

  return 0;
}
user3381726
la source
1

Je ne suis pas sûr, mais j'initialise généralement un tableau à "" dans ce cas, je n'ai pas besoin de m'inquiéter de l'extrémité nulle de la chaîne.

main() {
    void something(char[]);
    char s[100] = "";

    something(s);
    printf("%s", s);
}

void something(char s[]) {
    // ... do something, pass the output to s
    // no need to add s[i] = '\0'; because all unused slot is already set to '\0'
}
Erric Rapsing
la source
Vous ne devez pas vraiment utiliser la règle implicite int . Vous devez spécifier un type pour main()(et vous devez également utiliser void, c'est-à-dire int main(void) { ... }. C99 s'est débarrassé de cette règle, donc ce code ne sera pas compilé pour C99 et les versions ultérieures. L'autre chose à noter ici est que commençant par C99, si vous omettez returndans main, il y a un automatique return 0;placé / implicite avant la }fin de at main. Vous utilisez une règle int implicite qui ne fonctionne qu'avant C99, mais vous utilisez l'implicite returnqui ne fonctionne qu'avec C99 et les versions ultérieures ; ces deux sont évidemment contradictoires .
RastaJedi