Vou partir do princípio que todos sabem um pouco de linguagem C/C++ e que compreendem a forma de criação e utilização de funções. Também vou tentar escrever o mínimo possível e passar a ideia através de quatro exemplos muito simples, sempre à volta da clássica função troca.
Função Troca: recebe dois valores a e b, e troca os respectivos conteúdos.
Passagem de parâmetros por valor: A função recebe uma cópia da variável que é fornecida quando é invocada. Todas as alterações feitas dentro da função não vão afectar os valores originais.
Passagem de parâmetros por referência: Neste caso o que é enviado para a função é uma referência às variáveis utilizadas, e não uma simples cópia, pelo que as alterações realizadas dentro da função irão certamente alterar os valores contidos nessas variáveis.
Exemplo 1 – Passagem de parâmetros por valor – Linguagem C
#include<stdio.h>
void troca(int a, int b){
int temp;
temp=a;
a=b;
b=temp;
}
int main(){
int a=2,b=3;
printf("Antes de chamar a função :\na=%d\nb=%d\n",a,b);
troca(a,b);
printf("Depois de chamar a função:\na=%d\nb=%d\n",a,b);
return 0;
}
Apesar da troca dentro da função, os valores originais não sofreram alterações.
Exemplo 2 – Passagem de parâmetros por referência – Linguagem C
Contradizendo o título, em C só existe a passagem de parâmetros por valor (obrigatório o uso de apontadores).
#include<stdio.h>
void troca(int *a, int *b){
int temp;
temp=*a;
*a=*b;
*b=temp;
}
int main(){
int a=2,b=3;
printf("Antes de chamar a função :\na=%d\nb=%d\n",a,b);
troca(&a,&b);
printf("Depois de chamar a função:\na=%d\nb=%d\n",a,b);
return 0;
}
A troca dentro da função reflecte-se nos valores originais.
Exemplo 3 – Passagem de parâmetros por valor – Linguagem C++
#include<iostream>
using namespace std;
void troca(int a, int b){
int temp;
temp=a;
a=b;
b=temp;
}
int main(){
int a=2,b=3;
cout<<"Antes de chamar a função :\na="<<a<<"\nb="<<b<<endl;
troca(a,b);
cout<<"Depois de chamar a função :\na="<<a<<"\nb="<<b<<endl;
return 0;
}
Situação semelhante à apresentada no exemplo 1.
Exemplo 4 – Passagem de parâmetros por referência – Linguagem C++
#include<iostream>
using namespace std;
void troca(int &a, int &b){
int temp;
temp=a;
a=b;
b=temp;
}
int main(){
int a=2,b=3;
cout<<"Antes de chamar a função :\na="<<a<<"\nb="<<b<<endl;
troca(a,b);
cout<<"Depois de chamar a função :\na="<<a<<"\nb="<<b<<endl;
return 0;
}
Como se pode verificar, a evolução da linguagem C para C++ veio simplificar algumas tarefas:)
Pressupostos: Conhecimentos elementares de programação em Linguagem C/C++ e do conceito de variável.
Objectivo: Compreender o conceito de apontador.
A ideia por detrás do conceito de apontador é muito simples, e assenta no facto de todas as variáveis serem armazenadas na memória RAM do computador, tendo obrigatoriamente que ficar associadas a um endereço de memória.
Quando num programa utilizamos a instrução int x=33; estamos a indicar ao compilador para reservar um espaço na memória para poder armazenar valores do tipo inteiro, com o número de bits associado a este para cada compilador e/ou arquitectura. Simultaneamente é atribuído o valor 33 à variável x, o que significa que no endereço de memória associado à variável x é armazenado o valor 33.
Daqui em diante sempre que pretendermos utilizar ou alterar o valor armazenado neste endereço de memória bastará utilizar uma referência ao nome da variável ( x ) para o efeito.
No exemplo apresentado ( int x=33; ) diz-se que foi realizada uma declaração seguida da inicialização (Inicialização automática).
Em termos gráficos, fica representado na figura seguinte o que se passa ao nível da memória do computador:
|
|
x |
|
|
< – Nome da variável |
|
|
33 |
|
|
< – Conteúdo |
|
100 |
101 |
102 |
103 |
< – Endereço de memória |
Notar que foi utilizado o endereço de memória 101(endereço fictício) para armazenar o valor 33. Isto significa apenas que a representação binária do número 33 é armazenada a partir do endereço 101 e ocupa um número de bits correspondente ao tipo de dados declarado.
Depois de chegados a este ponto podemos avançar para o conceito de apontador.
Um apontador é uma variável como qualquer outra, mas que é utilizada para armazenar o endereço de memória de outra variável.
A imagem seguinte representa a evolução do caso acima apresentado, acrescido da utilização de um apontador “ptr” que irá ser utilizado para manipular o conteúdo do endereço de memória onde se encontra armazenado o valor de x:
|
|
x |
|
ptr |
< – Nome da variável |
|
|
33 |
|
101 |
< – Conteúdo |
|
100 |
101 |
102 |
103 |
< – Endereço de memória |
Acabamos de criar uma variável nova, mas agora trata-se de um apontador:
Conclusão: ptr é um apontador para a variável x.
Vamos avançar com um exemplo com valores reais:
#include<iostream>
#include<iomanip>
using namespace std;
int main(){
int x=33;
int *ptr_x=&x;
cout << "-- Estado inicial ---------------------------------------\n";
cout << "\tValor armazenado na variável x : " << x << endl;
cout << "\tEndereço de memória da variável x : " << &x << endl;
cout << "\tValor armazenado na variável ptr_x : " << ptr_x << endl;
cout << "\tEndereço de memória da variável ptr_x: " << &ptr_x << endl;
cout << "-- Ler um novo valor para x ------------------------------\n";
cout << "x = "; cin >> x;
cout << "\tValor armazenado na variável x : " << x << endl;
cout << "\tEndereço de memória da variável x : " << &x << endl;
cout << "\tValor armazenado na variável ptr_x : " << ptr_x << endl;
cout << "\tEndereço de memória da variável ptr_x: " << &ptr_x << endl;
return 0;
}
Comentários linha-a-linha: Apenas me vou referir ao que interessa abordar sobre este assunto.
Linha 5: Como já referi, esta linha de código faz a inicialização automática da variável x, do tipo inteiro, com o valor inicial 33.
Linha 6: Para compreender o que se passa nesta linha é necessário conhecer os operadores unários * e & .
De forma simplista temos:
Foi então criado um apontador ptr. cujo conteúdo foi automaticamente inicializado com o valor correspondente ao endereço de memória da variável x.
Note-se que a posição do caracter * pode ser feita de outras formas, tal como demonstrado a seguir, mas a primeira é a mais utilizada.
int *ptr; int* ptr; int * ptr;
Restantes linhas: Servem apenas para ir mostrando o que se passa com estas variáveis no decorrer da execução deste pequeno programa.
Nota final: Espero ter conseguido passa a mensagem sobre o que são os apontadores, mas termino recordando que este é uma assunto muito vasto e que muito fica por dizer, mas sem se compreender bem o que aqui foi dito não adianta muito avançar.
Antes de tudo é preciso assumir que estamos perante uma pergunta que nos conduz inevitavelmente a uma área de alguma complexidade.
Quando me surgiu esta ideia acabei neste endereço ( http://beej.us/guide/bgnet/output/html/multipage/index.html ), onde de facto está tudo muito claro. Parabéns ao autor Brian “Beej Jorgensen” Hall.
Mas imagine que, sem querer atravessar todo o processo de estudo de comunicação de dados em linguagem C, pretende escrever um programa que necessita de trocar pequenas quantidades de informação sem grandes preocupações de segurança?
Proponho um exemplo: “O Jogo do Galo”!
Numa análise simplista, para implementar este jogo em rede basta conseguir trocar dados do tipo “char” que representem as várias situações: ‘x’ para as cruzes; ‘o’ para as bolas; ‘ ‘ para uma célula vazia; e todos os outros caracteres para associar às várias situações de controlo que necessitem.
Sem explorar os aspectos básicos associados à implementação deste jogo, deixo aqui um pequeno programa de exemplo, onde implementei duas funções que tornam possível a comunicação entre dois “hosts” na vossa rede, bastando paro o efeito conhecer o endereço ip que lhes está atribuído.
A função “enviar” faz justiça ao nome escolhido, pois simplesmente lança no meio de transmissão um sinal dirigido ao “ip_receptor” contendo um caracter. O receptor faz com o caracter o que lhe apetecer!
A função “receber” ausculta o meio de transmissão até lhe ser enviado um caracter.
A função “main” é “paisagem”, pois apenas serve para exemplificar a utilização destas duas funções.
Download do código fonte: aqui (Box: sourcecode0004.cpp)
Basta mudarem os endereços ip para o vosso caso e já estão a trocar caracteres.
Espero que isto vos seja útil e fico à espera desse “Jogo do Galo – Versão rede :)”
Desde que iniciei este blog andava com uma dificuldade que já me estava a irritar.
Apesar de ser defensor de que o código fonte em qualquer Linguagem de Programação deve ser fiel a um estilo definido por cada programador e escolhido de forma a ser o mais universal possível e evidenciar as várias estruturas nele utilizadas, não estava a conseguir este efeito no WordPress.
Agora de repente encontrei uma forma simples de o fazer e vou aqui partilhá-la.
Basta colarem o vosso código entre as tags:
[sourcecode language='css']…[/sourcecode].
O efeito é este:#include <QApplication> #include <QLabel> int main(int argc, char *argv[]){ QApplication app(argc, argv); QLabel *texto = new QLabel("Bom dia QT!"); texto->show(); return app.exec(); }Giro não é?
Fonte: http://faq.wordpress.com/2007/09/03/how-do-i-post-source-code/