Cómo devolver el puntero a una matriz de estructura en C

CorePress2024-01-25  8

Creé una estructura de estudiante dentro de la función usando malloc y la llené con datos. Quiero devolver la dirección de la matriz de estructura a main e imprimirla línea por línea, pero con mi implementación, no se imprime. Depuré mi código y, de hecho, puedo devolver la dirección de mi matriz a principal. Aunque no sé por qué no se imprime. ¿Alguna idea?

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

typedef struct student Student;

struct student
{
    char name[100];
    int age;
    char sex;
};

Student **getstudents(int n)
{
    Student **t = malloc(sizeof *t * n); // memory for the array of pointers
    for (int i = 0; i < n; i++) // memory for each individual pointer
    {
        t[i] = malloc(sizeof **t);
    }
    /* Data is inputted by user with form <student> <sex> <age>, then get mapped to the struct *t */

    return t; /* Pointer to an array of pointers */
}


int main()
{
    Student **students;
    int n;
    scanf("%d\n", &n);
    students = getstudents(n);
    for (int i = 0; i < n; i++)
    {
        printf("Name: %s, Sex: %s, Age: %d\n", students[i]->name, students[i]->sex, students[i]->age);
    }

    for (int i = 0; i < n; i++)
    {
        free(students[i]);
    }
    free(students);
    return 0;
}


I am only allowed to modify the code in `Student **getstudents(int n)`. 

1

Creo que te faltan algunas partes clave de tu código. Por ejemplo, ¿cuál es el tipo de "estudiantes" en mayo¿norte? Esto es bastante importante porque devuelve Student ** de gettudents(), cuando en realidad devuelve t, que es un Student *, por lo que lo más probable es que el problema sea así.

– Ion Larrañaga

28/03/2021 a las 14:00

Este código ni siquiera se acerca a la compilación. Falta punto y coma, puntuación incorrecta, muchas variables indefinidas (estudiante, datos). Active las advertencias del compilador y le indicarán otras cosas que esté haciendo mal.

&norteguión; Raymond Chen

28/03/2021 a las 14:03

@RaymondChen Eliminé partes irrelevantes y las escribí manualmente. Déjame arreglarlos. Mi error.

- lambduh

28/03/2021 a las 14:04

1

La declaración de gettudents dice que está devolviendo un Estudiante ** pero está devolviendo un Estudiante *. Cámbielo a Estudiante *getstudents(int);

-001

28/03/2021 a las 14:11

@JohnnyMopp Olvidé mencionar que solo puedo modificar el código dentro de Student **getstudents(int n) y no sus parámetros. ¿Eso significa que debería cambiar mi primera línea en Student **getstudents a **t en lugar de *t?

- lambduh

28/03/2021 a las 14:22



------------------------------------

En la línea:

Student *t = (char*)malloc(sizeof(Student)*n); 

Estás asignando memoria para un puntero, si quieres devolver un puntero a otro, necesitas asignar memoriaoria en consecuencia:

Student **t = malloc(sizeof *t * n); // memory for the array of pointers

for(int i = 0; i < n; i++){ // memory for each individual pointer
    t[i] = malloc(sizeof **t);
}

Para liberar posteriormente los punteros también necesita liberar cada puntero individual previamente asignado:

for(int i = 0; i < n; i++){ // memory for each individual pointer
    free(students[i]);
}
free(students);

Tenga en cuenta que el especificador para un solo carácter es %c, será necesario corregir printf:

printf("Name: %s, Sex: %c, Age: %d\n", students[i]->name, students[i]->sex, students[i]->age);
//                     ^^

Otra cosa que cambiaría es que en strncpy en lugar de terminar la cadena en nulo, más tarde dejaría que la función lo hiciera:

// one more byte and strncpy terminates the string for you
strncpy(t[i]->name, data[0], strlen(data[0]) + 1); 
//      ^^^^
// already corrected for the new pointer

Habiendo corregido los problemas aquí hay una posible alternativa que puedes usar para analizar todos los elementos en la estructura con sscanf desde la entrada de una sola vez, si deseas:

