Match pointers in C

Asked

Viewed 97 times

1

In this code I picked up because I was unable to think about the exercise, in line 3 of the code the program asks for the min scanf, where min is a pointer, and min receives a scanf value, but the min value would not be the address value that the pointer indicates? In this case it seems that the amount that min receives is the same as *min, I could not catch the racicionio, if someone can clear thank very much the attention

The exercise would be this: Using the above strategy, write a function that returns the minimum and maximum value of a sequence of n user-provided values. The reading of the typed values on the keyboard should be done within the function. However, the amount of values to be read (n) shall be a function input parameter

int minMaxSeq(int n, int *min, int *max) {
    int i, x;
    scanf("%d", min);
    *max = *min;
    for (i = 2; i <= n; i = i + 1) {
        scanf("%d", &x);
        if (x > *max){
            *max = x;
        } else if (x < *min){
            *min  = x;
        }
    }
}

int main(void)
{
    int n, minimo, maximo;
    scanf("%d", &n);
     if (minMaxSeq(n, &minimo, &maximo))
        printf("%4d%4d\n", minimo, maximo);
    else printf("sequencia vazia\n");
        return 0;
}

2 answers

3


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?

  • no, there is no difference. but it is declaring ponteiro and the type of pointer is int* as the compiler and the books will tell you. *coisa is the content of the coisa. asterisk is an operator, the inverse of &, Pointer to E address of in the literature.

  • 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"?

  • 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 as tipo*, 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...

  • 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.

2

I’ll assume you already know the ratings:

  • &variable : memory address of variable
  • *pointer : value contained in memory address pointed by pointer

The function scanf expects from the second parameter a memory address. Assuming you have an entire type variable called min, you would use the scanf function this way:

    int minimo;
    scanf("%d", &minimo);

In its example, considering exclusively the code existing in the function minMaxSeq, you have min defined as an integer pointer (int *). Since min is already an integer pointer, you are using the scanf function in this way:

    int* min = /*algum endereço de memória, por exemplo endereço da variável minimo */;
    scanf("%d", min);

In general, what your program does is:

  • the main function (main) allocates space for 3 integer variables;
  • invokes the function minMaxSeq passing by n by value and minimum and maximum by reference (passes addresses of variables);
  • its function minMaxSeq reads the first value and assigns it to the variables pointed by min and max (minimum and maximum) through the address of the variables received by parameter;
  • in the following iterations, the next values are read and compared to the current values of min and max and eventually min or max can be changed;
  • at the end of the execution of minMaxSeq, the control goes back to main and the minimum and maximum values can be used to be "printed" for the user.
  • Alex thanks for the comment! Just to be clear, there is no difference between int* pointer and int *pointer?

Browser other questions tagged

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