[C con Clase] Error: Fallo de segmentación

Programante programante en gmail.com
Mar Ene 29 13:15:02 CET 2008


Jose Luis escribió:
> Gracias por la corrección. Entiendo lo que ha provocado el error, y la 
> conveniencia de pasar el puntero como argumento de la función. Pero 
> hay algunas cosas que no termino de entender en el diseño típico:
>
>         char * DectoBase( TIPO1 numdec, TIPO2 base, char *numbase )
>
> Empezando por la declaración de la función ¿qué necesidad hay de que 
> retorne el mismo puntero que se pasa como parámetro?
Puesto que se lo pasas como parámetro no sería necesario que lo 
devuelva. Podrías devolver un booleano indicando si salió bien o no con 
la misma funcionalidad.
Devolver el mismo puntero resulta (en ocasiones) cómodo y se usa en 
diversas funciones estándar, por lo que no es extraño usarlo también.

Piensa por ejemplo en  una construcción del tipo
char* Base;
if (Base = DectoBase(A, B, malloc(50)) {
    printf("La base es %s\n", Base);
    free(Base);
} else
    printf("No se pudo calcular Base\n");

> Tampoco tengo muy claro la utilidad de if(!numbase) return 0; aunque 
> he hecho la siguiente interpretación:
Vas a tener que trabajar con ese puntero. Si ese puntero es nulo, tu 
programará terminará en esa función con un fallo de segmentación. Ese if 
no es más que una guarda para evitar trabajar con un puntero nulo. Si el 
usuario de la función se encarga de verificar que no pasa nunca punteros 
nulos a la función, no hay problema alguno. Es más, muchas funciones 
estándar de C fallarán si les pasas un puntero nulo para que trabajen 
con él: strlen(), puts()...

En el ejemplo anterior, malloc() puede devolver un puntero nulo. Si 
realizas esa comprobación, funcionará siempre, porque el error pasa a la 
gestión de fallos de DectoBase(). Sino, tienes que comprobar el 
resultado de malloc() antes de pasárselo a DectoBase (lo cual es en 
todos los casos una buena idea).

>
>
> #include <iostream>
> using namespace std;
> typedef unsigned long long int ULLINT;
> typedef unsigned short int USINT;
>
> const char DIGITOS[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
>                         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
>
> void DectoBase(ULLINT numdec, USINT base, char *numbase);
> ULLINT Pot(USINT base, USINT exponente);
>
> int main()
> {
>     ULLINT numdec;
>     USINT base, nDig, nCant;
>     char *numbase;
>     numbase = NULL;
>    
>     cout << "\n Numero, base: ";
>     cin >> numdec >> base;
>    
>     if(base >= 2 && base <= 16) nCant = 0;
>     {
>         /* Calcula el número de dígitos de numdec: */
>         nDig = 0;
Esto no está haciendo lo que quieres. Si base está entre 2 y 16 nCant 
pasa a valer 0.
E *independientemente del valor de base* hace el cálculo de dígitos de 
numdec.

> y para terminar (lamento mi torpeza) tampoco logro entender la 
> utilidad del parámetro nCant en el segundo caso.
>
Yo tampoco.
Defines la función y su prototipo como void DectoBase(ULLINT numdec, 
USINT base, char *numbase); (tres parámetros)
pero luego la llamas con cuatro parámetros:  DectoBase(numdec, base, 
numbase, nCant);
En el mejor de los casos ignorará el último parámetro (por la convención 
de llamadas cdecl, con stdcall fallaría) aunque debería darte algún aviso.
Compilando como C++ te dirá que falta el prototipo e intentará enlazar 
con una función DectoBase de cuatro parámetros (sobrecargada) que es 
incapaz de encontrar.

Ahora, ¿para qué necesita esa función un parámetro nCant?
Le estás pasando un puntero a una zona de memoria para que escriba en 
ella, y usa toda la que necesite. ¿Qué pasa si tu le pasas un puntero a 
10 bytes de memoria y DectoBase necesita 15? Pues usará 15 
sobreescribiendo lo que haya en otras variables cercanas, produciendo un 
desbordamiento de Buffer. Por ello tienes que pasarle un parámetro 
diciendo la memoria máxima que se le permite usar.




Más información sobre la lista de distribución Cconclase