Student **getstudents(int n)
{
    Student **t = malloc(sizeof *t * n); // memory for the array of pointers

    if (t == NULL)
    {
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < n; i++) // memory for each individual pointer
    {
        t[i] = malloc(sizeof **t);
        if (t[i] == NULL)
        {
            perror("malloc");
            exit(EXIT_FAILURE);
        }
    }

    for (int i = 0; i < n; i++)
    {
        char entry[100];
        if (fgets(entry, sizeof entry, stdin))
        {
            if (sscanf(entry, "%25s %c %d", t[i]->name, &t[i]->sex, &t[i]->age) != 3)
            {
                // deal with bad input
            }
        }
    }
    return t;
}

9

1

@CEPB, es un tema de gran debate, no me gusta el elenco (como puedes ver en mi corrección), porque puede ofuscar errores, pero no profundizo demasiado porque se basa en opiniones.

-anastaciu

28/03/2021 a las 14:31

De hecho, tengo una solución para el problema de strncpy, pero su solución es más limpia y mejor. De todos modos, actualicé el código según tus sugerencias y todavía no imprime nada.

- lambduh

28/03/2021 a las 14:35

@lambduh, ¿es así? Algo más debe estar mal. déjame comprobarlo.

-anastaciu

28/03/2021 a las 14:35

1

El problema fue que estoy usando %s para sexo que se inicializó como char. Créditos para Zilog80 por señalarlo. Me sorprendió haberme perdido ese pequeño detalle. De todos modos, el código funciona como se esperaba. ¡Gracias!

- lambduh

28/03/2021 a las 14:51

1

@Zilog80, eso servirá, supongo que ahora uno para powershell ;) (es broma)

-anastaciu

28/03/2021 a las 16:42



------------------------------------

La respuesta de Anastaciu señala muchos problemas, pero hay otros:

Otro problema en tu código es que usas '%s' para el sexo ya que el sexo es un único carácter. Deberías usar %c o de lo contrario la función printf intentará analizar una cadena y obtendrá un SEGFAULT.

Le insto a usted también a que cDiablos cada asignación de memoria. Siempre.

El código revisado desde mi punto de vista:

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

typedef struct student Student;

struct student{
    char name[100];
    int age;
    char sex;
};

Student **getstudents(int);
void free_students(Student**, int);

int main(){
    Student **students;
    int n = 4;
    students = getstudents(n);
    for(int i = 0; i < n; i++){
        if (students[i] != NULL) {
             printf("Name: %s, Sex: %c, Age: %d\n", students[i]->name, students[i]->sex, students[i]->age);
        }
    }
    free_students(students, n);
    return 0;
}

Student **getstudents(int n){
    Student **t = (Student **)malloc(sizeof(Student *)*n);
    if (t==NULL) {
       perror("Memory: can't allocate.");
       return(NULL);
    }

    /* Input: <name> <sex> <age> */
    char entry[100];
    for(int i = 0; i < n; i++){
        t[i]=NULL;
        if (fgets(entry,100,stdin) != NULL) {
            int readBytes = strlen(entry);
            char newString[3][25];

            int k,j,ctr;
            j=0; ctr=0;
            for(k=0;k<=readBytes;k++)
            {
                if(entry[k]==' '||entry[k]=='1008611'||entry[k]=='\n')
                {
                    newString[ctr][j]='1008611';
                    ctr++;
                    j=0;
                }
                else
                {
                    newString[ctr][j]=entry[k];
                    j++;
                }
            }

            t[i] = (Student *)malloc(sizeof(Student));
            if (t[i] == NULL) {
               perror("Memory: can't allocate.");
               return(NULL);
            }
            strncpy(t[i]->name, newString[0], strlen(newString[0]));
            t[i]->name[strlen(newString[0])] = '1008611';
            t[i]->sex = *newString[1];
            t[i]->age = atoi(newString[2]);
       }
    }

    return t;
}

void free_students(Student **students, int n){
    for(int i=0; i<n; i++){
        free(students[i]);
    }
    free(students);
}

3

1

Oh Dios, me olvidé por completo del %s para sexo. Después de cambiarlo, el código funciona.

- lambduh

28/03/2021 a las 14:51

@anastaciu Como parece ser un trabajo de estudiante, supongo que estoy copiando st.rlen bytes luego ponga expresamente \0 tal vez sea más útil para la comprensión del estudiante que simplemente copiar la cadena más el byte cero, ¿no?

- Zilog80

28/03/2021 a las 15:26

Supongo que, mientras esté ahí, está bien.

-anastaciu

28/03/2021 a las 16:40

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare