Simple Pointer Teaching

16

I'm a sporadic programmer, and whenever I need to use pointers, I realize that I've forgotten how to use it, and I have to grate to learn everything again.

Does anyone have any simple didactics to remember the concept of pointers, and that is easy to save? I always learn, I've learned about 8 times, but I always forget too!

Thank you.

    
asked by anonymous 25.07.2014 / 20:12

4 answers

16

One way to see pointers is to make an analogy with names and addresses. Let's say that Alice lives at number 42 on X street, Bob lives at number 43 and Charlie at 44. If you only know Alice but do not know or care about where she lives, you can interact with her and only her. p>

int array[3] = {10, 20, 30};
int x = array[0]; // Você conhece o valor 10, mas não sabe em que posição de memoria ele está
int y = x + x;    // Você pode fazer operações com essa valor

array[0] = 40;   // Se o valor do array mudar
printf("%d", x); // x continua sendo 10

x = 50;
printf("%d", array[0]); // E vice-versa (40)

On the other hand, if all you know is where Alice lives, then you have to go there to meet her. If she moves, you'll find someone else instead.

int array[3] = {10, 20, 30};
int *x = &array[0]; // Dessa vez você salvou a posição de memória em que o valor 10 está
                    // &v significa "o endereço de v"; x não contém 10, mas o endereço do 10
int y = *x + *x;    // Se o 10 ainda estiver lá, você pode fazer operações com ele
                    // *x significa "o valor no endereço x"; ou seja, 10

array[0] = 40;    // Se o valor do array mudar
printf("%d", *x); // *x passa a ser 40
                  // x não mudou, continua sendo o mesmo endereço; o ocupante do endereço é que mudou

Also, if you have Alice's address, you can visit your neighbors.

int array[3] = { 10, 20, 30 };
int *x = &array[0]; // x guarda o endereço do primeiro valor do array (10)

printf("%d", *x); // 10

x++;              // Ao incrementar o x, ele passa a guardar o endereço do valor seguinte
printf("%d", *x); // 20

x++;
printf("%d", *x); // 30

But be careful! If you get too far off the known street, you can end up anywhere; probably a dangerous place ...: P

x++;              // O 30 está numa posição de memória qualquer; na posição seguinte, tem alguma
                  // coisa, mas você não sabe o que é.
printf("%d", *x); // Um valor inesperado, ou segmentation fault

So far, I've only given examples that looked at "the value that is in the x address". But it's good to note that x is a variable like any other: it has a value, and exists in a memory location.

int array[3] = {10, 20, 30};
int *x = &array[0];

printf("%d", x); // Aqui ele vai imprimir o endereço em memória do 10;
                 // pode ser qualquer coisa, inclusive mudar de uma invocação pra outra

int **z = &x; // Agora z tem a posição de memória onde está x
*z++;         // Se ele incrementar o valor que está lá
printf("%d", x); // x passa a ser o endereço em memória do 20
printf("%d", *x); // 20

Addendum: As demonstrated in the Lucas Virgili response , one of the utilities of pointers (besides running arrays, arrays, etc., and creating data dynamically via malloc etc) is to allow a function to change values that only exist outside that function. But you have to be careful, because sometimes the position of memory that once held something useful now has already been "recycled" to something else:

int *foo() {
    int x = 42;  // O valor 42
    int *y = &x; // O endereço de memória onde 42 está
    return y;
}

...

int *z = foo();   // O endereço de memória onde o 42 estaVA
bar();
printf("%d", *z); // (foo já terminou, então suas variáveis locais não estão necessariamente na mesma
                  //  posição de memória - ou sequer ainda existem [garantidamente])

As a rule, passing pointers (or addresses) to functions you are calling is OK, returning pointers or saving them for the future, only if you know what you are doing.

    
25.07.2014 / 21:43
13

In fact, as @Dante said, the Feofiloff tutorial is very good, but I'll try my own explanation.

