Ir para conteúdo

Desafio de ponteiros


Leandro Fróes

Posts Recomendados

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!

Link para o comentário
Compartilhar em outros 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!

Link para o comentário
Compartilhar em outros 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!

Link para o comentário
Compartilhar em outros 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! ;]]

Link para o comentário
Compartilhar em outros 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).

Link para o comentário
Compartilhar em outros 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!

Link para o comentário
Compartilhar em outros 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á)

Link para o comentário
Compartilhar em outros 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

Link para o comentário
Compartilhar em outros 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

Link para o comentário
Compartilhar em outros 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

Link para o comentário
Compartilhar em outros 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!!

Link para o comentário
Compartilhar em outros 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!

Link para o comentário
Compartilhar em outros sites

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...