2012-04-13 22 views
50

Przez przypadek stwierdziłem, że linia char s[] = {"Hello World"}; została poprawnie skompilowana i wygląda na to, że jest traktowana tak samo jak char s[] = "Hello World";. Czy pierwsza ({"Hello World"}) nie jest tablicą zawierającą jeden element, który jest tablicą znaków, więc deklaracja dla s powinna odczytać char *s[]? W rzeczywistości, jeśli zmienię go na char *s[] = {"Hello World"};, kompilator również zaakceptuje go, zgodnie z oczekiwaniami.Nawiasy wokół literału ciągu znaków w deklaracji tablicy znaków są poprawne? (np. char s [] = {"Hello World"})

Wyszukiwanie odpowiedzi, jedynym znalezionym miejscem, które o tym wspomniałem jest this one, ale nie ma cytowania normy.

Moje pytanie brzmi: dlaczego linia char s[] = {"Hello World"}; została skompilowana, mimo że lewa strona ma typ array of char, a prawa strona to typ array of array of char?

Po to program roboczy:

#include<stdio.h> 
int main() { 
    char s[] = {"Hello World"}; 
    printf("%s", s); // Same output if line above is char s[] = "Hello World"; 
    return 0; 
} 

Dzięki za wszelkie wyjaśnienia.

P.S. Mój kompilator to gcc-4.3.4.

+0

współpracuje z mingw32 – L7ColWinters

+0

Zamieściłem podobne pytanie kilka miesięcy temu: http://stackoverflow.com/questions/8061346/in-c-is-array-initialization-with-only-one- traktowane jako element specjalnie – Antoine

+0

wow .. 40upvotes .. – Jack

Odpowiedz

64

on wolno, ponieważ standard tak mówi section 6.7.8 C99, §14:

Tablica typu znak może być zainicjowany przez ciąg znaków dosłownym, ewentualnie w nawiasach. Kolejne znaki literału ciągu znaków (w tym kończący znak null, jeśli jest miejsce lub jeśli tablica ma nieznany rozmiar) inicjują elementy tablicy.

Oznacza to, że zarówno

char s[] = { "Hello World" }; 

i

char s[] = "Hello World"; 

są niczym więcej niż cukier składniowej dla

char s[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', 0 }; 

Na powiązana uwaga (ten sam odcinek, § 11), C pozwala również na nawiasy wokół inicjalizatorów skalarnych, takich jak

int foo = { 42 }; 

który, nawiasem mówiąc, pasuje ze składni literały złożonych

(int){ 42 } 
+3

Prawie identyczny tekst jest w C++ 2003, punkt 8.5.2. –

+1

Możliwość użycia zbędnych nawiasów wokół inicjalizatorów dla obiektów skalarnych obsługuje także idiom "uniwersalnego inicjatora zerowego" w języku C, gdzie '= {0}' może być użyte do zainicjowania obiektu praktycznie * dowolnego * typu z zerami. – AnT

+0

Ogólnie rzecz biorąc, nawiasy klamrowe po prostu grupują wszystkie zawarte w nich instrukcje w pojedynczą, większą instrukcję. Dlatego nie potrzebujesz '{}' dla jednej linii 'if' gałęzi (lub podczas itd.). Kompilator po prostu szuka instrukcji _next_ po 'if' i wykonuje ją warunkowo. Tak więc, jeśli chcesz dwóch pozycji, po prostu spraw, aby wyglądały jak je, otaczając je w curlies. – dcow

22

Klamry są opcjonalne, a wyrażenie jest równoważne tylko tablicy znaków.

Można również napisać to:

int a = {100}; //ok 

Demo: http://ideone.com/z0psd

W rzeczywistości C++11 uogólnia tę samą składnię, aby zainicjować non-macierze, a także tablice, jednostajnie. Więc C++11, można mieć te:

int a{}; //a is initialized to zero, and it is NOT an array 

int b[]{1,2,3,4}; //b is an array of size 4 containing elements 1,2,3,4 

int c[10]{}; //all 10 elements are initialized to zero 

int *d{}; //pointer initialized to nullptr 

std::vector<int> v{1,2,3,4,5}; //vector is initialized uniformly as well. 
2

może się mylę, ale myślę, że to nie jest tablicą tablic znaków, ale blok zawiera tablicę znaków. int a = {1}; może również działać.

3

jakakolwiek zmienna (w int, char, etc.) tak tablicą długości 1.

char s = {0}; 

działa tak samo.

1

[...] W rzeczywistości, jeśli zmienię go char * s [] = { "Hello Świat"}; kompilator przyjmuje ją jako dobrze, jak oczekiwano

Kompilator accepets, bo właściwie robisz tablicę 2D elementów wielkości niezdefiniowane, gdzie przechowywane tylko jeden element, ciąg "Hello World". Coś takiego:

char* s[] = {"Hello world", "foo", "baa" ...}; 

Nie można pominąć bracets w tym przypadku.

1

to dozwolone przez normy C++, jak również, Odniesienie:

[dcl.init.string] §1

Tablica wąskich znaków ([basic.fundamental]) char16_t tablicy, char32_t tablicy lub wchar_t macierzy może być zainicjalizowany przez wąski literał łańcuchowy, literał łańcuchowy char16_t, literał łańcuchowy char32_t lub literał o szerokim łańcuchu, odpowiednio, lub przez odpowiednio napisany ciąg literału zamknięty w nawiasach klamrowych ([lex.string]). [Ciach]