Simple Teaching of Pointers

Asked

Viewed 793 times

17

I’m a sporadic programmer, and whenever I need to use pointers, I realize I’ve forgotten how to use it, and I have to work hard to learn everything again.

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

Grateful.

  • 1

    Good afternoon, you can follow this tutorial from USP...is quite interesting and has examples for everything they explain. Enjoy. http://www.ime.usp.br/~pf/algoritmos/aulas/Pont.html

4 answers

16


One way to see pointers is to make an analogy with names and addresses. Let’s say Alice lives at 42 X Street, Bob lives at 43 and Charlie at 44. If you only know Alice, but you don’t know or care where she lives, you can interact with her and only her.

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 in, you’ll find someone else in her place.

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 her 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 beware! If you stray too far from the known street, you may 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 noted "the value that’s in the address x". But it’s nice to point out that x is a variable like any other: it has a value, and exists in a memory position.

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 response from Lucas Virgili, one of the pointer utilities (in addition to traversing 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 memory position that used to hold something useful has now 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, pass pointers (or addresses) to functions you are calling is OK, return pointers or save them to the future, only if you know what you are doing.

  • 3

    Something that may seem confusing (at least for me I never use C): int *x = &array[0]; is the same as int *x; x = &array[0];, and nay int *x; *x = &array[0];. Right?

  • 1

    @bfavaretto Certo. Every time you declare and assign a variable at the same time, you are assigning its value, and nothing else. See int *x as (int *)x - or T x. T x = y; => T x; x = y;. The fact of T == (int *) does not change that. Already the operation of dereference (Dereferencing) - with or without attribution - should be seen as something apart. See *x as *(x) - or op(x). P.S. Just to avoid this kind of confusion, many people prefer to use int* x instead of int *x. I would also do so if I still messed with C. Tomorrow I update the answer with these details.

  • I really needed this piece. I think so too int* x much clearer.

14

In fact, as @Dante said, the Feofiloff tutorial is very good, but I will 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 one value associated. When we declare ourselves a variable, what we are doing and giving a name for 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 x has been the address position 1:

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

And we execute this command:

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

We’re gonna stay with:

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

Right? Now, suppose we, rather than want to refer to value of x, we want to know where x is in memory, for example, to change its value in another function. We can do this using the operator &:

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

Like I said, we might want this to change the value of x in another function, since in C, parameters pass by value (that is, the value of the variable is copied to the parameter, not the 'variable' in itself). So if we want to make a "incrememento" function, which increases its parameter to 1, we can do something like:

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

What does that mean? The function incremento 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 memory of her parameter, and the *a indicates the value on that address.

So if we make the following call from 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 to say, *a this pointing directly to the value that is in memory address 1, ie, x.

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

I hope I’ve helped :)

  • 2

    The answer was very good, but the little guy was a little confused: "it’s pointing directly at the value of x". It does not point to a value, even because if the value changes it will continue pointing to the same address (which will have a different value). Can I make a suggestion? Choose one of the other comics and put the value 1 in it, associating it with *a (as 123 associates with x). Then pull an arrow from that 1 to the address 1, where is the 123. Showing that the *a keeps the address where the x.

  • In fact :) I’ll do it!

10

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

hotel

Having a room is like having a variable. It is yours and no one else can use it. You are free to close your account and leave when you feel like it. But the pointer is a little different from having a room. A pointer is a key. If you hold a room key you can go see it whenever you want. You can also see the room number on your key and get a key to the rooms next door in the same hallway. That way you can go into the room, touch something and leave without the owner noticing what happened.

int quarto = 25;
int* chave = &quarto;
*chave = 17;

printf("%d", quarto); // Eeei! Mexeram no meu quarto

Or your room is part of a corridor:

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

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

You can arrive in another room of the corridor:

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 enter everyone’s room! But where is the danger? Good... 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 come back to see what’s inside this room, it might be exactly the way you left it. There may still be a 16 there. Or it may be that someone else has rented the same room! And you will find things of that other person there. Maybe one is ugly -23587936. Who knows?

But get this, if I can get keys to any room from a key I have, will I create keys to enter where I like?

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. Maybe this room doesn’t 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 may be a protected room. Yes! The hotel manager, your operating system, has the power to deny you access to some rooms. Or he might even let you in, but he’ll keep an eye on you so you don’t change anything there. Remember, if you violate the hotel rules you will be evicted without the right to complaints! A beautiful Segmentation fault.

  • 2

    I like the metaphor, I just hope my memory is less bizarre than this hotel in the picture!

6

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

Illustration

inserir a descrição da imagem aqui

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

Browser other questions tagged

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