Passing a struct as parameter

Asked

Viewed 135 times

0

Good afternoon! Can anyone help me? I’m having doubts in this exercise... I’m not getting through parameter to struct for another function. NOTE: I am starting now... it is advisable to keep the structs in main or at global level?

void menorIdade(aluno){ //????
    
    int compIdade;
    printf("\nDigite uma idade: ");
    scanf("%d", &compIdade);
    
    printf("\nALUNOS COM IDADE MENOR QUE %d", compIdade);
    for(int i=0; i<qtdAlunos; i++){
        if(aluno[i].idade<compIdade){
            printf("\n%s - %d", aluno[i].nome,aluno[i].idade);
        }
    }
}

int main(){

    struct turma {
        char nome[50];
        int idade;
        int numeroReg;
    } aluno[qtdAlunos];

    
    for(int i=0; i<qtdAlunos; i++){
        setbuf(stdin, NULL);
        
        printf("\nALUNO %d", i+1);
        printf("\nNome: ");
        fgets(aluno[i].nome, 50, stdin);
        
        
        printf("Idade: ");
        scanf("%d", &aluno[i].idade );
        
        printf("Numero de registro: ");
        scanf("%d", &aluno[i].numeroReg );

    }
    menorIdade(struct turma aluno); //???
}
  • Your struct turma needs to be known in its function menorIdade, moreover aluno is an array of structs and not a single struct. Declare it in global scope so that it is known in both the main and the minority function.

2 answers

1


it is advisable to keep the structs in main or global scope?

Yes, it is advisable and often essential since the whole project will work with them. The general rule is to always use as little scope as possible, and to allocate nothing in the global space

I am unable to pass parameter to struct for another function

I’ll show you an example, typed on top of your program. And typing from the data

About your program

Before I write about your program...

struct turma {
    char nome[50];
    int idade;
    int numeroReg;
} aluno[qtdAlunos];

This construction is somewhat folk. So aluno is a vector of turma? Doesn’t seem strange to you? aluno is turma[], when the reality is the opposite: the turma is a collection of aluno

Write your program around the data. Always. And don’t write a single line for no reason. And don’t read data in a program you’re testing. It’s going to take forever for nothing. Use constants or data-generating functions. NEVER read. When you are sure of the program you put the reading. You will see this in the example.

And how to start this thing of writing around the data?

Of course we’re going to read a class so we can list the guys under the age of one. So the first thing you need is a goal. So in the IDE itself you use something like this

Seq        Mat                 Nome   Id
001..12345678..01234567890123456789..100
001  12345678  01234567890123456789  100
001..12345678..01234567890123456789..100
001  12345678  01234567890123456789  100

        XXX alunos

It’s so much easier when you have a goal BEFORE.

Of course, to test the function you need to be able to list the whole class or you won’t know or be able to prove that everything is all right. So you’re gonna need a function to show all the guys. Whenever you create a structure create a function like this because even if the statement does not ask you will want to list. How will you test this right without her? Then it may be

    int         mostra_turma( Turma* T );

Without thinking: the function receives the address of a struct Turma. And list the guys. Sure.

But of course showing everyone is the same thing as showing guys below a certain age, so the other function

int         menorIdade( Turma* T, Num idade );

it must be the same, right? Num is a number, like a int. It makes no difference now.

and the Class

In C there is this common practice of naming structs with the first letter capitalized, and only it. And naming constants with ALL letters capitalized. If you follow this will help you understand other people’s programs and vice versa.

One Turma is a collection of students. Here is a possibility


typedef struct
{
    Num     id;

    Aluno   aluno[MAX_ALUNOS_];
    Num     qtdAlunos;
    char    nome[50];

}   Turma;

See the difference here: the Turma has a name, a id because it’s nice to have a numeric field to compare, a number of Aluno and a vector of Aluno with a fixed size allocated, after all we are starting at C and will not want to allocate memory and such. And it’s much better to have information about the Class INSIDE the record. Compare with your case where you need to control a single struct vector with a certain number of occurrences and understand that you will have to keep a counter just for that. And if I had more than one Turma would be in a lot of trouble...

