Inicialización de matriz de caracteres C

118

No estoy seguro de qué habrá en la matriz de caracteres después de la inicialización de las siguientes maneras.

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

Para el caso 2, creo que buf[0]debería ser ' ', buf[1]debería ser '\0'y de buf[2]a buf[9]será contenido aleatorio. Para el caso 3, creo que buf[0]debería ser 'a',buf[1] debería ser '\ 0', y de buf[2]a buf[9]será contenido aleatorio.

¿Es eso correcto?

Y para el caso 1, ¿qué habrá en el buf? buf[0] == '\0'y de buf[1]a buf[9]habrá contenido aleatorio?

lkkeepmoving
fuente
2
Bueno, mi compilador no acepta su código (corregido): "el tipo de matriz 'char [10]' no es asignable".
Martin R
@MartinR ahora funcionará ...
lkkeepmoving
1
@lkkeepmoving: char buf[10]; buf = "a";no se compila. - Inténtelo primero y luego copie / pegue su código real en la pregunta. Eso le ahorra mucho trabajo a usted y a todos los lectores de su pregunta.
Martin R
@MartinR Lo siento por eso. Pensé que podía asignar el último buf [] pero parece que no. Ahora se ejecuta el código.
lkkeepmoving

Respuestas:

222

No es así como se inicializa una matriz, sino para:

  1. La primera declaración:

    char buf[10] = "";

    es equivalente a

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. La segunda declaración:

    char buf[10] = " ";

    es equivalente a

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. La tercera declaración:

    char buf[10] = "a";

    es equivalente a

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

Como puede ver, no hay contenido aleatorio: si hay menos inicializadores, el resto de la matriz se inicializa con 0. Este es el caso incluso si la matriz se declara dentro de una función.

ouah
fuente
45
Por el bien de la persona que hace la pregunta, vale la pena señalar que el estándar C requiere que cualquier inicialización de matriz parcialmente completa se rellene con cero para los elementos restantes (por el compilador). Esto se aplica a todos los tipos de datos, no solo char.
paddy
4
@ouah ¿por qué no hay '\ 0' al final de buf []?
lkkeepmoving
14
@lkkeepmoving 0y '\0tienen el mismo valor.
ouah
1
@lkkeepmoving La inicialización y la asignación son dos bestias diferentes, por lo que C le permite proporcionar una cadena como inicializador para una matriz de caracteres, pero prohíbe las asignaciones de matriz (como dijo ouah).
Lorenzo Donati - Codidact.com
3
@Pacerier char buff[3] = "abcdefghijkl";no es válido. char p3[5] = "String";también es inválido. char p[6] = "String";es válido y es el mismo que char p[6] = {'S', 't', 'r', 'i', 'n', 'g'};.
ouah
28

Editar: OP (o un editor) cambió silenciosamente algunas de las comillas simples en la pregunta original a comillas dobles en algún momento después de que proporcioné esta respuesta.

Su código resultará en errores del compilador. Tu primer fragmento de código:

char buf[10] ; buf = ''

es doblemente ilegal. Primero, en C, no existe un vacío char. Puede usar comillas dobles para designar una cadena vacía, como con:

char* buf = ""; 

Eso le dará un puntero a una NULcadena, es decir, una cadena de un solo carácter con solo el NULcarácter en ella. Pero no puede usar comillas simples sin nada dentro, eso no está definido. Si necesita designar el NULpersonaje, debe especificarlo:

char buf = '\0';

La barra invertida es necesaria para eliminar la ambigüedad del personaje '0'.

char buf = 0;

logra lo mismo, pero creo que el primero es un poco menos ambiguo de leer.

En segundo lugar, no puede inicializar matrices después de haberlas definido.

char buf[10];

declara y define la matriz. El identificador de la matriz bufes ahora una dirección en la memoria y no puede cambiar los bufpuntos a través de la asignación. Entonces

buf =     // anything on RHS

es ilegal. Su segundo y tercer fragmento de código son ilegales por este motivo.

Para inicializar una matriz, debes hacerlo en el momento de la definición:

char buf [10] = ' ';

le dará una serie de 10 caracteres con el primer carácter de ser el espacio '\040'y el ser de descanso NUL, es decir, '\0'. Cuando una matriz se declara y define con un inicializador, los elementos de la matriz (si los hay) más allá de los que tienen valores iniciales especificados se rellenan automáticamente con0 . No habrá ningún "contenido aleatorio".

Si declara y define la matriz pero no la inicializa, como se muestra a continuación:

char buf [10];

tendrás contenido aleatorio en todos los elementos.

verboso
fuente
"Para inicializar una matriz, debe hacerlo en el momento de la definición ..." Esto y la siguiente línea hacen que esto sea mejor que la respuesta aceptada.
Laurie Stearn
25
  1. Estos son equivalentes

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Estos son equivalentes

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Estos son equivalentes

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

La parte relevante del borrador del estándar C11 n1570 6.7.9 inicialización dice:

14 Una matriz de tipo de carácter puede inicializarse mediante un literal de cadena de caracteres o un literal de cadena UTF-8, opcionalmente entre llaves. Los bytes sucesivos del literal de cadena (incluido el carácter nulo de terminación si hay espacio o si la matriz es de tamaño desconocido) inicializan los elementos de la matriz.

y

21 Si hay menos inicializadores en una lista entre llaves que elementos o miembros de un agregado, o menos caracteres en un literal de cadena usado para inicializar un arreglo de tamaño conocido que elementos en el arreglo, el resto del agregado se inicializarán implícitamente igual que los objetos que tienen una duración de almacenamiento estático.

Por lo tanto, se agrega el '\ 0', si hay suficiente espacio , y los caracteres restantes se inicializan con el valor que static char c;se inicializaría dentro de una función.

Finalmente,

10 Si un objeto que tiene una duración de almacenamiento automático no se inicializa explícitamente, su valor es indeterminado. Si un objeto que tiene una duración de almacenamiento estática o de subprocesos no se inicializa explícitamente, entonces:

[-]

  • si tiene tipo aritmético, se inicializa a cero (positivo o sin signo);

[-]

Por lo tanto, al charser de tipo aritmético, también se garantiza que el resto de la matriz se inicializará con ceros.

Antti Haapala
fuente
3

Curiosamente, es posible inicializar matrices de cualquier forma en cualquier momento en el programa, siempre que sean miembros de structo union.

Programa de ejemplo:

#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;
}
usuario3381726
fuente
1

No estoy seguro, pero normalmente inicializo una matriz en "", en ese caso no necesito preocuparme por el final nulo de la cadena.

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
fuente
Realmente no debería hacer uso de la regla int implícita . Debe especificar un tipo paramain() (y también debe usar void, es decir int main(void) { ... },. C99 eliminó esta regla, por lo que este código no se compilará para C99 y posteriores. La otra cosa a tener en cuenta aquí es que comenzar con C99, si omite returnen main, hay una return 0;posición / implícita automática antes }del final de at main. Estás haciendo uso de la regla int implícita que solo funciona antes de C99, pero estás haciendo uso de la implícita returnque solo funciona con C99 y posteriores ; estos dos son obviamente contradictorios .
RastaJedi