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.
Your
struct turma
needs to be known in its functionmenorIdade
, moreoveraluno
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.– anonimo