Note that when using the convention I spoke about it is already clear that Turma, Aluno and Num are types defined in your program, and MAX_ALUNOS_ is a constant. A convention, but it helps too.

and Pupil?

What was in the original program

typedef struct
{
    Num     id; // para escrever menos :) 

    Num     idade;
    char    nome[50];
    
}   Aluno;

The simple. the id may not be the license plate, but we will use it as such. The advantage is that you know that Turma has Aluno and can change one struct without touching the other

the data then:

If you’re really reading this you noticed that we don’t have a program but we do have a model and two functions, and a feedback for the report. BEFORE writing the program, because we start with the data.

Here’s the data so far:

#include <limits.h>
#include <stdio.h>

#define MAX_ALUNOS_ 10

typedef     unsigned int Num; // para escrever menos

typedef struct
{
    Num     id; // para escrever menos :) 

    Num     idade;
    char    nome[50];
    
}   Aluno;


typedef struct
{
    Num     id;

    Aluno   aluno[MAX_ALUNOS_];
    Num     qtdAlunos;
    char    nome[50];

}   Turma;

// aqui vao as funcoes
int         menorIdade( Turma*, Num );
int         mostra_turma( Turma* );

// fim de turma.h

As the last line suggests it will be recorded in the file "header. h" of the EXAMPLE I am showing you and will be included in the program. the such

#include
  • Allocates nothing
  • defines Num, Aluno and Turma in a way that must serve
  • Num is a int no signal because it makes sense.
  • MAX_ALUNOS_ worth 10. That’s good. It makes no difference

And the functions?

There are two, actually one. and you can already write because you have the feedback upstairs. It was the first thing we wrote. They will be in the class file. c, same header name. Other convention. Important.

int         mostra_turma( Turma* T)
{
    // claro que a listagem e a mesma que acima, so que vai listar todos
    return menorIdade( T, INT_MAX );
};

That was easy, huh? 'Cause INT_MAX It’s a big value, as much as possible for a number, and then of course it’s going to list everyone, so you don’t have to use two functions to make something so similar. Of course I could have used 200 to list guys under 200. Or written them both like everybody else. One for testing and one for enunciation, but then you’d have to worry about the risk of changing one without changing the other...

The return value of mostra_turma() could be the total of faces or a negative value in case of error. Since it receives something like Class*, a pointer to Class, this pointer can be null for example and then could return an error code, right?

The example returns zero because it is an example.

age() at last

This is the program after all. I’ll show you the example and then some details. It’s very simple, of course, because just show what is in the feedback that was the first thing we wrote.

int         menorIdade( Turma* T, Num idade )
{
    const char* cab = "Seq       Mat                  Nome   Id\n";
    int t = 0; // conta os alunos
    if ( idade == INT_MAX )
        printf("Turma: '%s' [%d alunos]\n\n%s\n",
            T->nome,
            T->qtdAlunos,
            cab // o cabecalho comum
        );
    else
        printf("Turma: '%s' [%d alunos]. Limite: %d anos (inclusive)\n\n%s",
            T->nome,
            T->qtdAlunos,
            idade,
            cab
        );
    // agora lista um por um 
    for( int n = 0; n<T->qtdAlunos; n++)
    {
        if( T->aluno[n].idade <= idade )
        {
            printf("%3d  %8d  %20s  %3d\n",
            1+n, T->aluno[n].id, T->aluno[n].nome, T->aluno[n].idade 
            );
            t = t + 1;
        }
    };  // for()
    printf("\n\t%3d alunos\n\n", t);
    return 0;
}

Take this line for example:

        const char* cab = "Seq       Mat                  Nome   Id\n";

The header of the listing, copied from the template itself with cut and paste. And the fields have the size in numbered columns so there is no way not to be aligned... The gene does not want to be testing. See the line that prints the header:

        printf("Turma: '%s' [%d alunos]\n\n%s\n",
            T->nome,
            T->qtdAlunos,
            cab // o cabecalho comum
        );

