Inicialização do array C char

118

Não tenho certeza do que estará na matriz char após a inicialização das seguintes maneiras.

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

Para o caso 2, acho que buf[0]deveria ser ' ', buf[1]deveria ser '\0'e de buf[2]para buf[9]será conteúdo aleatório. Para o caso 3, acho que buf[0]deveria ser 'a', buf[1]deveria ser '\ 0', e de buf[2]a buf[9]terá conteúdo aleatório.

Isso está correto?

E para o caso 1, o que estará no buf? buf[0] == '\0'e de buf[1]a buf[9]será conteúdo aleatório?

manter em movimento
fonte
2
Bem, meu compilador não aceita seu código (corrigido): "tipo de array 'char [10]' não pode ser atribuído".
Martin R de
@MartinR agora vai funcionar ...
continuo em movimento
1
@lkkeepmoving: char buf[10]; buf = "a";se não compilar. - Experimente primeiro e, em seguida, copie / cole o seu código real na pergunta. Isso economiza muito trabalho para você e para todos os leitores de sua pergunta.
Martin R
@MartinR Desculpe por isso. Eu pensei que poderia atribuir o último buf [], mas parece que não. Agora o código é executado.
Continuando em

Respostas:

222

Não é assim que você inicializa uma matriz, mas para:

  1. A primeira declaração:

    char buf[10] = "";

    é equivalente a

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. A segunda declaração:

    char buf[10] = " ";

    é equivalente a

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. A terceira declaração:

    char buf[10] = "a";

    é equivalente a

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

Como você pode ver, nenhum conteúdo aleatório: se houver menos inicializadores, o restante do array é inicializado com 0. Este é o caso mesmo se o array for declarado dentro de uma função.

ouah
fonte
45
Para o bem da pessoa que está fazendo a pergunta, vale a pena apontar que o padrão C requer que qualquer inicialização de array parcialmente completa seja preenchida com zero para os elementos restantes (pelo compilador). Isso vale para todos os tipos de dados, não apenas char.
Paddy
4
@ouah porque não há '\ 0' no final de buf []?
Continuando em
14
@lkkeepmoving 0e '\0têm o mesmo valor.
ouah
1
@lkkeepmoving Inicialização e atribuição são duas feras diferentes, portanto, C permite fornecer uma string como um inicializador para um array char, mas proíbe atribuições de array (como ouah disse).
Lorenzo Donati - Codidact.com
3
@Pacerier char buff[3] = "abcdefghijkl";é inválido. char p3[5] = "String";também é inválido. char p[6] = "String";é válido e é o mesmo que char p[6] = {'S', 't', 'r', 'i', 'n', 'g'};.
ouah
28

Edit: OP (ou um editor) silenciosamente mudou algumas das aspas simples na pergunta original para aspas duplas em algum ponto depois de ter fornecido esta resposta.

Seu código resultará em erros do compilador. Seu primeiro fragmento de código:

char buf[10] ; buf = ''

é duplamente ilegal. Primeiro, em C, não existe vazio char. Você pode usar aspas duplas para designar uma string vazia, como com:

char* buf = ""; 

Isso lhe dará um ponteiro para uma NULstring, ou seja, uma string de um único caractere com apenas o NULcaractere nela. Mas você não pode usar aspas simples sem nada dentro delas - isso é indefinido. Se você precisar designar o NULpersonagem, você deve especificá-lo:

char buf = '\0';

A barra invertida é necessária para remover a ambigüidade do caractere '0'.

char buf = 0;

realiza a mesma coisa, mas o primeiro é um pouco menos ambíguo de se ler, eu acho.

Em segundo lugar, você não pode inicializar arrays após eles terem sido definidos.

char buf[10];

declara e define o array. O identificador de matriz bufagora é um endereço na memória e você não pode alterar para onde os bufpontos por meio de atribuição. assim

buf =     // anything on RHS

é ilegal. Seu segundo e terceiro fragmentos de código são ilegais por esse motivo.

Para inicializar um array, você deve fazer isso no momento da definição:

char buf [10] = ' ';

fornecerá um array de 10 caracteres com o primeiro caractere sendo o espaço '\040'e o restante sendo NUL, ou seja '\0',. Quando uma matriz é declarada e definida com um inicializador, os elementos da matriz (se houver) após aqueles com os valores iniciais especificados são automaticamente preenchidos com 0. Não haverá nenhum "conteúdo aleatório".

Se você declarar e definir a matriz, mas não inicializá-la, como a seguir:

char buf [10];

você terá conteúdo aleatório em todos os elementos.

prolixo
fonte
"Para inicializar um array, você tem que fazer isso no momento da definição ..." Isso e a linha a seguir tornam isso melhor do que a resposta aceita.
Laurie Stearn
25
  1. Estes são equivalentes

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Estes são equivalentes

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Estes são equivalentes

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

A parte relevante do rascunho da norma C11 n1570 6.7.9 inicialização diz:

14 Uma matriz de tipo de caractere pode ser inicializada por um literal de string de caracteres ou literal de string UTF-8, opcionalmente entre colchetes. Bytes sucessivos do literal de string (incluindo o caractere nulo de terminação se houver espaço ou se o array for de tamanho desconhecido) inicializam os elementos do array.

e

21 Se houver menos inicializadores em uma lista entre chaves do que elementos ou membros de um agregado, ou menos caracteres em um literal de string usado para inicializar uma matriz de tamanho conhecido do que os elementos na matriz, o restante do agregado deve obrigatoriamente ser inicializado implicitamente da mesma forma que objetos que possuem duração de armazenamento estático.

Assim, o '\ 0' é anexado, se houver espaço suficiente , e os caracteres restantes são inicializados com o valor que umstatic char c; seria inicializado dentro de uma função.

Finalmente,

10 Se um objeto com duração de armazenamento automático não for inicializado explicitamente, seu valor será indeterminado. Se um objeto que tem estática duração de armazenamento ou thread não for inicializado explicitamente, então:

[-]

  • se tiver tipo aritmético, é inicializado com zero (positivo ou sem sinal);

[-]

Portanto, charsendo um tipo aritmético, o restante da matriz também tem a garantia de ser inicializado com zeros.

Antti Haapala
fonte
3

Curiosamente, é possível inicializar arrays de qualquer maneira e a qualquer momento no programa, desde que sejam membros de um structou union.

Programa de exemplo:

#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
fonte
1

Não tenho certeza, mas normalmente inicializo uma matriz para "", nesse caso, não preciso me preocupar com a extremidade nula da string.

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
fonte
Você não deve realmente fazer uso da regra int implícita . Você deve especificar um tipo para main()(e também deve usar void, isto é int main(void) { ... },. C99 se livrou desta regra, então este código não irá compilar para C99 e posteriores. A outra coisa a notar aqui é que começando com C99, se você omitir returnem main, há um automático return 0;colocado / implícito antes }do final do main. Você está fazendo uso da regra int implícita que só funciona antes de C99, mas está fazendo uso do implícito returnque só funciona com C99 e posteriores ; essas duas são obviamente contraditórias .
RastaJedi