C char Array Initialisierung

118

Ich bin nicht sicher, was nach der Initialisierung auf folgende Weise im char-Array enthalten sein wird.

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

Für Fall 2 denke ich, buf[0]sollte sein ' ', buf[1]sollte sein '\0'und von buf[2]bis buf[9]wird zufälliger Inhalt sein. Für Fall 3, denke ich buf[0]soll sein 'a', buf[1]sollte ‚\ 0‘ sein, und von buf[2]zu buf[9]werden gelegentlichen zufrieden sein.

Ist das korrekt?

Und für den Fall 1, was wird in der sein buf? buf[0] == '\0'und von buf[1]bis buf[9]wird zufälliger Inhalt sein?

lkkeepmoving
quelle
2
Nun, mein Compiler akzeptiert Ihren (korrigierten) Code nicht: "Array-Typ 'char [10]' ist nicht zuweisbar".
Martin R
@ MartinR jetzt wird es funktionieren ...
lkkeepmoving
1
@lkkeepmoving: char buf[10]; buf = "a";nicht nicht kompilieren. - Bitte versuchen Sie es zuerst und kopieren Sie dann Ihren tatsächlichen Code in die Frage. Das spart Ihnen und allen Lesern Ihrer Frage viel Arbeit.
Martin R
@ MartinR Entschuldigung. Ich dachte, ich kann den buf [] letzteren zuweisen, aber es scheint nein. Jetzt läuft der Code.
lkkeepmoving

Antworten:

222

So initialisieren Sie ein Array nicht, sondern für:

  1. Die erste Erklärung:

    char buf[10] = "";

    ist äquivalent zu

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Die zweite Erklärung:

    char buf[10] = " ";

    ist äquivalent zu

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Die dritte Erklärung:

    char buf[10] = "a";

    ist äquivalent zu

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

Wie Sie sehen können, kein zufälliger Inhalt: Wenn weniger Initialisierer vorhanden sind, wird der Rest des Arrays mit initialisiert 0. Dies ist auch dann der Fall, wenn das Array innerhalb einer Funktion deklariert ist.

ouah
quelle
45
Für die Person, die die Frage stellt, ist darauf hinzuweisen, dass der C-Standard erfordert, dass eine teilweise vollständige Array-Initialisierung für die verbleibenden Elemente (vom Compiler) mit Null aufgefüllt wird. Dies gilt für alle Datentypen, nicht nur char.
Paddy
4
@ouah warum gibt es am Ende von buf [] kein '\ 0'?
lkkeepmoving
14
@lkkeepmoving 0und '\0haben den gleichen Wert.
Ouah
1
@lkkeepmoving Initialisierung und Zuweisung sind zwei verschiedene Bestien. Mit C können Sie also eine Zeichenfolge als Initialisierer für ein char-Array bereitstellen, aber Array-Zuweisungen verbieten (wie Sie sagten).
Lorenzo Donati - Codidact.com
3
@ Pacerier char buff[3] = "abcdefghijkl";ist ungültig. char p3[5] = "String";ist auch ungültig. char p[6] = "String";ist gültig und ist das gleiche wie char p[6] = {'S', 't', 'r', 'i', 'n', 'g'};.
Ouah
28

Bearbeiten: OP (oder ein Editor) hat einige der einfachen Anführungszeichen in der ursprünglichen Frage stillschweigend in doppelte Anführungszeichen geändert, nachdem ich diese Antwort gegeben hatte.

Ihr Code führt zu Compilerfehlern. Ihr erstes Codefragment:

char buf[10] ; buf = ''

ist doppelt illegal. Erstens gibt es in C kein leeres char. Sie können doppelte Anführungszeichen verwenden, um eine leere Zeichenfolge zu kennzeichnen, wie bei:

char* buf = ""; 

Das gibt Ihnen einen Zeiger auf einen NULString, dh eine Einzel Zeichenkette nur mit dem NULCharakter in ihm. Sie können jedoch keine einfachen Anführungszeichen verwenden, in denen sich nichts befindet - das ist undefiniert. Wenn Sie den NULCharakter bestimmen müssen, müssen Sie ihn angeben:

char buf = '\0';

Der Backslash ist notwendig, um vom Charakter zu unterscheiden '0'.

char buf = 0;

erreicht das gleiche, aber das erstere ist ein bisschen weniger zweideutig zu lesen, denke ich.

Zweitens können Sie Arrays nicht initialisieren, nachdem sie definiert wurden.

