Dúvidas sobre ponteiros em C

Surgiram algumas ´dúvidas aqui sobre o uso de ponteiros em C. Vamos supor que “k” seja um ponteiro para inteiro, recebido como parâmetro em uma função. Se eu modificar “k” dentro do corpo da função das formas abaixo, qual o significado de cada uma das formas de alteração?

(*k)++

*k++

*(k++)

Agradeço desde já a atenção…

não é por nada não, mas isso tá com cara de tarefa de casa.

olha o enunciado da questão:

"Vamos supor que “k” seja um ponteiro para inteiro, recebido como parâmetro em uma função. Se eu modificar “k” dentro do corpo da função das formas abaixo, qual o significado de cada uma das formas de alteração? "

Eu sou programador Java. Eu nunca programei efetivamente em C. Mal conheço a linguagem, mas estou querendo aprender. Fiz alguns testes e bolei uma função com esta cara abaixo para testar como o ponteiro é modificado. Coloquei a questão desta forma porque ela surgiu dentro deste contexto. Mas enfim…Não precisa responder se não quiser.

void testa(char *string, int *k) { char letra=0; fflush(stdin); scanf("%c",&letra); string[(*k)]=letra; (*k)++; string[(*k)]='\0'; }

É uma função simples que recebe um ponteiro para char e uma posição. Cada vez que é chamada ela adiciona o caracter lido à nova posição, de modo que o programa principal possa conhecer tanto a string quanto a posição, visto que são manipulados por referência dentro da função…Fiz a função para testar a noção de ponteiros a a aritmética de ponteiros.

(*k)++

*k++

*(k++) 

Vamos pensar: se k tem o tipo char*, *k tem o tipo char. Simples, não?

Digamos que k aponte para uma região de memória que contém 2 caracteres, ‘A’ e ‘Z’.
(*k)++ - incrementa o char apontado por k, ou seja, ‘A’ transforma-se em ‘B’.
*k++ - pela precedência de operadores, vale primeiro o que está à direita, depois á esquerda. Neste caso, esta expressão retorna ‘A’, mas o ponteiro, após a avaliação desta expressão, aponta para o caracter ‘Z’.
*(k++) - é exatamente a mesma coisa que *k++.

OK…Então minha função acima faz exatamente o que quero deixando “(*k)++”.

Obrigado. Esta manipulação de ponteiros me deu um nó. Vou estudar melhor este aspecto da linguagem. É que em Java, apesar de trabalharmos com referências o tempo todo, não conseguimos utilizar aritmética de ponteiros…Bom, você sabem disso :smiley:

Em particular, não gosto de usar essas coisas *k++. Eu prefiro separar em 2 linhas ou mais linhas, porque o código gerado é o mesmo.

Somos 2. Já se foi o tempo que funções como essa:

char *strcpy(char *dst, const char *src)
{
   char *ret = dst;
   while (*dst++ = *src++) ;
   return ret;
}

Precisavam ser tão rebuscadas.

Eu sempre fui a favor de código menos cheio de *p++ *q++ *p++ e outras coisas em C, desde que vi a saída de um código que o compilador gerou a partir de um programa C.
O Microsoft C 6.0 (16 bits) preferia que você usasse arrays em vez de ponteiros, e gerava código melhor para arrays, por incrível que pareça.
Hoje em dia isso nem é tão relevante assim - até porque hoje em dia é difícil escrever código em Assembly que seja muito melhor que o compilador costuma gerar.

Já programei muito em C. Uma das piores coisas para depurar em alguns casos são os tais ponteiros…
por isso tem que tomar muito cuidado e sempre programar seguindo padrões de codificação. Exemplo de um padrão: usar if(0==x) ao invés de if(x==0), pois se não digitar um dos iguais (=) será uma instrução inválida do C.

Att.

[quote=entanglement]Em particular, não gosto de usar essas coisas *k++. Eu prefiro separar em 2 linhas ou mais linhas, porque o código gerado é o mesmo.
[/quote]

Só não entendi muito bem como faria isso neste código acima, por exemplo. Acho que não capturei o espírito da coisa. Como seria a versão alternativa, orientado a “boas práticas de programação”, para o trecho acima.

Poderia dar um exemplo?

Somos 2. Já se foi o tempo que funções como essa:

char *strcpy(char *dst, const char *src)
{
   char *ret = dst;
   while (*dst++ = *src++) ;
   return ret;
}

Precisavam ser tão rebuscadas.[/quote]

Porque Vini?

Acho que isto é mais claro.
Pra começar, acho que aritmética com ponteiros não é uma coisa legal.
É melhor que você fique mais próximo da idéia (que é copiar um array no outro, certo?)

char *strcpy (char *dst, const char *src) {
     int i;
     for (i = 0; src[i] != '\0'; ++i) {
         dst[i] = src[i];
     }
     return dst;
}

Se olhar o código gerado (em modo de otimização do compilador, é claro!) vai ver que é exatamente equivalente àquele código esquisito que ensinam a gente a escrever nas aulas de C, e que torna a manutenção dos programas muito mais difícil.

Veja o tanto de coisa implícita que o cara tem que saber para entender o código que postei acima:

  1. Precedência de operadores. E não de quaisquer operadores, mas operadores sinistros como *, ++ e =
  2. Que a atribuição retorna valor;
  3. Que o while irá parar no último caracter da string, pois ele é o \0, e 0 é false;

Não é à toa que o código é um pequeno inferno.

Já o do entanglement, tudo isso fica claro. A comparação com \0 usa um operador de ==, atribuições são feitas com índices e não há dúvidas que operam sobre os valores.

a = b+++c; :slight_smile:

A pior coisa que já tive que mecher em C foi orientação a objetos, tudo usando ponteiros e tais… Mas apesar de tudo isso sempre que preciso de programas de alta performance, em que microsegundos importam, sempre recorro a C. Qualquer coisa coloca um JNI e pronto :smiley:

Att.

Orientação à objetos em C ou C++?

Orientação à objetos em C ou C++?[/quote]

Em C mesmo. É possível fazer, mas dá um trabalhão… principalmente para consertar os bugs… utilizei isto ao trabalhar em projetos em Linux.
para os interessados segue um link de um artigo sobre isso http://murilo.wordpress.com/2009/08/05/como-programar-em-c-orientado-a-objetos/

Att.

Sim, eu já sabia que dava para fazer. Só estava curioso se vc fez mesmo esse heroísmo. heheheheh

De qualquer forma, ainda acho mais fácil usar C++ nesses casos. Com os recursos de template e cuidado, você pode fazer código tão otimizado quanto em C.

Como posso ver o código Assembly gerado pelo compilador?

No GCC (Gnu C Compiler) deve ser usada a opção -S no momento da compilação, que será gerado o código em assembly. Em outros compiladores deve haver uma opção parecida para usar no momento da compilação.

Att.