Jump to content
Sign in to follow this  
Leandro Fróes

Desafio de ponteiros

Recommended Posts

Boa tarde galera,

 

um tempo atrás fiquei com uma dúvida e tanto sobre ponteiros, principalmente com um uso em específico. Tendo isso em mente decidi jogar aqui pra vocês testarem e pensarem, acho que vai ser legal pra geral aprender. P.S Não usem o google, testem ;)

 

- Qual a diferença entre (*p) e *p?

 

Só será validada a resposta daquele que mostrar o código e o pq, sem compromisso galera, apenas pra descontrair :)

 

Abraços!

Share this post


Link to post
Share on other sites

*p = valor da posição de memoria;

(*p) = valor da posição da posição de memória neste caso usando um array/vetor

 

void f()
{
  	int v[] = {1, 2, 3}, x=24;
  int * p= NULL;
  
  p = &x;
  
  std::cout << *p << "!\n"; //output o valor de x = 24
  std::cout << (*v)+1 << "!\n"; //output 2
  
}

PS: Caso eu tenha dito besteira favor me corrija!

Edited by kassane

Share this post


Link to post
Share on other sites
1 hora atrás, kassane disse:

*p = valor da posição de memoria;

(*p) = valor da posição da posição de memória neste caso usando um array/vetor

 


void f()
{
  	int v[] = {1, 2, 3}, x=24;
  int * p= NULL;
  
  p = &x;
  
  std::cout << *p << "!\n"; //output o valor de x = 24
  std::cout << (*v)+1 << "!\n"; //output 2
  
}

PS: Caso eu tenha dito besteira favor me corrija!

Opa, na verdade *p aponta para o conteúdo do endereço que tem dentro de p, como ai foi um vetor ele aponta para o endereço do primeiro elemento do vetor. Se você fizer (*v)+1 ele vai pegar o primeiro elemento e somar 1 e não andar uma posição. Ai deu certo porque 1+1 da 2 xD. Exemplo:

#include <stdio.h>

int main(){

  int v[] = {10,20,30};
  int *p = v;

  printf("Segunda posicao do vetor: %d\n", (*p)+2);

  return 0;

}

 

user@user:/home# ./test
Segunda posicao do vetor: 12

 

Mas o caminho pra achar a resposta é esse mesmo: arrays. Vou esperar mais um tempo antes de postar a resposta.

 

Abraço!

Share this post


Link to post
Share on other sites

Queria deixar uma pergunta interessante para se pensar antes de resolver o desafio. Considerando o ponteiro p:

 

  •  O que acontece se usarmos p++? E quando se usa (*p)++?

 

Tente aplicar em um array e veja seus elementos =D

 

Abraço!

Share this post


Link to post
Share on other sites

Falai, Leandro! Bele ?

Legal essa questão, trabalhar com pointeiro é tenso. Nada melhor que treinar ;p

Nesse caso, se printarmos o "p++" direito no printf o valor não irá mudar.
Pois o operador ++ usado após a variável só incrementado depois de valor de p ser mostrado no print. Ou seja, no print ele n muda.
Porém se você usar o operador antes da variável ++p ele primeiro soma o valor de p para então usá-lo.

No caso de p++ ele irá acrescentar o tamanho do ponteiro p. Se for int em 32bit endereço de p + 4.
No caso do (*p)++ é o mesmo lance do operador, mas nesse caso ele soma o valor contido no primeiro elemento do array.

Vale ressaltar que o parentes são opcionais, não muda em nada.

Abraço! ;]]

Edited by Pimptech

Share this post


Link to post
Share on other sites
#include <stdio.h>
int main(void){
    int a[] = {10,20};
    int *p = a;

    // De primeira a gente acha que a ordem de interpretação dos parâmetros é da
    // esquerda para direita, mas não.

    //                                                                       2º       1º a ser interpretado
    printf("*(++p): %d\t++(*p): %d\n", *(++p), ++(*p));

    //volta o valor original de p (endereço de a)
    p--;

    //                                                                        2º       1º (p agora é a[1] que é 20)
    printf("++(*p): %d\t*(++p): %d\n", ++(*p), *(++p));

    return 0;
}

Saída:

*(++p): 20      ++(*p): 11
++(*p): 21      *(++p): 20

Se eu escrevi alguma bobeira por favor me corrijam rs

Explicando melhor!

Se no primeiro printf o primeiro parâmetro (da esquerda para direita) fosse avaliado primeiro teríamos que ter 20 e 21, não 20 e 11.

O que parece acontecer é:

  1. Pega-se o valor de *p e soma 1 (isso da 11) e guarda esse valor (2º parâmetro da esquerda para direita)
  2. Incrementa-se o valor do endereço de p e pega seu valor (isso dá 20) (1º parâmetro da esquerda para direita)

A impressão desses valores segue a ordem "normal"  da esquerda para direita, aí dá 20 e 11.

Fiz isso para mostrar a diferença nos usos do parêntesis e também o que acontece quando passamos parâmetros para funções (melhor dizendo, como elas são avaliadas, em que ordem).

Edited by gzn

Share this post