char buf[10];

deklariert und definiert das Array. Die Array-ID bufist jetzt eine Adresse im Speicher, und Sie können bufdurch Zuweisung nicht ändern, wo Punkte liegen. So

buf =     // anything on RHS

ist illegal. Ihre zweiten und dritten Codefragmente sind aus diesem Grund illegal.

Um ein Array zu initialisieren, müssen Sie dies zum Zeitpunkt der Definition tun:

char buf [10] = ' ';

Sie erhalten ein Array mit 10 Zeichen, wobei das erste Zeichen das Leerzeichen '\040'und der Rest das Zeichen NUList '\0'. Wenn ein Array mit einem Initialisierer deklariert und definiert wird, werden die Array-Elemente (falls vorhanden), die über die Elemente mit den angegebenen Anfangswerten hinausgehen, automatisch aufgefüllt 0. Es wird keinen "zufälligen Inhalt" geben.

Wenn Sie das Array deklarieren und definieren, es aber nicht wie folgt initialisieren:

char buf [10];

Sie werden zufälligen Inhalt in allen Elementen haben.

ausführlich
quelle
"Um ein Array zu initialisieren, müssen Sie dies zum Zeitpunkt der Definition tun ..." Dies und die folgende Zeile machen dies besser als die akzeptierte Antwort.
Laurie Stearn
25
  1. Diese sind gleichwertig

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Diese sind gleichwertig

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Diese sind gleichwertig

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

Der relevante Teil der Initialisierung des C11-Standardentwurfs n1570 6.7.9 lautet:

14 Ein Array vom Typ Zeichen kann durch ein Zeichenfolgenliteral oder ein UTF-8-Zeichenfolgenliteral initialisiert werden, das optional in geschweiften Klammern eingeschlossen ist. Aufeinanderfolgende Bytes des Zeichenfolgenliteral (einschließlich des abschließenden Nullzeichens, wenn Platz vorhanden ist oder wenn das Array eine unbekannte Größe hat) initialisieren die Elemente des Arrays.

und

21 Wenn eine in Klammern eingeschlossene Liste weniger Initialisierer enthält als Elemente oder Elemente eines Aggregats oder weniger Zeichen in einem Zeichenfolgenliteral, das zum Initialisieren eines Arrays bekannter Größe verwendet wird, als Elemente im Array, der Rest des Aggregats muss implizit genauso initialisiert werden wie Objekte mit statischer Speicherdauer.

Daher wird '\ 0' angehängt, wenn genügend Speicherplatz vorhanden ist , und die verbleibenden Zeichen werden mit dem Wert static char c;initialisiert, den a innerhalb einer Funktion initialisieren würde.

Schließlich,

10 Wenn ein Objekt mit automatischer Speicherdauer nicht explizit initialisiert wird, ist sein Wert unbestimmt. Wenn ein Objekt mit statischer oder Thread-Speicherdauer nicht explizit initialisiert wird, gilt Folgendes:

[-]

  • Wenn es einen arithmetischen Typ hat, wird es auf (positiv oder ohne Vorzeichen) Null initialisiert.

[-]

Da chares sich um einen arithmetischen Typ handelt, wird garantiert, dass der Rest des Arrays auch mit Nullen initialisiert wird.

Antti Haapala
quelle
3

Interessanterweise ist es möglich, Arrays jederzeit im Programm auf irgendeine Weise zu initialisieren, vorausgesetzt, sie sind Mitglieder eines structoder union.

Beispielprogramm:

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

Ich bin mir nicht sicher, aber ich initialisiere ein Array normalerweise mit "". In diesem Fall muss ich mir keine Sorgen um das Null-Ende der Zeichenfolge machen.

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
quelle
Sie sollten die implizite int- Regel nicht wirklich verwenden . Sie sollen eine Art angeben , für main()(und Sie sollten auch verwenden void, dh int main(void) { ... }. C99 wurde von dieser Regel zu befreien, so dass dieser Code nicht für C99 kompilieren und später. Die andere Sache , hier zu beachten ist , dass beginnend mit C99, wenn Sie weglassen returnin main, es gibt eine automatische return 0;Platzierung / Implikation vor dem }Ende von at main. Sie verwenden die implizite int-Regel, die nur vor C99 funktioniert, aber Sie verwenden die implizite Regel, die nur returnmit C99 und höher funktioniert . Diese beiden sind offensichtlich widersprüchlich .
RastaJedi