Handling files in c prints garbage in reading and later writing

0

Hello, I have this code where it reads a string from a file that contains names in the following way

Robert Fair
Amanda Insley
Daniel Berryhill

This code compiles sometimes and others do not, even when compiling and executing it, in the file garbage is kept in addition to the word, for example

 ‚Jê2+b"¢?Robert Fair
B0Ê4Amanda Insley
Daniel Berryhill
êr&rGarry Puckett

Code:

#include <stdlib.h>
#include <string.h>
#include <time.h>


#define fila 50000  
#define columna 50

int EXTRAE_DATOS(char *variable, FILE *file);
int NUMEROS_AL();

int main()
{
    int n,a,i=0;
    char **nombre;

    FILE *alias;
    alias = fopen("nombres_aleatorios.txt","r");
    if (alias == NULL)
    {
        printf("\nError: El archivo 'nombres_aleatorios.txt' no se ha encontrado.\n");
    }

    FILE *escribo;
    escribo = fopen("nombres_generados.txt","w");
    if (escribo == NULL)
    {
        printf("\nError: El archivo 'nombres_generados.txt' no se ha encontrado.\n");
    }


    nombre=(char**)malloc(fila*sizeof(char*));

     for(i=0;i<fila;i++)
    {
        nombre[i]=(char*)malloc(columna*sizeof(char));
        if(nombre[i]==NULL)
        {
            printf("No se ha podido reservar memoria");
            exit(1);
        }
    }

    srand(time(NULL));       //Semilla para generar números aleatorios
    i=0;

    fseek(alias,0,SEEK_SET);
    while(!feof(alias))
    {
        fgets(*(nombre+i),200,alias);
        i++;
    }

    for(n=0;n<fila;n++)
    {
        a=NUMEROS_AL();
        fprintf(escribo,"%s",nombre[a]);
    }

    fclose(escribo);
    fclose(alias);
    free(nombre);
}


int NUMEROS_AL()
{
    int num;
    //numero = rand () % (N-M+1) + M;   // Este está entre M (valor minimo) y N (valor maximo)
    num = rand() % fila-1; //Numeros aleatorios entre 0 y 30 -> quedará entre 1 y 31
    return num;
}
    
asked by EmiliOrtega 01.09.2017 в 00:41
source

1 answer

1

Your program has some inconsistencies:

Sizes that do not match

#define columna 50

nombre[i]=(char*)malloc(columna*sizeof(char));
//                      ^^^^^^^ = 50

while(!feof(alias))
{
    fgets(*(nombre+i),200,alias);
    //                ^^^ 200 > 50
    i++;
}

As you see in the comments, you reserve space for chains of length 50 and, later, you make readings of up to 200 characters. That can lead to the program ending up treading memory. If you define a constant ... use it, please:

fgets(*(nombre+i),columna,alias);

On the other hand, to improve the readability of the code, we would appreciate it if the #define were in upper case (code conventions):

#define COLUMNA 50

This way in the code it is easier to differentiate them from the normal variables.

Too many iterations

This is the code that supposedly generates the new file:

for(n=0;n<fila;n++)
{
    a=NUMEROS_AL();
    fprintf(escribo,"%s",nombre[a]);
}

You have a problem with the NUMEROS_AL() function:

int NUMEROS_AL()
{
    int num;
    //numero = rand () % (N-M+1) + M;   // Este está entre M (valor minimo) y N (valor maximo)
    num = rand() % fila-1; //Numeros aleatorios entre 0 y 30 -> quedará entre 1 y 31
    return num;
}

nombre will have i records ... which, since you have no control, may be greater, less or equal to fila ... you do not know it or you will not be able to deduce it at compile time. Assuming that the generator must give you numbers in the range (0, row) is wrong since the correct range should be (0, i).

On the other hand I do not understand that effort to use global variables for everything. Please, unless it is a requirement of the exercise, do not use global variables .

Your role should look like this:

int NUMEROS_AL(int maximo)
{
    return rand() % maximo; //Numeros aleatorios en el rango (0,maximo-1)
}

By the way, since C99 (dating from 1999) it is legal to declare the variables at the time of use ... as for example within the loop itself:

for(int n=0;n<fila;n++)
{
    a=NUMEROS_AL(i);
    fprintf(escribo,"%s",nombre[a]);
}

It is good practice to reduce the life of the variables to the minimum necessary to avoid silly mistakes.

As a final note on this loop, note that you are not adding a line break at the end of each name:

for(int n=0;n<fila;n++)
{
    a=NUMEROS_AL(i);
    fprintf(escribo,"%s\n",nombre[a]);
}

Memory leaks

Your program has memory leaks. That's right.

Notice that to create the array of names you use two malloc:

nombre=(char**)malloc(fila*sizeof(char*)); // (1)

for(i=0;i<fila;i++)
{
    nombre[i]=(char*)malloc(columna*sizeof(char)); // (2)
    if(nombre[i]==NULL)
    {
        printf("No se ha podido reservar memoria");
        exit(1);
    }
}

And yet at the time of releasing the memory you only make a free :

free(nombre);

What about the reservations in each row? It happens that they get lost (hence you have memory leaks). The memory releases in the case of arrays or nesting have to be done in reverse order to how reservations have been made:

for( int i=0; i<fila; i++ )
  free(nombre[i]);
free(nombre);
    
answered by 01.09.2017 / 08:46
source