Suppose you have a memory with 5 positions. Each position has an address, going from 0 to 4:

Endereco         0            1           2           3           4
           +------------+-----------+------------+-----------+-----------+
           |            |           |            |           |           |
           |            |           |            |           |           |
Valor      |    17      |     -12   |    99999   |   0       |   3.14    |
           |            |           |            |           |           |
           |            |           |            |           |           |
           +------------+-----------+------------+-----------+-----------+

As you can see, each address has an associated value . When we declare ourselves a variable, what are we doing and giving a name to any of these positions, right? For example:

int x; // O compilador vai fazer sua magica e alguma posicao da memoria vai
       // receber o nome x

Let's say that x was at position 1:

Endereco         0            1           2           3           4
           +------------+-----------+------------+-----------+-----------+
           |            |           |            |           |           |
           |            |           |            |           |           |
Valor      |    17      |     -12   |    99999   |   0       |   3.14    |
           |            |           |            |           |           |
           |            |           |            |           |           |
           +------------+-----------+------------+-----------+-----------+
                              /                                   
                             /                                    
                            /                                    
                           x

And let's run this command:

x = 123; // agora essa posicao vai ter seu valor alterado para 123.

We're staying with:

Endereco         0            1           2           3           4
           +------------+-----------+------------+-----------+-----------+
           |            |           |            |           |           |
           |            |           |            |           |           |
Valor      |    17      |     123   |    99999   |   0       |   3.14    |
           |            |           |            |           |           |
           |            |           |            |           |           |
           +------------+-----------+------------+-----------+-----------+
                              /                                   
                             /                                    
                            /                                    
                           x

Correct? Now suppose that we want to know where x is in memory, for example, in order to change the value of x . value it in another function. We can do this using the & operator:

int endereco = &x; // endereco vai valer 1, o endereco da variavel x

As I said, we might want this to change the value of x into another function, since in C, passing parameters is done by value (ie the value of the variable and copied to the parameter, not 'variable' itself). So, if we want to do an "increment" function, which increments its parameter by 1, we can do something like:

void incremento(int *a) {
    *a = *a + 1;
}

What does this mean? The incremento function no longer receives an integer value, it receives a pointer to a position in memory. When we do, then, *a = *a + 1; , the function knows exactly the address in the memory of its parameter, and the *a indicates the value that is in that address.

So, if we make the following call to the increment function:

incremento(&x); // Passamos para incremento o endereco de X

What happens in memory and something like:

                                  /------------
                                 /             \
                                /               \
Endereco         0            1           2      \    3           4
           +------------+-----------+------------+\----------+-----------+
           |            |           |            | \         |           |
           |            |           |            |  \        |           |
Valor      |    17      |     124   |    99999   |   1       |   3.14    |
           |            |           |            |     \     |           |
           |            |           |            |      \    |           |
           +------------+-----------+------------+-------\---+-----------+
                              /                           \
                             /                             \
                            /                              *a
                           x

That is, *a is pointing directly to the value that is in memory address 1, that is, x .

This is the most fundamental use of C pointers. Better understand the basics before the rest: P

I hope I have helped:)

    
25.07.2014 / 20:34
10

The memory is like a large, spacious hotel. It has many fours, all numbered, and in each of those there may be someone.

Havingaroomislikehavingavariable.Itisyoursandnooneelsecanuseit.Youarefreetocloseyouraccountandleaveasyouwish.Butthepointerisabitdifferentfromhavingaroom.Apointerisakey.Ifyoukeepthekeytoaroomyoucangoseeitwheneveryouwant.Youcanalsoseetheroomnumberthatisonyourkeyandgetakeytotheroomsnextdoorinthesamehallway.Thiswayyoucanentertheroom,tinkerwithsomethingandleavewithouttheownernoticingwhathappened.

intquarto=25;int*chave=&quarto;*chave=17;printf("%d", quarto); // Eeei! Mexeram no meu quarto

