1

hace poco empecé a sumergirme en este mundo de la programación. Claramente, estoy dando mis primeros pasos. Ahora, intentaba hacer un programa que resuelva sistemas de ecuaciones, pero en la entrada de datos ya tengo un problema cuya causa no logro identificar. Me alegraría bastante encontrar alguna respuesta.

La idea de la entrada de datos, es identificar cuantas ecuaciones tiene el sistema y, posteriormente, recoger cada una en una cadena (array) de caracteres. Luego, otra función se encarga de evaluar cada carácter de la cadena y decidir si es un coeficiente, una variable o un signo. Luego, almacena estos datos en una estructura que se crea para cada ecuación. La función que me da problemas es la que recoge la cadena de caracteres, pues cuando ejecuto el programa recibe hasta el sexto carácter y se finaliza por algún error:

introducir el código aquí

    typedef struct ecua
        {                       /*cabecera del programa*/
            int coefi[8];
            char varia[8];                     /*estructura para cada ecuacion*/
            char sig[8];
        }ecuacion;
        void entrada(char**ecu);
        int con1;
        int con2;
        int n;  
    
        int main()   /* en la funcion main, declaro y defino punteros para trabajar con memoria dinamica*/        
        {
            printf("Por favor, indique cuantas ecuaciones hay en el sistema a solucionar\n");
            scanf("%d",&con1);
            ecuacion *pun;
            char *ec; 
            pun=(struct ecua*)malloc(sizeof(int)*8+sizeof(char)*16);
            for(con2=1;con2<=con1;con2++)
            {
                if(con2>1)
                {
                    pun=(struct ecua*)realloc(pun,(sizeof(int)*8+sizeof(char)*16));
                } /*asigna memoria para la clasificación que se hará posteriormente en otra función*/
                entrada(&ec); 
        }
            return 0;
        
        }
    void entrada(char**ecu)     /*no se cual es el error en esta funcion :( */
    {
         n=0;
        *ecu=(char*)malloc(sizeof(char));
        printf("introduzca la ecuacion %d. Para terminar, pulsa enter\n",con2);
        *ecu[0]=getche();  
        while(*ecu[n]!=(13))                       /*Mientras el caracter no sea enter,*/      
        {
            n++;
            *ecu=(char*)realloc(*ecu,sizeof(char));
            *ecu[n]=getche();
            
        }
        return;

}
Nathra1967
  • 65
  • 5
  • Revisé tu código y no queda claro que quieres hacer.. ¿Por qué razón usas `getche()` de conio.h? Si quieres escanear una ecuación lo más óptimo es usar `scanf()` con un string, he visto que usas memoria dinámica, entonces sería válido esa manera. ¿Cuál es la razón de que uses `getche()` en la función `entrada()`? –  Jul 18 '20 at 18:13
  • Uso el getche() porque si escaneo una cadena se correría el riesgo de que algunos caracteres se graben fuera de la memoria asignada en caso de que esta no alcanzara a contener todo el string. Claramente, podría crear un espacio para una cadena que contenga una ecuación de digamos 20 caracteres y luego escanearla, pero seria una limitante en caso de querer introducir una ecuación larga o, ineficiente en caso de que la ecuación sea pequeña. No se si estoy omitiendo algo. – Nathra1967 Jul 18 '20 at 18:47

1 Answers1

2

Analicemos detenidamente la función entrada:

void entrada(char**ecu)    
{
    n=0;
    *ecu=(char*)malloc(sizeof(char));
    printf("introduzca la ecuacion %d. Para terminar, pulsa enter\n",con2);
    *ecu[0]=getche();  
    while(*ecu[n]!=(13))                          
    {
        n++;
        *ecu=(char*)realloc(*ecu,sizeof(char));
        *ecu[n]=getche();
            
    }
    return;
}

Hay dos fallas a simple vista:

1.- Esa no es la forma correcta de usar la función realloc, debido a que, en cada iteración, le pasas el mismo tamaño (en este caso un byte), por lo tanto, ¡no estás redimensionando el array!

El segundo parámetro de realloc espera un nuevo tamaño en bytes. Al principio, el array consume 1 byte, luego al redimensionar, le debes pasar 2 bytes, luego en la tercera iteración debes pasar 3 bytes y así sucesivamente.

Así que al segundo parámetro deberías pasar esto:

(n+1) * sizeof(char)

Se le suma un más uno a n porque hay que dejar un espacio adicional para el caracter nulo, ya que indica el fin de la cadena.

2.- Esta sentencia ocasiona un fallo de segmentación:

*ecu[n]

La sentencia de arriba es equivalente a:

**(ecu + n)

Ahora, la pregunta es, ¿qué pasa si n = 1? Simplemente estaríamos accediendo a una dirección de memoria que al programa no le pertenece y esto hace que el SO mate el proceso. Todo esto se debe porque esta expresión se la usa para acceder a X posición de un array de punteros, pero este no es el caso, ya que el puntero doble (ecu) solo puede acceder a un puntero.

3. ¡No necesitas la función getche! ¡No es estándar! Usa la función getchar que sí es estándar.

La función getchar lee un caracter a la vez del búfer del teclado.

La función entrada quedaría así si seguimos las correcciones mencionadas:

