This code that "got" is not so good. And that didn’t help you much.
This title "equalizing C pointers" also makes no sense, especially if we imagine that this is due to this line
*max = *min;
Perhaps, since you are apparently learning, you should avoid the addiction of this kind of program statement that "took":
int minMaxSeq(int n, int *min, int *max) // ...
That’s correct, many authors and companies use it this way. However it is stating what in the list of arguments? n
, min
and max
. And what is n
? int
. What is max
? int*
, a pointer to int. And what is min
? another pointer to int
, int*
would tell you the compiler C. So avoid declaring things like int *max
and instead always declare int* max
because you are declaring a name and the name is max
. And declaring such a name as a variable of a type, and the type is int*
Back on the show
So max
is int*
and so *max
is what? A int
, of course. And it’s not about matching pointers. if that’s what generated the title. It’s just an assignment of a int
to another.
This function has to RETURN these two values, min
and max
. However the functions can only return one argument, and so the option of the author in this case was to return the TWO values passing pointers to two int
as arguments. These are exit arguments. The guy who calls minMaxSeq()
passes both int
to receive the result. Note that the function does not have a return
and must have, as your compiler dee have said.
That stretch
scanf("%d", min);
*min = *max;
indicates only reading separately from the first number. Of course it can be the only value if n
for 1 and so it will be the minimum and max. And if it is not the only one there the program reads the remaining values. If the guy type 5 read, of course, the other 4, for example.
Always test the return of scanf()
. It’s naive to go along with the program if scanf()
You haven’t read anything: of course you’ll lose count. If you were going to enter 10 values and give error in the second will even try to read another 8 knowing that the program failed? Should not. But it’s written like that and it’s silly.
To return more than one value one can always return a struct, thus:
typedef struct
{
int min;
int max;
} Min_Max;
Min_Max* min_max(unsigned n);
And it would be common in C: return the struct or pointer to a dynamically allocated one. Something like this
Min_Max* min_max(unsigned n)
{ // exemplo
int res = 0;
int x = 0;
Min_Max* p = (Min_Max*) malloc( sizeof(Min_Max) );
if (p == NULL) return NULL;
printf("Valor 1 de %u: ", n);
res = scanf("%d", &p->min);
if ( res != 1 ) return NULL;
p->max = p->min; // afinal so tem um por enquanto
for ( unsigned i = 1; i < n; i = i + 1)
{
printf("Valor %u de %u: ", 1+i, n );
res = scanf("%d", &x);
// se res != 1 entao deu errado tentando ler o i-esimo numero
if ( res != 1 ) return NULL;
if (x > p->max)
p->max = x;
else if (x < p->min)
p->min = x;
}; // for()
return p; // retorna o ponteiro para a nova struct
}; // min_max()
So it has another advantage: it can change the content of struct
without changing the statement. It can for example include the average beyond the maximum and minimum and will not change what is called the function signature. And so you don’t have to touch the old programs that used this struct
. It is the concept of encapsulation. In practice this goes much further, but the example remains.
As there are only two values use two pointers is simple and more economical after all ;)
Using a function Factory
In general they are called Factory functions functions that each time they are called return a pointer to a new unit of something, a record, a transmission buffer, a character, something. In this case it is only a structure with the values of min
and max
. Of course, since there’s only two, it might not be worth it, but if there were five, I think you’d think about it, right?
And why not a vector? Because not always everything you want to return is the same type: you may need to return a name, char*
, a weight float
, a quantity, unsigned int
, and a price, float
, for example, and it would not be so new.
And when using typedef Coisa
and return a pointer to Coisa
can always change the content without changing the function signature, since Coisa
continues to be Coisa
.
Of course, the two functions are similar and cut and paste helps well. Watch out for allocation via malloc()
in the second and for the fact that it must destroy the structure when it is no longer used, calling free()
.
Note: there is a chain, based in part on texts from 20 years ago, which recommends not to use cast to the pointer returned by malloc()
for certain reasons. Before commenting here that one should not do this I will say that at all times I do this as a reminder to myself to know that I’m allocating what I think I’m allocating. And also because I program more in C++ than in C++ and C++ this is mandatory. Yes, no memory is allocated in C++ like this since 2011 practically ;) ...
The example program calls the two functions and can compare the use.
a safer version of the original function
int minMaxSeq(
unsigned n,
int* min,
int* max
)
{
int res = 0;
printf("Valor 1 de %u: ", n);
res = scanf("%d", min);
if ( res != 1 ) return -1;
*max = *min;
n = n - 1; // ja leu um
for ( unsigned i = 0, x; i < n; i = i + 1)
{
printf("Valor %u de %u: ", 2+i, 1+n );
res = scanf("%d", &x);
// se res != 1 entao deu errado tentando ler o i-esimo numero
if ( res != 1 ) return -i-2;
if (x > *max)
*max = x;
else if (x < *min)
*min =x;
}; // for()
return 0;
}
This version is a little more readable, probably. And more secure. And it has a better interface. The function returns zero if read ok, or -x if error when trying to read the x-esimo element. And you have the courtesy to instruct the unfortunate about what you are going to type, instead of leaving the black screen there...
THE EXAMPLE with the two functions
Below are some examples of executing the following code:
PS C:\src> gcc -o teste -Wall -std=c17 mm.c
PS C:\src> ./teste
Entre com o tamanho da sequencia: 4
Valor 1 de 4: 1
Valor 2 de 4: 2
Valor 3 de 4: 3
Valor 4 de 4: x
erro -4 na funcao
PS C:\src> ./teste
Entre com o tamanho da sequencia: 4
Valor 1 de 4: -34
Valor 2 de 4: 3
Valor 3 de 4: 345
Valor 4 de 4: -12
Dos 4 valores lidos pela funcao MIN = -34 e MAX = 345
Testando com a funcao "factory" e 3 elementos
Valor 1 de 3: 3
Valor 2 de 3: 2
Valor 3 de 3: 1
Dos 3 valores lidos pela funcao MIN = 1 e MAX = 3
PS C:\src>
a test program
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct
{
int min;
int max;
} Min_Max;
Min_Max* min_max(unsigned n);
int minMaxSeq(unsigned,int*,int*);
int main(void)
{
unsigned n = 0;
int min = INT_MAX;
int max = INT_MIN;
int res = 0;
printf("Entre com o tamanho da sequencia: ");
res = scanf("%u", &n);
if ( res != 1 ) return -1;
res = minMaxSeq( n, &min, &max );
if ( res < 0 )
{
printf( "erro %d na funcao\n", res );
return -2;
}
printf("Dos %u valores lidos pela funcao MIN = %d e MAX = %d\n",
n, min, max);
printf("\n\nTestando com a funcao \"factory\" e 3 elementos\n\n");
Min_Max* novo = min_max( 3 );
if ( novo == NULL )
{
printf( "erro na funcao de leitura\n");
return -2;
}
printf("Dos %u valores lidos pela funcao MIN = %d e MAX = %d\n",
3, novo->min, novo->max);
free(novo);
return 0;
}; // main()
Min_Max* min_max(unsigned n)
{ // exemplo
int res = 0;
int x = 0;
Min_Max* p = (Min_Max*) malloc( sizeof(Min_Max) );
if (p == NULL) return NULL;
printf("Valor 1 de %u: ", n);
res = scanf("%d", &p->min);
if ( res != 1 ) return NULL;
p->max = p->min; // afinal so tem um por enquanto
for ( unsigned i = 1; i < n; i = i + 1)
{
printf("Valor %u de %u: ", 1+i, n );
res = scanf("%d", &x);
// se res != 1 entao deu errado tentando ler o i-esimo numero
if ( res != 1 ) return NULL;
if (x > p->max)
p->max = x;
else if (x < p->min)
p->min = x;
}; // for()
return p; // retorna o ponteiro para a nova struct
}; // min_max()
int minMaxSeq(
unsigned n,
int* min,
int* max
)
{
int res = 0;
int x = 0;
printf("Valor 1 de %u: ", n);
res = scanf("%d", min);
if ( res != 1 ) return -1;
*max = *min;
n = n - 1; // ja leu um
for ( unsigned i = 0; i < n; i = i + 1)
{
printf("Valor %u de %u: ", 2+i, 1+n );
res = scanf("%d", &x);
// se res != 1 entao deu errado tentando ler o i-esimo numero
if ( res != 1 ) return -i-2;
if (x > *max)
*max = x;
else if (x < *min)
*min =x;
}; // for()
return 0;
}
Nice arfneto class, thanks! So just to be clear, there is no difference between int* pointer and int *pointer?
– Cl2727
no, there is no difference. but it is declaring
ponteiro
and the type of pointer isint*
as the compiler and the books will tell you.*coisa
is the content of thecoisa
. asterisk is an operator, the inverse of &, Pointer to E address of in the literature.– arfneto
Oh got it. When I put scanf on a pointer like I did in the code, scanf("%d", min);.. the value assigned then always goes to the content of the variable’s address? In this case "minimum"?
– Cl2727
scanf()
does not allocate memory. So you need to pass an address to each specifier, which is that like%d
or%s
for example. So either you pass a pointer, something declared astipo*
, or pass the address of something using the reverse,&algo
. For each specifier, AND TEST the return. It is naive not to test. See the program I showed you...– arfneto
includes an example of the function that allocates a new structure, so you can see the difference between passing two pointers as parameter and returning a structure with values.
– arfneto