Or your room is part of a hallway:

int corredor[] = {10, 20, 30};
int* chave2 = &corredor[1];
*chave2 = corredor[0];

printf("%d", corredor[1]); // Ops, meu vinte sumiu

You can reach another room in the hallway:

int corredor[] = {10, 20, 30};
int* chave2 = &corredor[1];
int* chave3 = chave2 + 1;
*chave3 = corredor[0];


printf("%d", corredor[2]); // Mas eu nem dei a chave desse quarto!

Very cool! I can go into everyone's room! But where is the danger? Well ... Imagine you rented a room, took a key for it, made a copy of it, and then returned the room.

int* evil() {
    int quarto = 16;
    int* chave = &quarto;
    return chave;
}

The big problem is that when you go back to see what's inside that room, it may be just the way you left it. You can still have a 16 there. Or it may be that someone else has rented the same room! And you will find things from that other person there. Maybe one be ugly -23587936. Who knows?

But look, if I can get keys to any room from a key I have, can I create keys to enter where I please?

int* chaveMestra = 5678; // Pronto, tenho a chave para o quarto 5678. Não sei o que tem lá.

int outroQuarto = *chaveMestra; // oops!

What if I go in there and try to see the room? Very problematic. It may be that this room does not even exist. It may be from a part of the hotel that existed a while ago but was demolished because no one lived there. Or even worse, it could be a protected room. Yes! The hotel manager, your operating system, has the power to forbid you from accessing some rooms. Or he may even let you in, but he will keep an eye on you not to change anything there. Remember, if you violate hotel rules you will be turned down with no right to complaints! A beautiful segmentation fault.

    
26.07.2014 / 17:33
6

Simple teaching, right? Then nothing like a short example accompanied by an image. :)

Illustration

Code

#include <iostream> int main() { /*** DECLARAÇÃO ***/ int *i; int j; char c; char *s; /*** ATRIBUIÇÃO ***/ i = (int *) malloc(sizeof(int)); *i = 2; j = 42; s = "ola!"; c = s[2]; /*** APRESENTAÇÃO ***/ printf("Endereco de i: 0x%x\n", &i); printf("Valor de i = 0x%x\n", i); printf("Valor apontado por i = %d\n", *i); printf("Endereco do valor apontado por i = 0x%x\n", &(*i)); printf("Endereco de j: 0x%x\n", &j); printf("Valor de j: %d\n", j); // Valor apontado por j (e seu endereço) não faz sentido porque j não foi declarado como ponteiro // (gera erro "illegal indirection") printf("Endereco de s: 0x%x\n", &s); printf("Valor de s: 0x%x (%s)\n", s, s); printf("Valor apontado por s: %c\n", *s); printf("Endereco do valor apontado por s: 0x%x\n", &(*s)); printf("Endereços de s[0], s[1], s[2] e s[3]: 0x%x, 0x%x, 0x%x e 0x%x\n", &(s[0]), &(s[1]), &(s[2]), &(s[3])); printf("Endereco de c: 0x%x\n", &c); printf("Valor de c = %c\n", c); // Mesmo comentário para o valor apontado por j, já que c também não foi declarado como um ponteiro /*** ENCERRAMENTO ***/ free(i); // libera memória da única variável alocada dinamicamente return 0; }

Result (for example)

Endereco de i: 0x95fef8
Valor de i = 0xad44d8
Valor apontado por i = 2
Endereco do valor apontado por i = 0xad44d8
Endereco de j: 0x95feec
Valor de j: 42
Endereco de s: 0x95fed4
Valor de s: 0x10cd08 (ola!)
Valor apontado por s: o
Endereco do valor apontado por s: 0x10cd08
Endereþos de s[0], s[1], s[2] e s[3]: 0x10cd08, 0x10cd09, 0x10cd0a e 0x10cd0b
Endereco de c: 0x95fee3
Valor de c = a
    
26.07.2014 / 00:04