Link to post
Share on other sites
3 horas atrás, gzn disse:

#include <stdio.h>
int main(void){
    int a[] = {10,20};
    int *p = a;

    // De primeira a gente acha que a ordem de interpretação dos parâmetros é da
    // esquerda para direita, mas não.

    //                                                                       2º       1º a ser interpretado
    printf("*(++p): %d\t++(*p): %d\n", *(++p), ++(*p));

    //volta o valor original de p (endereço de a)
    p--;

    //                                                                        2º       1º (p agora é a[1] que é 20)
    printf("++(*p): %d\t*(++p): %d\n", ++(*p), *(++p));

    return 0;
}

Saída:


*(++p): 20      ++(*p): 11
++(*p): 21      *(++p): 20

Se eu escrevi alguma bobeira por favor me corrijam rs

Explicando melhor!

Se no primeiro printf o primeiro parâmetro (da esquerda para direita) fosse avaliado primeiro teríamos que ter 20 e 21, não 20 e 11.

O que parece acontecer é:

  1. Pega-se o valor de *p e soma 1 (isso da 11) e guarda esse valor (2º parâmetro da esquerda para direita)
  2. Incrementa-se o valor do endereço de p e pega seu valor (isso dá 20) (1º parâmetro da esquerda para direita)

A impressão desses valores segue a ordem "normal"  da esquerda para direita, aí dá 20 e 11.

Fiz isso para mostrar a diferença nos usos do parêntesis e também o que acontece quando passamos parâmetros para funções (melhor dizendo, como elas são avaliadas, em que ordem).

Falai, @gzn.

Bele ? Bacana o exemplo! =)
Porém só queria acrescentar que os parenteses não fazem diferença. 
Se você remove-los o resultado será o mesmo. O que importa é a ordem de incremento.

Se incrementar diretamente o ponteiro ++p, o endereço será incrementado no tamanho do ponteiro. Então podemos usar *++p para incrementar primeiro o endereço(ponteiro) e depois "castar" para pegar o valor que o endereço de p aponta. Parenteses em ponteiros são ilustrativos, dão uma sensação de separação, são usados mais para deixar o código mais "legível". É nois! 

Abraço!

  • Curtir 1

Share this post


Link to post
Share on other sites

Sr. @Pimptech obrigado pelos esclarecimentos.

E ai @Leandro Fróes , vc tem algum comentário para ajudar a gente a entender melhor isso? comenta aí! rs

Se o @fredericopissarra puder vir aqui e dar um comentário extra também seria uma boa, pq esse sr. entende bastante (esses dias quando fiz o curso do merces de prog moderna em c li muitos comentários dele lá)

Edited by gzn

Share this post


Link to post
Share on other sites

Bom, a diferença entre *p e (*p), puramente, é nenhuma. :P
Agora, você falou sobre usar incrementos... Ai sim os parênteses fazem diferença...

Já que se nós escrevemos *p++ irá resultar em:
1) É usado o valor que p está apontando no momento.
2) DEPOIS da operação é incrementado o valor do ponteiro p.

Agora, ao fazer (*p)++ o resultado é:
1) É usado o valor que p está apontando.
2) DEPOIS da operação é incrementado o valor ONDE o ponteiro aponta...

Isto é, sem os parênteses é incrementado o endereço para onde p aponta.
E com os parênteses é incrementado o VALOR que p está apontando na memória.

Como você pediu, deixo um código exemplificando:
https://ghostbin.com/paste/8gpjw

Edited by Felipe.Silva
  • Curtir 2

Share this post


Link to post
Share on other sites
 1 /**
 2  * Hehe, esse negócio confunde mesmo.
 3  * O parenteses parece fazer diferença conforme o uso.
 4  */
 5 #include <stdio.h>
 6 int main(void){
 7     int a[] = {10, 20}, *p = a;
 8 
 9     (*p)++;
10     printf("%d\n", *p); // saída é 11
11 
12     *p++;
13     printf("%d\n", *p); // saída é 20
14 
15     return 0;
16 }

E aí, faz ou não faz diferença? :D

Edited by gzn
  • Curtir 1

Share this post


Link to post
Share on other sites
14 horas atrás, gzn disse:

 1 /**
 2  * Hehe, esse negócio confunde mesmo.
 3  * O parenteses parece fazer diferença conforme o uso.
 4  */
 5 #include <stdio.h>
 6 int main(void){
 7     int a[] = {10, 20}, *p = a;
 8 
 9     (*p)++;
10     printf("%d\n", *p); // saída é 11
11 
12     *p++;
13     printf("%d\n", *p); // saída é 20
14 
15     return 0;
16 }

E aí, faz ou não faz diferença? :D

É, faz hehe..
Se quiser isolar primeiro o valor que p aponta e depois usar o incremento. Caso específico.

Muito bom, n tinha pensado nesse ponto. Vivendo e aprendo :D

  • Agradecer 1

Share this post


Link to post
Share on other sites

Boa tarde pessoal!

 

Muito foda que vocês tentaram, deixaram o post muito completo. Bom, mas eai? Qual a diferença? Depende kkkkkkk

 

