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

4

I'm doing a code that consists of parsing an arithmetic expression, and checking if when I open a '(', then I should 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 to pointers in my functions as pop() , push() and verificasimbolo() . However, it has not been clear to me why this implementation. Since in codes I implemented a simple linked list, in similar functions I just needed a pointer to make those changes.

Thank you for your attention.

Here is 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] != '
#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] != '%pre%'; j++) {
            verificaSimbolo(&topo, argv[i][j]);

        }
    }

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

}
'; j++) { verificaSimbolo(&topo, argv[i][j]); } } if(ehvazia(&topo)) printf("Expressao valida\n"); else printf("Expressao invalida\n"); }
    
asked by anonymous 13.07.2017 / 06:02

1 answer

4

Consider the following example, make a function that changes the value of an integer. We could start with a simplistic (though wrong) approach:

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

And call it on main:

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

That shows:

  

2

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

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

How can we then do to even change x ?

Instead of passing the numero we pass the address where it is in memory, that way we can go where it is and change it. Let's start by changing the alteraInt() function to get 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 also changed:

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

That already shows what expected:

  

10

Let's now transpose this principle to 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);

What it presents:

  

Before 0028FF18

     

Then 0028FF18

The pointer was not changed because we copied the pointer value into the function. When you change within 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 passing a pointer to this pointer, so that the function knows where to go to memory to change. Then the function is now:

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

And in the call also changes:

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

Result:

  

Before 0028FF18

     

Then 00000014

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

But it's 14 in the result!?

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

And why does it have to be that way in the queue?

In main we have a pointer that represents the queue:

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

    PILHA* topo = NULL;

And in some functions we want to change the value of this pointer, by pointing it to another node, such as push:

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

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

Conclusion

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

    
13.07.2017 / 11:50