If you change your mind about the header you don’t need to look for it in the middle of the printf()...

And the student line?

            printf("%3d  %8d  %20s  %3d\n",
            1+n, T->aluno[n].id, T->aluno[n].nome, T->aluno[n].idade 
            );

Note the size of the fields after %. so it ensures that it will align, before testing the program. After all it is to be like this, as est;a there above...

001  12345678  01234567890123456789  100

3, then 8, then 20 after 3.

The if there at the beginning is because when to list by age we need the value on the screen and when to list everyone not...

The code will show you how to access each field within the structures. Read carefully.

riding gang. c

Then this new file has the functions that are declared from the class header. h and whatever it takes to make them rotate. You don’t need anything else here.

#include    "turma.h"

int         menorIdade( Turma* T, Num idade )
{
    const char* cab = "Seq       Mat                  Nome   Id\n";
    int t = 0; // conta os alunos
    if ( idade == INT_MAX )
        printf("Turma: '%s' [%d alunos]\n\n%s\n",
            T->nome,
            T->qtdAlunos,
            cab // o cabecalho comum
        );
    else
        printf("Turma: '%s' [%d alunos]. Limite: %d anos (inclusive)\n\n%s",
            T->nome,
            T->qtdAlunos,
            idade,
            cab
        );
    // agora lista um por um 
    for( int n = 0; n<T->qtdAlunos; n++)
    {
        if( T->aluno[n].idade <= idade )
        {
            printf("%3d  %8d  %20s  %3d\n",
            1+n, T->aluno[n].id, T->aluno[n].nome, T->aluno[n].idade 
            );
            t = t + 1;
        }
    };  // for()
    printf("\n\t%3d alunos\n\n", t);
    return 0;
}


int         mostra_turma( Turma* T)
{
    // claro que a listagem e a mesma que acima, so que vai listar todos
    return menorIdade( T, INT_MAX );
};

// fim de turma.c

Of course from the #include all the struct are known and can call the functions inside

because there is no main()?

Leaving this separate you can write programs that use these functions for a lifetime, without even having to open those files again. And you can test its functions with several possible main(). Or you can sell your functions to someone who will only use the header and compiled code, as you do with stdio.h and printf() for example...

How to Create a Test Class

Like I said, it’s the devil reading from the user every time you test the program. It just doesn’t make sense.

Look at this:

    Turma teste = 
    {   // uma turma de teste basta
        .id = 42,
        .qtdAlunos = 3,
        .nome = "Fisica II",
        .aluno[0] = { 42, 22, "Jhonny Cash" },
        .aluno[1] = { 45, 25, "Willie Nelson" },
        .aluno[2] = { 52, 30, "Kris Kristofferson" }
    };

    Turma*  p = &teste; // inutil: e so um exemplo

There is a test class, set up with 3 students already. That’s enough for our program, which never ran. Pay attention to the notation: it is not complicated. You precede the name of the struct fields by point. Use keys when you have one struct inside the other, use brackets for vector indices. No need to initialize all fields.

Note the example of how to declare p as a pointer to Class.

And the test itself?

    mostra_turma( p );

    menorIdade( &teste, 12 ); // sem usar o ponteiro
    menorIdade( p, 25 ); // dois alunos
    menorIdade( p, 55 ); // todos   

That’s enough: mostra_turma(0 will list all. The first filter by age will not find anyone, the second will find 2, one at the age limit. The third will include everyone.

Behold tmain. c, that test program

#include "turma.h"

int main(void)
{
    Turma teste = 
    {   // uma turma de teste basta
        .id = 42,
        .qtdAlunos = 3,
        .nome = "Fisica II",
        .aluno[0] = { 42, 22, "Jhonny Cash" },
        .aluno[1] = { 45, 25, "Willie Nelson" },
        .aluno[2] = { 52, 30, "Kris Kristofferson" }
    };

    Turma*  p = &teste; // inutil: e so um exemplo

    mostra_turma( p );

    menorIdade( &teste, 12 ); // sem usar o ponteiro
    menorIdade( p, 25 ); // dois alunos
    menorIdade( p, 55 ); // todos
    
    return 0;
}

// fim de tmain.c

How to compile this?

gcc -o t -Wall -std=c17 tmain.c turma.c

This command will generate the executable t from the tmain. c and class sources. c Or use your IDE.

The 3 files are separated here and just copy. The program printed right the first time. ;) the same as the following error. And it didn’t take long to write. Let alone to test.

