'Pointers and all that [C] [closed]

well, I'm trying to create a simple program that simply print the name of a list of students, the thing is,I do all that's required but when I try to print all the elements come out as the same. It's in portuguese but I don't think it should be a problem.

Here is the program:

#include <stdlib.h>
#include <stdio.h>

typedef struct struct_t{

   char * nome;
   int * notas; 


}DADOS_ALUNOS;

typedef struct struct_s{

    DADOS_ALUNOS total_alunos;


}ALUNOS;

int main (){

         
    ALUNOS * Classe;
    DADOS_ALUNOS aluno;
    int numero_alunos, quantidade_provas, i;


    printf("Digite a quantidade de alunos\n");
    scanf("%d", &numero_alunos);
    printf("Agora, digite a quantidade de provas dadas\n");
    scanf("%d", &quantidade_provas);

    printf ("Total numeoro alunos: %d\n", numero_alunos);

    Classe = (ALUNOS *) malloc (numero_alunos * sizeof(ALUNOS));
    aluno.nome = (char *) malloc (sizeof(char) * 20);
    
    for (i = 0; i < numero_alunos; i++){

        printf("Digite o nome do aluno\n");
        scanf("%s", aluno.nome);

       //printf("O que está contindo na variavael temporaria: %s", aluno.nome);
        
        Classe[i].total_alunos.nome = (char *) malloc (sizeof(aluno.nome));
        Classe[i].total_alunos.nome = aluno.nome;
        //printf("O que está contindo na variavael : %s", Classe[i].total_alunos.nome);
        //free(aluno.nome);

    }

    for (i = 0; i < numero_alunos; i++){

        printf("Nome: %s\n", Classe[i].total_alunos.nome);

    }



    return 0;
}

any suggestions are welcome.



Solution 1:[1]

In these statements:

    Classe[i].total_alunos.nome = (char *) malloc (sizeof(aluno.nome));
    Classe[i].total_alunos.nome = aluno.nome;

there are produced memory leaks.

At first memory was allocated and its address was assigned to the pointer Classe[i].total_alunos.nome and then the pointer was reassigned with the address of the memory allocated before the for loop:

    Classe[i].total_alunos.nome = aluno.nome;

At least you need to use the string function strcpy like:

    strcpy( Classe[i].total_alunos.nome, aluno.nome );

provided that you allocated enough space for the array pointed to by the pointer Classe[i].total_alunos.nome because in this allocation

Classe[i].total_alunos.nome = (char *) malloc (sizeof(aluno.nome));

you allocating memory only for pointer. That is sizeof(aluno.nome ) is equal to sizeof( char * ).

However pay attention to that there will be still a memory leak because the memory pointed to by the pointer aluno.nome was not freed.

There is no great sense to declare an object of the type DADOS_ALUNOS:

DADOS_ALUNOS aluno;

and then dynamically allocate memory:

aluno.nome = (char *) malloc (sizeof(char) * 20);

Instead you could declare just a character array as for example:

char nome[20];

and use this array in the for loop:

scanf( " %19[^\n]", nome );
       ^^^^^^^^^^  

Solution 2:[2]

Several issues.

First, change

Classe[i].total_alunos.nome = (char *) malloc (sizeof(aluno.nome));

to

Classe[i].total_alunos.nome = malloc( strlen( aluno.nome ) + 1 );

As of C89 casts on malloc are unnecessary, and under the C89 standard can suppress a useful diagnostic.

The type of the expression aluno.nome is char *, so sizeof( aluno.nome ) gives you the size of the pointer, not the size of the buffer it points to. Use strlen to get the length of the input string, then add 1 to account for the terminator.

Next, change

Classe[i].total_alunos.nome = aluno.nome;

to

strcpy( Classe[i].total_alunos.nome, aluno.nome );

The = operator is not defined to copy the contents of one array to another - in order to do that you have to use a library function like strcpy or memcpy, or copy elements individually in a loop. All you are doing here is assigning the pointer value stored in aluno.nome to Classe[i].total_alunos.nome, and in the process you're losing the reference to the memory you allocated with malloc, leading to a memory leak.

Finally, instead of using scanf to read string input, use fgets - it makes it easier to prevent a buffer overrun:

printf("Digite o nome do aluno\n");
fgets( aluno.nome, 20, stdin );

This will read at most 19 characters into aluno.nome and terminate the string. You can do that with scanf as well:

scanf( "%19s", aluno.nome );

but the lengths have to be hardcoded in the conversion specifier; you can't use * to specify a length at runtime like you can with printf.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 halfer
Solution 2 John Bode