Pointer pointer to change my battery. Why should I use them?

Asked

Viewed 732 times

5

I am making a code that consists of analyzing an arithmetic expression, and checking if when I open a '(', then I must close a ')'. That is, check whether the expression is valid or not. For this I implemented a stack to help me solve this problem.

However, I realized that I should use a pointer pointer in my functions such as pop(),push() and verificasimbolo(). However, it has not yet become clear to me why this implementation is taking place. Since in codes I implemented a simple chained list, in similar functions I only needed a pointer to make these changes.

Thank you for your attention.

Just follow my code:

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

#define ABRE_PARENTESE '('
#define FECHA_PARENTESE ')'

struct pilha {

    char elemento;
    struct pilha* prox;

};

typedef struct pilha PILHA;

int ehvazia(PILHA** p) {
    return *p == NULL;
}

void verifica(PILHA** p){
    if(*p == NULL) {
        printf("MEMORIA INDISPONIVEL\n");
        exit(1);
    }
} 

void push(PILHA** topo, char newElemento) {

    PILHA* newPtr = malloc(sizeof(PILHA));
    verifica(&newPtr);

    newPtr->elemento = newElemento;
    newPtr->prox = (*topo);
    (*topo) = newPtr;

    printf("%c foi inserido na pilha.\n", (*topo)->elemento);
    // free(newPtr);
}

void pop(PILHA** topo) {

    PILHA* tempPtr;
    tempPtr = malloc(sizeof(PILHA));
    verifica(&tempPtr);

    tempPtr = (*topo);
    (*topo) = (*topo)->prox;

    printf("%c foi removido da pilha.\n", tempPtr->elemento);
    free(tempPtr);

}

void verificaSimbolo(PILHA** topo, char simbolo) {

    if((simbolo == ABRE_PARENTESE)
        || (simbolo == FECHA_PARENTESE)) {

        if(ehvazia(topo)) {
            push(topo, simbolo);

        }
        else if(((*topo)->elemento == ABRE_PARENTESE)
            && (simbolo == FECHA_PARENTESE)){
            pop(topo);

        } else{
            push(topo, simbolo);
        }
    }
}


int main(int argc, char** argv) {

    PILHA* topo = NULL;

    f       
        }
    }

    if(ehvazia(&topo))
        printf("Expressao valida\n");
    else 
        printf("Expressao invalida\n");

}
 for(int i = 1; i < argc; i++) {
        for(int j = 0; argv[i][j] != '\0'; j++) {
            verificaSimbolo(&topo, argv[i][j]);

        }
    }

    if(ehvazia(&topo))
        printf("Expressao valida\n");
    else 
        printf("Expressao invalida\n");

}

1 answer

5


Let us consider the following example, to make a function that changes the value of an integer. We could start with a simplistic approach (although wrong):

void alteraInt(int numero){
    numero = 10;
}

And call her on the main:

int x = 2;
alteraInt(x);
printf("%d",x);

Which shows:

2

And now we can wonder, but why? if it was changed in function ?

In c the default values are passed to the copy functions, logo the parameter numero in function alteraInt() is a copy of x! So change the numero no function does not change the x main.

How then can we do to even change the x ?

Instead of passing the numero we pass the address where it is in memory, that way we can go to where it is and change it. Let’s then start by changing the function alteraInt() to receive the pointer instead of an integer:

void alteraInt(int *numero){ //agora recebe ponteiro
    *numero = 10; //agora diz que o valor que está no endereço recebido passa a ser 10
}

The call was going to change too:

alteraInt(&x); //agora com o & para passar o endereço do x e não o valor

That already shows the expected:

10

We will now transpose this principle into a pointer. If we have a pointer and want to change the pointer in a function we return to the same problem.

void alteraPonteiro(int *ponteiro){
    ponteiro = 20; //só para exemplificar vamos colocar o endereço 20 no ponteiro
}

And now call this function with a pointer:

int x = 2;
int *p = &x; //ponteiro p aponta para o x
printf ("Antes %p", p);
alteraPonteiro(p);
printf ("\nDepois %p", p);

That presents:

Before 0028FF18

After 0028FF18

The pointer was not changed because we copied the value of the pointer into the function. When changing inside the function you are changing a copy of the pointer and not the original pointer.

How can we fix this?

Applying the same principle, and now pass a pointer to this pointer, so that the function knows where to go to the memory to change. So the function is now:

void alteraPonteiro(int **ponteiro){ //agora ponteiro de ponteiro
    *ponteiro = 20; //agora com * para ser o valor apontado
}

And the call also changes:

alteraPonteiro(&p); //agora passa o endereço do ponteiro em vez do valor dele

Upshot:

Before 0028FF18

After 00000014

Here we see that we can change the value of the pointer, and have it point to the address 20.

But it is 14 in the result !?

This is because when we write the value of a pointer with %p It by default is presented in hexadecimal, and 0x14 in hexadecimal corresponds to 20 in decimal.

And why it has to be that way in the queue ?

In the main we have a pointer representing the row:

int main(int argc, char** argv) {

    PILHA* topo = NULL;

And in some functions we want to change the value of this pointer, to point it to another node, for example in the push:

void push(PILHA** topo, char newElemento) {
    ...
    (*topo) = newPtr;

If you receive a normal battery pointer, a PILHA* , this will be a copy of what exists in main and so does not alter what we have in main. Instead it has to be like this code node and receive the memory address where the main pointer is, so the function can go to that location and change.

Completion

If we have a variable of a certain type and want to change it within a function, we have to receive a pointer to it in the function, otherwise we are changing a copy of that variable.

  • I understand now. Thank you very much Isac =)

Browser other questions tagged

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