Estoy tratando de compilar y ejecutar el siguiente programa C en mis máquinas Ubuntu y Windows con GCC y VC9. Sin embargo, me enfrento a los siguientes problemas:
En la máquina Ubuntu:
GCC compila bien, pero cuando se ejecuta, me muestra este mensaje:
Segmentation Fault (Core Dump).
En la máquina de Windows:
VC9 Compila y funciona bien. GCC compila bien, pero el proceso termina cuando se ejecuta el programa.
Necesito su asistencia experta aquí. Aquí está mi 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;
}
Actualizar:
El crédito es para Eliah por no solo ayudarme a rastrear el error, sino también presentarme gdb
y su herramienta de seguimiento ( bt
) que es tan útil para depurar un programa compilado por gcc. Aquí está la versión modificada, trabajé después de alguna prueba y error:
#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;
}
Respuestas:
Se produce un error de segmentación cuando un programa intenta acceder a la memoria fuera del área que se le ha asignado.
En este caso, un programador de C experimentado puede ver que el problema está sucediendo en la línea donde
sprintf
se llama. Pero si no puede saber dónde está ocurriendo su falla de segmentación, o si no quiere molestarse en leer el código para tratar de resolverlo, entonces puede construir su programa con símbolos de depuración (congcc
, la-g
bandera hace esto ) y luego ejecutarlo a través de un depurador.Copié su código fuente y lo pegué en un archivo que nombré
slope.c
. Luego lo construí así:(El
-Wall
es opcional. Es solo para que produzca advertencias para más situaciones. Esto también puede ayudar a descubrir qué podría estar mal).Luego ejecuté el programa en el depurador
gdb
ejecutando primerogdb ./slope
para comenzargdb
con el programa, y luego, una vez en el depurador, dándole elrun
comando al depurador:(No se preocupe por mi
you have broken Linux kernel i386 NX
...support
mensaje; no evita quegdb
se use de manera efectiva para depurar este programa).Esa información es muy críptica ... y si no tiene símbolos de depuración instalados para libc, obtendrá un mensaje aún más críptico que tiene una dirección hexadecimal en lugar del nombre de la función simbólica
_IO_default_xsputn
. Afortunadamente, no importa, porque lo que realmente queremos saber es en qué parte del programa está ocurriendo el problema.Entonces, la solución es mirar hacia atrás, para ver qué llamadas de función se llevaron a cabo antes de esa llamada de función en particular en una biblioteca del sistema donde
SIGSEGV
finalmente se activó la señal.gdb
(y cualquier depurador) tiene esta característica incorporada: se llama traza de pila o traza inversa . Utilizo elbt
comando depurador para generar una traza inversa engdb
:Puede ver que su
main
función llama a lacalc_slope
función (que ha previsto) y luegocalc_slope
llamasprintf
, que (en este sistema) se implementa con llamadas a un par de otras funciones de biblioteca relacionadas.Lo que generalmente le interesa es la llamada de función en su programa que llama a una función fuera de su programa . A menos que haya un error en la biblioteca / bibliotecas que esté utilizando (en este caso, la biblioteca C estándar
libc
provista por el archivo de la bibliotecalibc.so.6
), el error que causa el bloqueo está en su programa y con frecuencia estará cerca del última llamada en su programa.En este caso, eso es:
Ahí es donde llama su programa
sprintf
. Sabemos esto porquesprintf
es el siguiente paso. Pero incluso sin que eso lo diga , usted sabe esto porque eso es lo que sucede en la línea 26 , y dice:En su programa, la línea 26 contiene:
(Siempre debe usar un editor de texto que muestre automáticamente los números de línea, al menos para la línea en la que se encuentra actualmente. Esto es muy útil para interpretar tanto los errores en tiempo de compilación como los problemas de tiempo de ejecución revelados al usar un depurador).
Como se discutió en la respuesta de Dennis Kaarsemaker ,
s
es una matriz de un byte. (No es cero, porque el valor que le ha asignado""
es de un byte, es decir, es igual a{ '\0' }
, de la misma manera que"Hello, world!\n"
es igual a{ 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n', '\0' }
).Entonces, ¿por qué esto podría funcionar en alguna plataforma (y aparentemente funciona cuando se compila con VC9 para Windows)?
La gente suele decir que cuando asigna memoria y luego intenta acceder a la memoria externa, se produce un error. Pero eso no es realmente cierto. De acuerdo con los estándares técnicos C y C ++, lo que esto realmente produce es un comportamiento indefinido.
En otras palabras, ¡cualquier cosa puede pasar!
Aún así, algunas cosas son más probables que otras. ¿Por qué es que una pequeña matriz en la pila, en algunas implementaciones, parece funcionar como una matriz más grande en la pila?
Esto se reduce a cómo se implementa la asignación de la pila, que puede variar de una plataforma a otra. Su ejecutable puede asignar más memoria a su pila de la que está destinada a ser utilizada en cualquier momento. A veces esto puede permitirle escribir en ubicaciones de memoria que no ha reclamado explícitamente en su código. Es muy probable que esto sea lo que sucede cuando compila su programa en VC9.
Sin embargo, no debe confiar en este comportamiento incluso en VC9. Potencialmente podría depender de diferentes versiones de bibliotecas que podrían existir en diferentes sistemas de Windows. Pero aún más probable es el problema de que el espacio de pila adicional se asigne con la intención de que realmente se use, por lo que en realidad se puede usar.Luego experimenta la pesadilla completa del "comportamiento indefinido", donde, en este caso, más de una variable podría terminar almacenada en el mismo lugar, donde escribir en una sobrescribe a la otra ... pero no siempre, porque a veces escribe en variables se almacenan en caché en los registros y en realidad no se realizan de inmediato (o las lecturas de las variables se pueden almacenar en caché, o se puede suponer que una variable es la misma que antes porque el compilador sabe que la memoria asignada a ella no se ha escrito a través de la variable misma).
Y eso me lleva a la otra posibilidad probable de por qué el programa funcionó cuando se creó con VC9. Es posible, y algo probable, que alguna matriz u otra variable haya sido asignada realmente por su programa (lo que puede incluir ser asignado por una biblioteca que esté utilizando su programa) para usar el espacio después de la matriz de un byte
s
. Entonces, tratars
como una matriz de más de un byte tendría el efecto de acceder al contenido de esas / esas variables / matrices, lo que también podría ser malo.En conclusión, cuando tiene un error como este, es afortunado recibir un error como "Error de segmentación" o "Error de protección general". Cuando no tenga eso, es posible que no se entere hasta que sea demasiado tarde que su programa tenga un comportamiento indefinido.
fuente
Hola desbordamiento de búfer!
Usted asigna un byte para una cadena en la pila y luego procede a escribir más de un byte en él. Y para colmo, lees más allá del final de esa matriz. Lea un manual en C y especialmente la sección sobre cadenas y asignación de memoria para ellos.
fuente