void entrada(char** ecu)
{
    int n = 0;
    int ch;
    char* aux;
    char* buf;
    buf = malloc(sizeof(char));
    //Si hubo una falla al asignar memoria..
    if(buf == NULL)
    {
        //Para detectar el error..
        *ecu = NULL;
        return;
    }
    //Recorremos el búfer del teclado hasta encontrar un salto de línea..
    while((ch = getchar()) != '\n')
    {
        buf[n++] = ch;
        //Debemos usar un puntero auxiliar..
        aux = buf;
        //Ya que la función realloc puede retornar NULL si no pudo reservar memoria y esto sobrescribe el contenido del puntero y perdemos la dirección base donde se aloje el array.
        buf = realloc(buf, (n+1)* sizeof(char));
        if(buf == NULL)
        {
            //De este modo, tenemos la oportunidad de liberar la memoria..
            free(aux);
            //Para detectar el error..
            *ecu = NULL;
            return;
        }
    }
    //El caracter nulo debe estar en la última posición del array..
    buf[n] = '\0';
   //Actualizamos el puntero al que apunte "ecu"..
    *ecu = buf;
}

Modo de uso:

int main(void) 
{
    char* ecu;
    printf("Introduzca algo:\n");
    entrada(&ecu);
    if(ecu == NULL)
    {
        printf("Error: No se puso asignar memoria!");
        return 1;
    }
    printf("%s\n", ecu);
    //Se debe liberar la memoria manualmente.
    free(ecu);
    return 0;
}

Otro problema es el código que tienes en la función main, te has complicado demasiado y la forma como calculas el tamaño en bytes sigo sin entender porque lo hiciste así.

Lo único que debiste hacer es crear un array de estructuras de N elementos. Así que si N = 2 es porque tendrás dos ecuaciones.

En código quedaría así:

typedef struct ecua
{                      
    int coefi[8];
    char varia[8];                    
    char sig[8];
}ecuacion;

//Podemos omitir el nombre del parámetro cuando declaramos la función.
void entrada(char**);

/*
¡No necesitamos usar variables globales! ¡No es necesario en este caso!

*/

//Según el estándar, el encabezado de la función main debe ser: int main(void)
int main(void)       
{
    int cont1;
    ecuacion *pun;
    char *ec; 
    printf("Por favor, indique cuantas ecuaciones hay en el sistema a solucionar\n");
    scanf("%d",&con1);
    while(getchar() != '\n'); //Limpia el búfer del teclado.
    //Crea un array de estructuras de N elementos
    pun = malloc(con1 * sizeof(ecuacion));
    if(pun == NULL)
    {
        printf("Error: No se puso asignar memoria!");
        return 1;
    }
    //Recorremos el array de estructuras
    for(int con2 = 0; con2  < con1; ++con2 )
    {
        printf("introduzca la ecuacion %d. Para terminar, pulsa enter\n", con2 + 1);
        entrada(&ec);
        if(ec == NULL)
        {
            printf("Error: No se puso asignar memoria!");
            return 1;
        } 
        //aquí el código que quieras, para poder acceder al ARRAY lo haces así: pun[1].sig[0] (es un ejemplo claro).
    }
    return 0;
}

void entrada(char** ecu)
{
    int n = 0;
    int ch;
    char* aux;
    char* buf;
    buf = malloc(sizeof(char));
    if(buf == NULL)
    {
        *ecu = NULL;
        return;
    }
    while((ch = getchar()) != '\n')
    {
        buf[n++] = ch;
        aux = buf;
        buf = realloc(buf, (n+1)* sizeof(char));
        if(buf == NULL)
        {
            free(aux);
            *ecu = NULL;
            return;
        }
    }
    buf[n] = '\0';
    *ecu = buf;
}

Observación:

1.- No abuses de las variables globales. Mira este hilo.

2.- No olvides de liberar la memoria, de lo contrario, habrá fuga de memoria.

MrDave1999
  • 7,491
  • 1
  • 7
  • 22
  • Pasa algo muy curioso a la hora de probar el codigo, pues parece que el salto de linea que finaliza la función **scanf** para _con1_, también se toma como el primer carácter de **getchar** en la función entrada, por lo que pasa directamente a la ecuacion 2 y la 1 solo con un caracter _'\n'_. Lo resolví utilizando un **do while** en la función entrada, sin embargo, el primer carácter sigue siendo la secuencia de escape y deberá tratarse de manera especial la primera ecuación a la hora de asignar coeficientes y variables a la estructura. Creo que solo hará falta un condicional con _con1_ – Nathra1967 Jul 19 '20 at 14:40
  • @GabrielAvila Esa parte se me olvidó. Debes limpiar el búfer del teclado con este código : `while(getchar() != '\n');`. Sí, cuando se ejecute el primer *scanf* para leer el entero, el búfer queda con un salto de línea, así que cuando la función *getchar* se ejecute, no pausará el programa, porque si o si, el búfer debe estar limpio. Editaré la respuesta. – MrDave1999 Jul 19 '20 at 17:32
  • Hola de nuevo. continué con la escritura del código y, en la estructura, cree un array de 9 enteros `int coef[9];`. sin embargo, luego de asignar la memoria con `pun = malloc(con1 * sizeof(ecuacion));`, si trato de acceder con esta sentencia `pun[0].coef[4]=0;`, el programa falla. No sucede lo mismo con coef[3]. Alguna idea de a que se debe esto? – Nathra1967 Jul 21 '20 at 10:51
  • @GabrielAvila Elabora otra pregunta detallando ese problema. – MrDave1999 Jul 21 '20 at 14:05