Até onde eu sei (e se alguém souber mais por favor, compartilhe) o parênteses serve para dar ênfase. Na prática eu vejo algumas situações que fazem diferença e duas já foram citadas aqui. São elas:

  • Incremento (ou decremento): aqui *p++ anda de acordo com o tipo de dado que o ponteiro aponta e (*p)++ da ênfase ao elemento apontado.

 

  • Percorrendo um array:
    #include <stdio.h>
    
    int main(){
    
    	int v[] = {10,20,30};
    	int *p = v;
    	int i;
    
    	for(i=0;i<3;i++){
     		printf("Com parenteses: %d\n", *(p+i));
     		printf("Sem parenteses: %d\n", *p+i);
    
    	}
    
    }

    Saída:

Com parenteses: 10
Sem parenteses: 10
Com parenteses: 20
Sem parenteses: 11
Com parenteses: 30
Sem parenteses: 12

 

E um outro caso que não foi comentado aqui é para declaração de arrays. Quando usamos int *v[] estamos criando um array de ponteiros do tipo intero. Agora quando usamos int (*v)[] estamos criando um ponteiro para um array de inteiros.

 

Mas é isso ai galera, desafio concluído e já achamos 3 coisas interessantes, alguém tem algo mais para mostrar para nós? :)

 

Abraços!!

Share this post


Link to post
Share on other sites

Meus dois dedinhos de prosa, se é que já não explicaram isso exaustivamente ai em cima...

"Ponteiro" é apenas uma variável, como qualquer outra, que contém um ENDEREÇO de memória ao invés de um valor do tipo especificado. Existe diferença entre a DECLARAÇÃO de algo e seu USO, especialmente quando se lida com "ponteiros". Abaixo, temos uma declaração de uma variável p que é um ponteiro que aponta para um char, na memória. Obviamente a variável não está inicializada (assim como você pode fazer com declarações como "int x;"):

char *p;

E, abaixo, temos a declaração de um array s contendo uma string e a inicialização do ponteiro p que passa a apontar para o 3º byte da string:

char s[] = "Fred";
char *p;

p = &s[2];  // & é o OPERADOR "endereço de"...

Assim como com outros tipos de variáveis, OPERAÇÕES são efetuadas usando OPERADORES como +, -, *, /, =, etc. Só que, com ponteiros, o símbolo * é também usado como OPERADOR DE INDIREÇÃO, ou seja, ele pega o endereço no interior da variável e usa para localizar o dado referenciado por esse endereço. Quando fazemos:

*p = 'a'; // usando o ponteiro inicializado acima

A variável p (ponteiro p) contém o endereço (aponta para) do 3º item do array s. O * antes de p é o OPERADOR DE INDIREÇÃO que usa o endereço contido em p e pega (ou escreve, neste caso, porque temos o operador = e a expressão está do lado esquerdo) o caracter apontado.

A expressão *p pega/escreve 1 caracter porque este é o tipo APONTADO pela variável p.

Quando usamos operadores como +, -, ++ e -- com ponteiros trabalhamos com aritmética (duh!), mas o endereço será incrementado ou decrementado de acordo com o tamanho do tipo... Por exemplo, se fizermos:

int x[] = { 1, 2, 3, 4};
int *p = &x[1];

printf("%d\n", *++p);

Assumindo que p tem um endereço 0x400020 depois de inicializado, ao fazer ++p ele conterá 0x400024, ou seja, incrementamos o endereço em 4 unidades porque o tamanho de um "int" é de 4 bytes. mas note que a expressão que usei no printf() foi *++p. Isso quer dizer que fazemos um pré-incremento de p (p apontará para a posição do array x que contém o 3) e depois usamos o operador de indireção para ler o valor 3 no endereço dado por p.

Neste ponto podemos responder qual é a diferença entre *p e (*p)... NENHUMA! Note que se tivéssemos uma expressão como:

a = b;

Faz alguma diferença se escrevessemos isso como "a = (b)"? Os parênteses ai é um operador, mas é usado apenas para forçar a ordem de precedência da expressão como um todo.

Isso não significa que parensteses não possam ser usados para DECLARAR tipos diferentes de ponteiros... Por exemplo:

int *a[];  // a é um array de ponteiros para int.
int (*a)[]; // a é um ponteiro de arrays para int.

E, às vezes, os parenteses ajudam a garantir que uma expressão faça o que queremos que ela faça... Por exemplo:

c = *p++;  // mesma coisa que c=*p; p=p+1;
c = (*p)++; // mesma coisa que c = *p; t = *p; t = t + 1; *p = t;

Aliás... não é obvio, mas ao obtermos um N-ésino item de um array a, por exemplo, via a[N], na verdade o símbolo 'a' é o ponteiro para o primeiro elemento do array que é somado ao valor N e depois "derreferenciado" (via um operador de indireção implícito)... Ou seja:

a[N] == *(a + N)

Isso gera um "macete" interessante, mas perigoso: a[N] também pode ser escrito como N[a] (tente, o compilador não reclamará!). Isso porque *(a + N) é a mesma coisa que *(N + a) - propriedade comutativa da adição!

  • Curtir 3

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...