Home > Back-end >  Why doesn't this program print the name?
Why doesn't this program print the name?

Time:07-01

I’m trying to make a program that receives a text from a file where its lines are a first name, a last name and a note. I want to return the ordered lines: first the students with a grade lower than 5 and after the students passed in order of appearance in the file. The problem is that I can’t print the names and I don’t know what the fault is. The main code is as follows:

int main(int argc, char *argv[])
{   
    char line[MaxLinea 1];
    char *name;
    char *surname;
    lista_notas *mi_lista = NULL;
    int i, blank, grade;
    FILE *archivo = fopen(argv[1], "r");

    while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
    {
        grade = get_grade(line);        
        if (grade < 5) //Insertar en la lista
        {
            name = get_name(line);
            surname = get_surname(line);
            insertar(&mi_lista, name, surname, grade);
        }
    }
    
    fclose(archivo);
    archivo = fopen(argv[1], "r");
    
    while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
    {
        grade = get_grade(line);        
        if (grade > 4) //Insertar en la lista
        {
            name = get_name(line);
            surname = get_surname(line);
            insertar(&mi_lista, name, surname, grade);
        }
    }
    
    
    mostrar_lista(mi_lista);
    free_lista(mi_lista);

    //system("leaks a.out");
    return 0;
}

The get_name function is:

char *get_name(char *line)
{
    int i;
    char *name = malloc(51);
    if (name == NULL)
        exit(71);

    i = 0;
    
    while(line[i] != ' ')
        name[i] = line[i  ];
        
    name[i] = 0;

    return name;
}

If the program receives a fich.txt which content is:

Nombre1 Apellido1 8
Nombre2 Apellido2 2
Nombre3 Apellido3 6

The output must be:

Nombre2 Apellido2 2
Nombre1 Apellido1 8
Nombre3 Apellido3 6

but instead, it is:

Apellido2 2
Apellido1 8
Apellido3 6

Thanks for your help!

The full code is:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxLinea 154
//Tamaño máximo linea = 50 (nombre)   100 (apellido)   2 (nota máx 10) 
    //   2 espacios   caracter nulo? = 155

typedef struct notas{
    char *nombre;
    char *apellido;
    int nota;
    struct notas *siguiente;
} lista_notas;

int get_grade(char *line);
char *get_name(char *line);
char *get_surname(char *line);
void insertar(lista_notas **ptr, char *name, char *surname, int grade);
void mostrar_lista(lista_notas *ptr);
void free_lista(lista_notas *ptr);

int main(int argc, char *argv[])
{   
    char line[MaxLinea 1];
    char *name;
    char *surname;
    lista_notas *mi_lista = NULL;
    int i, blank, grade;
    FILE *archivo = fopen(argv[1], "r");

    while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
    {
        grade = get_grade(line);        
        if (grade < 5) //Insertar en la lista
        {
            name = get_name(line);
            surname = get_surname(line);
            insertar(&mi_lista, name, surname, grade);
        }
    }
    
    fclose(archivo);
    archivo = fopen(argv[1], "r");
    
    while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
    {
        grade = get_grade(line);        
        if (grade > 4) //Insertar en la lista
        {
            name = get_name(line);
            surname = get_surname(line);
            insertar(&mi_lista, name, surname, grade);
        }
    }
    
    
    mostrar_lista(mi_lista);
    free_lista(mi_lista);

    //system("leaks a.out");
    return 0;
}


void insertar(lista_notas **ptr, char *name, char *surname, int grade)
{
    lista_notas *p1, *p2;

    p1 = *ptr;
    if(p1 == NULL)
    {
        p1 = malloc(sizeof(lista_notas));//y si usamos calloc ¿qué cambia?
        if (p1 == NULL)
            exit(71);
        if (p1 != NULL)
        {
            p1->nombre = name;
            p1->apellido = surname;
            p1->nota = grade;
            p1->siguiente = NULL;
            *ptr = p1;
        }
    }
    else
    {
        while(p1->siguiente != NULL)//recorrer la lista hasta el último
            p1 = p1->siguiente;
        p2 = malloc(sizeof(lista_notas));//y si usamos calloc ¿qué cambia?
        if (p2 == NULL)
            exit(71);
        if(p2 != NULL)
        {
            p2->nombre = name;
            p2->apellido = surname;
            p2->nota = grade;
            p2->siguiente = NULL;
            p1->siguiente = p2;
        }
    }
}

void mostrar_lista(lista_notas *ptr)
{
    while(ptr != NULL)
    {
        printf("%s ",ptr->nombre);
        printf("%s ",ptr->apellido);
        printf("%d\n",ptr->nota);
        ptr = ptr->siguiente;
    }
/*  printf("\n");*/
}

void free_lista(lista_notas *ptr)
{
    lista_notas *aux = ptr;
    lista_notas *aux2;

    while(aux != NULL)
    {
        aux2 = aux;
        aux = aux->siguiente;
        free(aux2->nombre);
        free(aux2->apellido);
        free(aux2); 
    }
}

int get_grade(char *line)
{
    int i, blank, num;

    i = 0;
    blank = 0;
    while(line[i] != '\0')
    {
        if (blank == 2) //sacar la nota
        {
            num = atoi(&line[i]);
            blank  ;
        }
        else if(line[i] == ' ')
            blank  ;
        i  ;    
    }
    return num;
}

char *get_name(char *line)
{
    int i;
    char *name = malloc(51);
    if (name == NULL)
        exit(71);

    i = 0;
    
    while(line[i] != ' ')
        name[i] = line[i  ];
        
    name[i] = 0;

    return name;
}

char *get_surname(char *line)
{
    int i, j;
    char *surname = malloc(101);
    if (surname == NULL)
        exit(71);
    
    i = 0;
    j = 0;

    while(line[i] != ' ')
        i  ;

    while(line[  i] != ' ')
        surname[j  ] = line[i];
    
    surname[j] = 0;

    return surname;
}

CodePudding user response:

At least these problems:

not sequenced

name[i] = line[i ]; is bad code. The i may occur before, after, (or even during) name[i]. Result: undefined behavior (UB). @paddy

Limited size

char *name = malloc(51); does not need to use the magic number 51.

May run off end

while(line[i] != ' ') leads to trouble when line[] lacks a ' '.


Alternative (like OP's code)

char *get_name(char *line) {
    size_t i = 0;
    while(line[i] != ' ' && line[i] != '\0') {
        i  ; 
    }

    char *name = malloc(i   1);
    if (name == NULL) {
        exit(71);
    }

    for (size_t j = 0; j < i; j  ) {
        name[j] = line[j];
    }
    name[i] = 0;

    return name;
}

Or perhaps using standard efficient library functions

char *get_name(const char *line) {
  size_t token_length = strcspn(line, " ");
  char *name = malloc(token_length   1);
  if (name == NULL) {
    exit(71);  // Consider a named macro/enum here rather than a magic 71
  }

  name[token_length] = '\0';
  return memcpy(name, line, token_length);    
}

Other issues

Off by 1

// fgets(line, MaxLinea, archivo)
fgets(line, sizeof line, archivo)

Advanced: Assuming first, last names do not include spaces

Consider first names like "Betty Jo" and last names like Lloyd Webber

Some names are longer than 51.

  •  Tags:  
  • c
  • Related