Inizializzazione dell'array di caratteri C.


119

Non sono sicuro di cosa ci sarà nell'array char dopo l'inizializzazione nei seguenti modi.

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

Per il caso 2, penso che buf[0]dovrebbe essere ' ', buf[1]dovrebbe essere '\0', e da buf[2]a buf[9]sarà contenuto casuale. Per il caso 3, penso che buf[0]dovrebbe essere 'a', buf[1]dovrebbe essere "\ 0" e da buf[2]a buf[9]sarà contenuto casuale.

È corretto?

E per il caso 1, cosa ci sarà nel buf? buf[0] == '\0'e da buf[1]a buf[9]sarà contenuto casuale?


2
Ebbene, il mio compilatore non accetta il tuo codice (corretto): "il tipo di array 'char [10]' non è assegnabile".
Martin R

@MartinR ora funzionerà ...
lkkeepmoving

1
@lkkeepmoving: char buf[10]; buf = "a";non si compila. - Per favore prova prima, quindi copia / incolla il tuo codice effettivo nella domanda. Ciò consente di risparmiare molto lavoro per te e per tutti i lettori della tua domanda.
Martin R

@ MartinR Ci scusiamo per questo. Pensavo di poter assegnare il buf [] a quest'ultimo ma sembra di no. Ora il codice viene eseguito.
lkkeepmoving

Risposte:


222

Non è così che si inizializza un array, ma per:

  1. La prima dichiarazione:

    char buf[10] = "";

    è equivalente a

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. La seconda dichiarazione:

    char buf[10] = " ";

    è equivalente a

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. La terza dichiarazione:

    char buf[10] = "a";

    è equivalente a

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

Come puoi vedere, nessun contenuto casuale: se ci sono meno inizializzatori, il resto dell'array viene inizializzato con 0. Questo è il caso anche se l'array è dichiarato all'interno di una funzione.


47
Per il bene della persona che pone la domanda, vale la pena sottolineare che lo standard C richiede che qualsiasi inizializzazione di array parzialmente completa venga riempita con zero per gli elementi rimanenti (dal compilatore). Questo vale per tutti i tipi di dati, non solo char.
risaia

4
@ouah, perché non c'è "\ 0" alla fine di buf []?
lkkeepmoving

14
@lkkeepmoving 0e '\0hanno lo stesso valore.
ouah

1
@lkkeepmoving L'inizializzazione e l'assegnazione sono due bestie diverse, quindi C ti consente di fornire una stringa come inizializzatore per un array di caratteri, ma proibisce l'assegnazione di array (come ha detto ouah).
Lorenzo Donati - Codidact.com

3
@Pacerier char buff[3] = "abcdefghijkl";non è valido. char p3[5] = "String";non è valido anche. char p[6] = "String";è valido ed è uguale a char p[6] = {'S', 't', 'r', 'i', 'n', 'g'};.
ouah

28

Modifica: OP (o un editore) ha silenziosamente modificato alcune delle virgolette singole nella domanda originale in virgolette doppie ad un certo punto dopo aver fornito questa risposta.

Il codice provocherà errori del compilatore. Il tuo primo frammento di codice:

char buf[10] ; buf = ''

è doppiamente illegale. Primo, in C, non esiste un vuoto char. Puoi usare le virgolette per designare una stringa vuota, come con:

char* buf = ""; 

Questo ti darà un puntatore a una NULstringa, cioè una stringa di un solo carattere contenente solo il NULcarattere. Ma non puoi usare virgolette singole senza nulla al loro interno - questo è indefinito. Se devi designare il NULpersonaggio, devi specificarlo:

char buf = '\0';

Il backslash è necessario per disambiguare il carattere '0'.

char buf = 0;

compie la stessa cosa, ma il primo è un po 'meno ambiguo da leggere, credo.

In secondo luogo, non è possibile inizializzare gli array dopo che sono stati definiti.

char buf[10];

dichiara e definisce l'array. L'identificatore di matrice bufè ora un indirizzo in memoria e non è possibile modificare i bufpunti in cui si trova tramite assegnazione. Così

buf =     // anything on RHS

è illegale. Il secondo e il terzo frammento di codice sono illegali per questo motivo.

Per inizializzare un array, devi farlo al momento della definizione:

char buf [10] = ' ';

vi darà una matrice 10 caratteri con il primo carattere essendo lo spazio '\040'e l'essere resto NUL, cioè '\0'. Quando un array viene dichiarato e definito con un inizializzatore, gli elementi dell'array (se presenti) oltre quelli con valori iniziali specificati vengono automaticamente riempiti con 0. Non ci sarà alcun "contenuto casuale".

Se dichiari e definisci l'array ma non lo inizializzi, come nel seguente:

char buf [10];

avrai contenuti casuali in tutti gli elementi.


"Per inizializzare un array, devi farlo al momento della definizione ..." Questo e la riga seguente lo rendono migliore della risposta accettata.
Laurie Stearn

26
  1. Questi sono equivalenti

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Questi sono equivalenti

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Questi sono equivalenti

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

8

La parte rilevante dell'inizializzazione della bozza standard C11 n1570 6.7.9 dice:

14 Un array di tipo di carattere può essere inizializzato da una stringa di caratteri letterale o UTF-8 letterale, facoltativamente racchiusa tra parentesi graffe. I byte successivi della stringa letterale (incluso il carattere null di terminazione se c'è spazio o se l'array è di dimensioni sconosciute) inizializzano gli elementi dell'array.

e

21 Se ci sono meno inizializzatori in un elenco racchiuso tra parentesi graffe rispetto agli elementi o membri di un aggregato, o meno caratteri in un valore letterale stringa utilizzato per inizializzare un array di dimensioni note rispetto agli elementi dell'array, il resto dell'aggregato deve essere inizializzato implicitamente come gli oggetti che hanno una durata di memorizzazione statica.

Pertanto, "\ 0" viene aggiunto, se c'è abbastanza spazio , e i caratteri rimanenti vengono inizializzati con il valore che a static char c;sarebbe inizializzato all'interno di una funzione.

Finalmente,

10 Se un oggetto che ha una durata di memorizzazione automatica non viene inizializzato esplicitamente, il suo valore è indeterminato. Se un oggetto che ha una durata di archiviazione statica o di thread non viene inizializzato in modo esplicito, allora:

[-]

  • se ha un tipo aritmetico, viene inizializzato a zero (positivo o senza segno);

[-]

Pertanto, charessendo un tipo aritmetico, anche il resto dell'array è garantito per essere inizializzato con zeri.


3

È interessante notare che è possibile inizializzare gli array in qualsiasi modo e in qualsiasi momento nel programma, a condizione che siano membri di un structo union.

Programma di esempio:

#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;
}

1

Non ne sono sicuro, ma di solito inizializzo un array su "", in questo caso non mi devo preoccupare dell'estremità nulla della stringa.

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'
}

Non dovresti davvero usare la regola int implicita . Dovresti specificare un tipo per main()(e dovresti anche usare void, ad esempio int main(void) { ... },. C99 ha eliminato questa regola, quindi questo codice non verrà compilato per C99 e versioni successive. L'altra cosa da notare qui è che a partire da C99, se ometti returnin main, c'è un automatico return 0;posto / implicito prima }della fine di main. Stai facendo uso della regola implicita int che funziona solo prima di C99, ma stai facendo uso dell'implicito returnche funziona solo con C99 e successivi ; questi due sono ovviamente contraddittori .
RastaJedi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.