Estou tentando compilar e executar o programa C abaixo em minhas máquinas Ubuntu e Windows com GCC e VC9. No entanto, estou enfrentando problemas abaixo:
Na máquina Ubuntu:
O GCC compila bem, mas, quando executado, esse prompt é mostrado:
Segmentation Fault (Core Dump).
Na máquina Windows:
VC9 Compila e roda bem. O GCC compila bem, mas o processo termina quando o programa é executado.
Precisa da sua assistência especializada aqui. Aqui está o meu código:
#include <string.h>
#include <stdio.h>
int calc_slope(int input1,int input2)
{
int sum=0;
int start=input1;
int end=input2;
int curr=start;
//some validation:
if (input1>input2)
return -1;
while(curr<=end)
{
if (curr>100)
{
char *s="";
int length;
int left;
int right;
int cent;
sprintf(s,"%d",curr);
length=strlen(s);
s++;
do
{
//printf("curr=%d char=%c pointer=%d length=%d \n",curr,*s,s,length);
left = *(s-1) - '0';
cent = *s - '0';
right = *(s+1) - '0';
//printf("curr=%d l=%d c=%d r=%d\n",curr,left,cent,right);
if ( (cent>left && cent>right) || (cent<left && cent<right) )
{
sum+=1; //we have either a maxima or a minima.
}
s++;
} while (*(s+1)!='\0');
}
curr++;
}
return sum;
}
int main()
{
printf("%d",calc_slope(1,150));
return 0;
}
Atualizar:
O crédito é dado a Eliah por não apenas me ajudar a rastrear o erro, mas também me apresentar gdb
e sua ferramenta de rastreamento ( bt
), que são muito úteis na depuração de um programa compilado pelo gcc. Aqui está a versão modificada, trabalhei após algumas tentativas e erros:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int calc_slope(int input1,int input2)
{
int sum=0;
int start=input1;
int end=input2;
int curr=start;
//some validation:
if (input1>input2)
return -1;
while(curr<=end)
{
if (curr>100)
{
int size=10;
char *s=(char*)malloc((size+1) * sizeof(char));
int left;
int right;
int cent;
sprintf(s,"%d",curr);
s++;
do
{
left = *(s-1) - '0';
cent = *s - '0';
right = *(s+1) - '0';
if ( (cent>left && cent>right) || (cent<left && cent<right) )
{
sum+=1; //we have either a maxima or a minima.
}
s++;
} while (*(s+1)!='\0');
}
curr++;
}
return sum;
}
int main()
{
printf("%d",calc_slope(1,150));
return 0;
}
Respostas:
Uma falha de segmentação ocorre quando um programa tenta acessar a memória fora da área que foi alocada para ele.
Nesse caso, um programador C experiente pode ver que o problema está acontecendo na linha em que
sprintf
é chamado. Mas se você não pode dizer onde está ocorrendo sua falha de segmentação ou se não deseja ler o código para tentar descobrir, pode criar seu programa com símbolos de depuração (comgcc
, o-g
sinalizador faz isso ) e execute-o através de um depurador.Copiei seu código-fonte e colei-o em um arquivo que eu nomeei
slope.c
. Então eu construí assim:(O
-Wall
é opcional. É apenas para fazer com que ele produza avisos para mais situações. Isso pode ajudar a descobrir o que também pode estar errado.)Em seguida, executei o programa no depurador
gdb
executando primeirogdb ./slope
para iniciargdb
o programa e, uma vez no depurador, fornecendo orun
comando ao depurador:(Não se preocupe com a minha
you have broken Linux kernel i386 NX
...support
mensagem; ela não impede quegdb
seja usada com eficácia para depurar este programa.)Essa informação é altamente enigmática ... e se você não possui símbolos de depuração instalados no libc, receberá uma mensagem ainda mais enigmática que possui um endereço hexadecimal em vez do nome da função simbólica
_IO_default_xsputn
. Felizmente, isso não importa, porque o que realmente queremos saber é onde o problema está acontecendo no seu programa .Portanto, a solução é olhar para trás e ver quais chamadas de função ocorreram antes dessa chamada de função específica em uma biblioteca do sistema onde o
SIGSEGV
sinal foi finalmente acionado.gdb
(e qualquer depurador) tem esse recurso embutido: é chamado de rastreamento de pilha ou backtrace . Eu uso obt
comando debugger para gerar um backtrace emgdb
:Você pode ver que sua
main
função chama acalc_slope
função (que você pretendeu) e, em seguida ,calc_slope
chamasprintf
, que é (neste sistema) implementada com chamadas para algumas outras funções relacionadas da biblioteca.Em geral, o que você está interessado é a chamada de função no seu programa que chama uma função fora do seu programa . A menos que exista um erro nas próprias bibliotecas / bibliotecas que você esteja usando (nesse caso, a biblioteca C padrão
libc
fornecida pelo arquivo da bibliotecalibc.so.6
), o erro que causa a falha está no seu programa e geralmente estará no ou próximo ao última chamada no seu programa.Nesse caso, é isso:
É para onde o seu programa chama
sprintf
. Sabemos disso porquesprintf
é o próximo passo. Mas mesmo sem declarar isso, você sabe disso, porque é o que acontece na linha 26 e diz:No seu programa, a linha 26 contém:
(Você sempre deve usar um editor de texto que mostre automaticamente os números de linha, pelo menos para a linha em que está atualmente. Isso é muito útil para interpretar erros em tempo de compilação e problemas de tempo de execução revelados ao usar um depurador.)
Como discutido na resposta de Dennis Kaarsemaker ,
s
é uma matriz de um byte. (Diferente de zero, porque o valor que você atribuiu a ele""
tem um byte de comprimento, ou seja, é igual a{ '\0' }
, da mesma maneira que"Hello, world!\n"
é igual a{ 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n', '\0' }
.)Então, por que isso ainda funciona em alguma plataforma (e aparentemente funciona quando compilado com o VC9 para Windows)?
As pessoas costumam dizer que quando você aloca memória e tenta acessar a memória fora dela, isso gera um erro. Mas isso não é verdade. De acordo com os padrões técnicos C e C ++, o que isso realmente produz é um comportamento indefinido.
Em outras palavras, tudo pode acontecer!
Ainda assim, algumas coisas são mais prováveis que outras. Por que uma pequena matriz na pilha, em algumas implementações, parece funcionar como uma matriz maior na pilha?
Isso se resume a como a alocação de pilha é implementada, o que pode variar de plataforma para plataforma. Seu executável pode alocar mais memória para sua pilha do que realmente se destina a ser usado a qualquer momento. Às vezes, isso pode permitir que você escreva na memória locais que você não reivindicou explicitamente em seu código. É muito provável que seja isso que acontece quando você cria seu programa no VC9.
No entanto, você não deve confiar nesse comportamento mesmo no VC9. Pode depender potencialmente de diferentes versões de bibliotecas que possam existir em diferentes sistemas Windows. Mas o mais provável é o problema de o espaço extra da pilha ser alocado com a intenção de que ele realmente seja usado e, portanto , possa realmente ser usado.Então você experimenta o pesadelo completo do "comportamento indefinido", onde, nesse caso, mais de uma variável pode acabar armazenada no mesmo local, onde a escrita em uma substitui a outra ... mas nem sempre, porque às vezes escreve em variáveis são armazenados em cache nos registradores e, na verdade, não são executados imediatamente (ou as leituras das variáveis podem ser armazenadas em cache, ou pode-se presumir que uma variável seja a mesma de antes), porque a memória alocada a ela é conhecida pelo compilador por não ter sido gravada por meio de a própria variável).
E isso me leva à outra possibilidade provável de por que o programa funcionou quando construído com o VC9. É possível, e de certa forma, que alguma matriz ou outra variável tenha sido realmente alocada pelo seu programa (que pode incluir ser alocada por uma biblioteca que o seu programa está usando) para usar o espaço após a matriz de um byte
s
. Portanto, tratars
como uma matriz com mais de um byte teria o efeito de acessar o conteúdo dessa / dessas variáveis / matrizes, o que também poderia ser ruim.Concluindo, quando você tem um erro como esse, é uma sorte receber um erro como "Falha na segmentação" ou "Falha na proteção geral". Quando você não tem isso, pode não descobrir até que seja tarde demais que seu programa tenha um comportamento indefinido.
fonte
Olá estouro de buffer!
Você aloca um byte para uma seqüência de caracteres na pilha e depois escreve mais de um byte nela. E ainda por cima, você lê além do final dessa matriz. Por favor, leia um manual em C e especialmente a seção sobre strings e alocação de memória para elas.
fonte