What it takes is to explain and write here :) but I wanted to show a possible mechanism from scratch except for its clear program.

  • Thank you very much!!!

  • It is advisable to maintain the functions before or after the main?

  • In C no matter the order, but it is important to be close to where they are called. In Python for example the functions must be declared before being called, but in C it makes no difference.

  • The difference is not for the compiler: And who will read the code, including the author weeks later. main() should be only in a separate file because it is the reality: production and testing. The whole reason to have a file with functions is to be able to use it elsewhere. If main() is together there is no way. Some order matters when it comes to locating the code but modern Ids keep a list in alphabetical order so this has become less important. Only not everyone uses an IDE. @Natanfernandes grateful for the suggestions. I’ve incorporated a few

  • I get it... thanks again!

-1

Good night.

Your code has two errors, the first one is about the scope (where it is visible) of your struct statement. Remember that a struct is a data type equal to int or char, but it is a data type created by the programmer. The new data type is not native and so it can only be used by the functions you know. In your code you declare a new data type in main and it only exists there, when you try to use this type of data in another function there will be error, because this function does not know how this new type of data works (does not know its fields). When you do that:

struct turma {
    char nome[50];
    int idade;
    int numeroReg;
} aluno[qtdAlunos];

You create a new type of data and at the same time already create a variable (vector) of the data type created, that is, you speak to the program that struct turma is a new type of data, equal to int, and says that aluno is a variable (vector) of this type. Example:

// Em ambos os casos n1 e n2 são variáveis
// E `int` e `struct turma` são tipos de dados
int n1;
struct turma n2;

For all the functions of your program to know this new type of data we need to leave your statement globally, that is to say, struct turma will be declared in global scope. If you leave this piece of code globally:

struct turma {
    char nome[50];
    int idade;
    int numeroReg;
} aluno[qtdAlunos];

So the variable (vector) will also be global, but that’s not what we want. To solve the problem we need to unlink the declaration of the new data type with the variable declaration. Example:

// Aqui é somente a declaração do novo tipo de dado
// Nenhuma variável ou vetor está sendo declarado
// Esse trecho de código precisa ter escopo global
// Assim todo o programa vai reconhecer esse novo tipo
// Igual ocorre com o `int` ou o `char`
struct turma {
    char nome[50];
    int idade;
    int numeroReg;
};

// Na sua função `main` você declara
// Uma variável desse tipo
// Esse vetor é igual a qualquer outro vetor do tipo
// `char` ou `int`, a diferença é que ele é
// Do tipo que você declarou
struct turma aluno[qtAluno];

The second error is in the argument of its function. Normally a function has as argument a variable with its type. Example:

// Aqui x e y são do tipo `int`
int soma(int x, int y);

You forgot to do this in your job:

// Repare que a variável aluno está sem tipo
// A função não sabe se aluno é do tipo `int`,
// `char` ou `struct turma`
void menorIdade(aluno)

To solve this just add the type:

void menorIdade(struct turma aluno)

The example above would work for passages by value, when we work with passages by reference we need to use pointers, so it would look like this:

void menorIdade(struct turma *aluno)

Now this function can receive a vector without problems. In main just put:

// Isso fica na `main`
// aluno é um vetor
// pois essa função recebe um ponteiro
menorIdade(aluno);

NOTE: I guess you didn’t post the full code because qtdAlunos is not stated in the text. A tip is to leave this variable as constant (if already then recommend to leave all letters in upper case, is a good programming practice). Example of how to declare constants:

// 34 é o valor da constante QTALUNOS
#define QTALUNOS 34
  • Thank you so much! You helped me so much!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.