Dado que uma string C é uma matriz de caracteres terminada em nulo:
const char str1[] = {"abc"};
const char str2[] = {'a', 'b', 'c', '\0'};
const char str3[] = {97, 98, 99, '\0'};
são os mesmos.
Então, por que é possível gerar uma matriz de strings como esta:
const char * str_arr[] = {"abc", "ABCD"};
const char * str_arr[] = { str1, str2, str3 };
mas não assim? :
const char * str_arr[] = { {'a', 'b', 'c', '\0'}, {'A', 'B', 'C', 'D', '\0'} };
fatal error: excess elements in scalar initializer
Eles funcionam devido às regras em C 2018 6.7.9 sobre como os inicializadores são processados:
const char str1[] = {"abc"};
, uma string literal é fornecida para inicializar uma matriz deconst char
. 6.7.9 14 diz “Uma matriz de tipo de caractere pode ser inicializada por uma cadeia de caracteres literal ou uma cadeia de caracteres UTF–8 literal, opcionalmente entre colchetes. Bytes sucessivos da string literal (incluindo o caractere nulo de terminação se houver espaço ou se a matriz for de tamanho desconhecido) inicializam os elementos da matriz.”const char str2[] = {'a', 'b', 'c', '\0'};
, uma lista deint
valores (as constantes de caracteres têm o tipoint
) é fornecida para inicializar um array. 6.7.9 17 nos diz que eles são usados para inicializar os subobjetos do array (seus elementos) em ordem.Para estes:
const char * str_arr[] = {"abc", "ABCD"};
, uma lista de strings literais é usada para inicializar uma matriz de ponteiros. Observe que esta não é uma string literal entre colchetes; são dois literais de cadeia de caracteres, portanto, não correspondem à regra acima. Não há nenhuma regra especial para strings literais sendo usadas para inicializar uma matriz de ponteiros em vez de uma matriz de tipo de caractere, portanto, ela é tratada usando outras regras de C e as duas strings literais inicializam dois elementos da matriz. Uma string literal designa uma matriz de caracteres. 6.3.2.1 3 diz que quando um array não é o operando desizeof
, o operando de unary&
, ou uma string literal usada para inicializar uma matriz, ela é convertida em um ponteiro para seu primeiro elemento. Portanto, cada uma dessas duas matrizes, aquelas designadas pelas strings literais, é convertida em um ponteiro para seu primeiro elemento, e esses ponteiros se tornam os valores iniciais destr_arr
.const char * str_arr[] = { str1, str2, str3 };
,str1
,str2
estr3
são matrizes. Como logo acima, eles são convertidos automaticamente em ponteiros para seus primeiros elementos, e esses ponteiros são usados para inicializarstr_arr
.Para isso, cada elemento de
str_arr
é umconst char *
, e o inicializador oferecido para ele é{'a', 'b', 'c', '\0'}
. Não há nenhuma regra em C que aconst char *
possa ser inicializada com uma lista deint
valores entre chaves. Quando{'a', 'b', 'c', '\0'}
aparece nos inicializadores, não tem nenhum significado especial como array. É apenas uma lista de valores. Como essa lista de valores é processada depende do contexto da inicialização. Se houvesse um array para preencher, os valores na lista poderiam ser usados para preencher os elementos do array. Mas não há array e não há regra que diga que essa lista de valores é transformada em array e um ponteiro para esse array é feito.Você realmente pode, se você os lançar para
const char []
:Você não pode inicializar um tipo de
const char *
com uma matriz dechar
s (porque onde está o ponteiro?), mas pode inicializar um tipo deconst char[]
com isso e fazer com que ele se transforme emconst char *
.