Nenhum erro fora dos limites

Eu tenho esse código em C, que leva em monte de char s

 #include # define NEWLINE '\n' int main() { char c; char str[6]; int i = 0; while( ((c = getchar()) != NEWLINE)) { str[i] = c; ++i; printf("%d\n", i); } return 0; } 

A input é: testtesttest

Saída: 1 2 3 4 5 6 7 8 117 118 119 120

Minhas perguntas são:

  1. Por que eu não obtenho uma exceção fora de limite (falha de segmentação) embora eu exceda claramente a capacidade da matriz?

  2. Por que os números na saída subitamente saltam para números muito grandes?

Eu tentei isso em C ++ e tenho o mesmo comportamento. Alguém poderia por favor explicar qual é a razão para isso?

    1. C não verifica os limites da matriz. Uma falha de segmentação só ocorrerá se você tentar excluir um ponteiro para a memory que seu programa não tem permissão para acessar. Basta ir além do final de uma matriz para causar esse comportamento. Comportamento indefinido é apenas isso – indefinido. Pode parecer que funciona muito bem, mas você não deve confiar em sua segurança.
    2. Seu programa faz com que o comportamento indefinido, acessando a memory após o final da matriz. Neste caso, parece que um dos seus str[i] = c escreve substitui o valor em i .
    3. C ++ tem as mesmas regras que C neste caso.

    Quando você acessa um índice de matriz, C e C ++ não fazem verificação vinculada. As falhas de segmentação ocorrem apenas quando você tenta ler ou gravar em uma página que não foi alocada (ou tentar fazer algo em uma página que não é permitida, por exemplo, tentar gravar em uma página somente leitura), mas como as páginas são geralmente muito grande (múltiplos de alguns kilobytes; no Mac OS, múltiplos de 4 KB), geralmente deixa muito espaço para transbordar.

    Se sua matriz está na pilha (como a sua), pode ser ainda pior, já que a pilha é geralmente muito grande (até vários megabytes). Essa também é a causa de preocupações de segurança: gravar os limites de uma matriz na pilha pode sobrescrever o endereço de retorno da function e levar à execução arbitrária de código (as violações de segurança do “estouro de buffer”).

    Os valores que você obtém quando lê são exatamente o que acontece nesse lugar em particular. Eles são completamente indefinidos .

    Se você usa C ++ (e tem a sorte de trabalhar com C ++ 11), o padrão define o tipo std::array , que é uma matriz que conhece seus limites. O método at irá lançar se você tentar ler após o final dele.

    C não verifica os limites da matriz.

    Na verdade, uma falha de segmentação não é especificamente um erro de tempo de execução gerado por exceder os limites da matriz. Pelo contrário, é um resultado da proteção de memory que é fornecida pelo sistema operacional. Ocorre quando o seu processo tenta acessar a memory que não pertence a ele, ou se ele tenta acessar um endereço de memory que não existe.

    Porque o C / C ++ não verifica limites.

    Arrays são indicadores internos para um local na memory. Quando você chama arr[index] que ele faz é:

     type value = *(arr + index); 

    Os resultados são grandes números (não necessariamente) porque são valores de lixo. Apenas como uma variável não inicializada.

    Escrever fora dos limites da matriz (na verdade, mesmo apenas executando o ponteiro aritmético / array subscripting, mesmo se você não usar o resultado para ler ou escrever nada) resulta em um comportamento indefinido . Comportamento indefinido não é um erro relatado ou reportável; mede seu programa poderia fazer qualquer coisa. É muito perigoso e você é totalmente responsável por evitá-lo. C não é Java / Python / etc.

    A alocação de memory é mais complicada do que parece. A variável “str”, neste caso, está na pilha, próxima a outras variables, portanto não é seguida por memory não alocada. A memory também é geralmente alinhada à palavra (uma “palavra” é de quatro a oito bytes.) Você possivelmente estava mexendo com o valor de outra variável, ou com algum “preenchimento” (espaço vazio adicionado para manter o alinhamento de palavras) ou algo totalmente diferente .

    Como R .. disse, é um comportamento indefinido. Condições fora dos limites podem causar um segfault … ou podem causar corrupção silenciosa de memory. Se você estiver modificando a memory que já foi alocada, isso não será detectado pelo sistema operacional. É por isso que erros fora dos limites são tão insidiosos em C.

    Você tem que compilar assim:

     gcc -fsanitize=address -ggdb -o test test.c 

    Há mais informações aqui.