AC string é uma matriz de caracteres que termina com um terminador nulo .
Todos os caracteres têm um valor de tabela de símbolos. O terminador nulo é o valor do símbolo 0
(zero). É usado para marcar o final de uma string. Isso é necessário, pois o tamanho da string não é armazenado em nenhum lugar.
Portanto, toda vez que você alocar espaço para uma sequência, você deve incluir espaço suficiente para o caractere terminador nulo. Seu exemplo não faz isso, apenas aloca espaço para os 5 caracteres de "hello"
. O código correto deve ser:
char str[6] = "hello";
Ou, de forma equivalente, você pode escrever um código de auto-documentação para 5 caracteres mais 1 terminador nulo:
char str[5+1] = "hello";
Ao alocar memória para uma sequência dinamicamente em tempo de execução, você também precisa alocar espaço para o terminador nulo:
char input[n] = ... ;
...
char* str = malloc(strlen(input) + 1);
Se você não anexar um terminador nulo no final de uma sequência, as funções da biblioteca que esperam que uma sequência não funcione corretamente e você receberá erros de "comportamento indefinido", como saída de lixo ou falhas no programa.
A forma mais comum para escrever um caractere nulo terminador em C é usando um chamado "sequência de escape octal", procurando assim: '\0'
. Isso é 100% equivalente à gravação 0
, mas \
serve como código de auto-documentação para indicar que o zero é explicitamente destinado a ser um terminador nulo. Código como if(str[i] == '\0')
verificará se o caractere específico é o terminador nulo.
Observe que o termo terminador nulo não tem nada a ver com ponteiros nulos ou com a NULL
macro! Isso pode ser confuso - nomes muito semelhantes, mas significados muito diferentes. É por isso que o terminador nulo às vezes é chamado de NUL
um L, para não ser confundido com NULL
ponteiros nulos. Veja as respostas a esta pergunta do SO para obter mais detalhes.
O "hello"
código em seu código é chamado literal de string . Isso deve ser considerado como uma sequência de somente leitura. A ""
sintaxe significa que o compilador anexará um terminador nulo no final da cadeia literal automaticamente. Portanto, se você imprimir sizeof("hello")
, receberá 6, não 5, porque obtém o tamanho da matriz, incluindo um terminador nulo.
Ele é compilado corretamente com o gcc
De fato, nem mesmo um aviso. Isso ocorre devido a um detalhe / falha sutil na linguagem C que permite que as matrizes de caracteres sejam inicializadas com uma literal de cadeia de caracteres que contenha exatamente quantos caracteres houver espaço na matriz e, em seguida, descarte silenciosamente o terminador nulo (C17 6.7.9 / 15) O idioma está propositalmente se comportando assim por razões históricas, consulte Diagnóstico inconsistente do gcc para inicialização de strings para obter detalhes. Observe também que o C ++ é diferente aqui e não permite que esse truque / falha seja usado.
char str[] = "hello";
caso.char *str = "hello";
...str[0] = foo;
problema.sizeof
para seu uso em um parâmetro de função, especialmente quando definido como uma matriz.Do padrão C (7.1.1 Definições de termos)
Nesta declaração
a string literal
"hello"
tem a representação interna comoportanto, possui 6 caracteres, incluindo o zero final. Seus elementos são usados para inicializar a matriz de caracteres,
str
que reserva espaço apenas para 5 caracteres.O padrão C (oposto ao padrão C ++) permite essa inicialização de uma matriz de caracteres quando o zero final de um literal de seqüência de caracteres não é usado como inicializador.
No entanto, como resultado, a matriz de caracteres
str
não contém uma sequência.Se você deseja que a matriz contenha uma string, você pode escrever
ou apenas
No último caso, o tamanho da matriz de caracteres é determinado a partir do número de inicializadores da cadeia literal igual a 6.
fonte
Todas as cadeias de caracteres podem ser consideradas uma matriz de caracteres ( Sim ), todas as matrizes de caracteres podem ser consideradas cadeias de caracteres ( Não ).
Por que não? e por que isso importa?
Além das outras respostas que explicam que o comprimento de uma string não é armazenado em nenhum lugar como parte da string e nas referências ao padrão em que uma string é definida, o outro lado da página é "Como as funções da biblioteca C lidam com as strings?"
Enquanto uma matriz de caracteres pode conter os mesmos caracteres, é simplesmente uma matriz de caracteres, a menos que o último caractere seja seguido pelo caractere nulo-terminador . Esse caractere de terminação nula é o que permite que a matriz de caracteres seja considerada (manipulada como) uma string.
Todas as funções em C que esperam uma sequência como argumento esperam que a sequência de caracteres seja nula-terminada . Por quê?
Tem a ver com o modo como todas as funções de string funcionam. Como o comprimento não está incluído como parte de uma matriz, funções de string, avance na matriz até encontrar o caractere nulo (por exemplo,
'\0'
equivalente a decimal0
). Consulte Tabela e Descrição ASCII . Independentemente se você está usandostrcpy
,strchr
,strcspn
, etc .. Todas as funções de cadeia confiar na de terminação nul caráter estar presente para definir onde o fim dessa cadeia é.Uma comparação de duas funções semelhantes de
string.h
enfatizará a importância do caractere nul-terminator . Considere por exemplo:A
strcpy
função simplesmente copia bytes desrc
atédest
até que o caractere de finalização nula seja encontrado informandostrcpy
onde parar a cópia de caracteres. Agora pegue a função semelhantememcpy
:A função executa uma operação semelhante, mas não considera ou requer que o
src
parâmetro seja uma sequência. Comomemcpy
não é possível simplesmente avançar nasrc
cópia de bytesdest
até que um caractere de terminação nula seja atingido, é necessário um número explícito de bytes para copiar como um terceiro parâmetro. Esse terceiro parâmetro fornecememcpy
o mesmo tamanho de informaçãostrcpy
capaz de derivar simplesmente avançando até encontrar um caractere de terminação nula .(que também enfatiza o que está errado
strcpy
(ou qualquer função que esteja esperando uma string) se você não fornecer uma função com uma string terminada em nulo - ela não tem idéia de onde parar e terá prazer em correr pelo resto do segmento de memória invocando comportamento indefinido até que um caractere nulo seja encontrado em algum lugar da memória - ou ocorra uma falha de segmentação)É por isso que as funções que esperam uma sequência terminada em nulo devem passar por uma sequência terminada em nulo e por que isso é importante .
fonte
Intuitivamente ...
Pense em uma matriz como uma variável (contém coisas) e uma sequência como um valor (pode ser colocada em uma variável).
Eles certamente não são a mesma coisa. No seu caso, a variável é muito pequena para conter a string, portanto a string é cortada. ("cadeias de caracteres entre aspas" em C têm um caractere nulo implícito no final.)
No entanto, é possível armazenar uma string em uma matriz muito maior que a string.
Observe que os operadores habituais de atribuição e comparação (
=
==
<
etc.) não funcionam como o esperado. Mas astrxyz
família de funções chega bem perto, quando você sabe o que está fazendo. Veja as perguntas frequentes C sobre strings e matrizes .fonte