C++ - Ponteiros (continuação) Dimensionando matrizes em tempo de execução : Exemplo #include <iostream.h>
void main( ) {
int tamanho;
int *notas; // ponteiro para inteiro cout << “\nQuantas notas? “; cin >> tamanho;
notas = new int[tamanho]; //aloca memória for(int i=0; i<tamanho; i++) // entrada de dados { cout << “\nDigite a nota do aluno “ << (i+1) << “: “;
cin >> *(notas + i); } int m = media (notas, tamanho);
cout << “\n\nMedia das notas : “ << m;
delete [ ] notas; // libera memória }
Matrizes multidimensionais : somente a primeira dimensão pode ser definida em tempo de execução, as outras devem ser constantes.
int (*notas)[3]; ...
delete [ ] notas;
Ponteiros para objetos : Uso do new para criar objetos em tempo de execução. Exemplo utilizando a classe Venda.
void main( ) {
Venda A; // declara objeto
A.getvenda( ); // acesso aos membros através do operador ponto A.printvenda( );
Venda *B; // declara ponteiro para objeto B = new Venda // aloca memória
B->getvenda( ); // acesso aos membros através do operador Seta B->printvenda( );
}
(*B).getvenda( ); (pouco usado)
O operador de acesso a membros (->) conecta um ponteiro para um objeto a um membro dele, enquanto o operador ponto (.) conecta o nome de um objeto a um membro dele.
Usando referências : Podemos criar uma referência a um objeto definido pelo operador new. Exemplo
void main( ) {
Venda& A = *(new Venda);
A.getvenda( ); // acesso através do operador ponto A.printvenda( );
}
Criando uma lista ligada : Lista ligada assemelha-se a uma corrente em que os registros de dados estão pendurados sequencialmente. O espaço de memória é obtido pelo operador new, conforme surge a necessidade de adicionar itens à lista. Cada registro é conectado ao anterior por meio de um ponteiro. O primeiro registro contém um ponteiro com o valor NULL, e cada registro sucessor contém um ponteiro para o anterior.
Ex.: Lista de livros #include <iostream.h> #include <conio.h> #include <stdio.h> struct Livro { char titulo[30]; char autor[30]; int numreg; double preco;
Livro *anterior; // ponteiro para a estrutura Livro } ;
class ListaLigada {
Livro *fim; public :
ListaLigada() {fim = (Livro *)NULL;} // lista vazia void novonome();
void print(); } ;
void ListaLigada::novonome() {
Livro *novolivro = new Livro; // aloca memória
cout << "\nDigite Titulo : "; gets(novolivro->titulo); //entra valores cout << "\nDigite Autor : "; gets(novolivro->autor);
cout << "\nDigite o Numero do Registro : "; cin >> novolivro->numreg; cout << "\nDigite o Preco : "; cin >> novolivro->preco;
novolivro->anterior = fim; // encadeia (une os elos) fim = novolivro; // atualiza ponteiro fim }
void ListaLigada::print() {
Livro *atual = fim; // inicializa ponteiro de percurso while (atual != NULL) // enquanto tiver elos ... {
cout << "\n\nTitulo : " << atual->titulo; // imprime campos cout << "\nAutor : " << atual->autor;
cout << "\nNo.Reg. : " << atual->numreg; cout << "\nPreco : " << atual->preco;
atual = atual->anterior; // anda com ponteiro } } void main( ) { ListaLigada li; char opcao;
do // entra com dados { li.novonome();
}while(opcao == 's');
cout << "\nLista dos Livros cadastrados";
cout << "\n*********************************"; li.print(); // imprime a lista
}
Ponteiro para ponteiros : Alteração do programa que ordena uma matriz de strings, criando uma matriz de ponteiros para objetos e ordenando estes ponteiros baseado nos dados contidos nos objetos.
#include <iostream.h> # include <string.h> #include <stdio.h>
enum Boolean { False, True }; class String { private : char *str; public : int getname( ) { char nome [100]; gets(nome);
str = new char [ strlen(nome) +1]; strcpy(str, nome);
return strcmp(str, “”); }
Boolean operator > (String s)
{ return (strcmp(str, s.str)>0) ? True : False; } void print( ) { cout << str; }
} ;
void ordena(String **p, int n); void main( )
String *p[100]; int n; // vetor de ponteiros para String for ( n=0; ; n++)
{ cout << "\nDigite nome ou <ENTER> para encerrar : "; p[n] = new String; // aloca memória if(p[n]->getname() == 0) break; } // entra com dados cout << "\nLista original : "; // imprime lista original for(int i=0; i<n; i++)
{ cout << "\n"; p[i]->print();} // acesso à função membro ordena(p,n); // ordena os ponteiros cout << "\nLista ordenada : "; // imprime a lista ordenada for (int i=0; i<n; i++)
{ cout << "\n"; p[i]->print();} }
void ordena (String **p, int n) // **p - ponteiro para ponteiro {
String *temp;
for (int i=0; i<n; i++) {
for (int j=i+1; j<n; j++)
if( *(*(p+i)) > *(*(p+j)) ) // compara conteúdo (objeto) {
temp = *(p+i); // troca os ponteiros *(p+i) = *(p+j);
*(p+j) = temp; }
} }
Observ. : p[i] é equivalente a *(p+i) (endereço do objeto String) *p[i] é equivalente a *(*(p+i)) (conteúdo do objeto String) Argumentos da linha de comando : Os argumentos digitados na linha de comando são enviados como argumentos da função main( ) :
void main ( int argc, char ** argv) onde:
**argv é uma matriz de ponteiros para strings, onde cada string representa um dos argumentos da linha de comando. Estes podem ser acessados por meio da notação de matriz argv[0], argv[1], etc ou por meio da notação ponteiro *(argv+0), *(argv+1), etc.
Exemplo :
#include <iostream.h>
void main( int argc, char **argv) {
cout << “ \nNumero de argumentos : “ << argc; for (int i=0; i<argc; i++)
cout << “ \nArgumento num. “ << i << “ : “ << argv[i]; }
Supondo que o arquivo com o programa chame-se TESTE.CPP, um exemplo de execução seria :
C:\ Teste Bom dia
resultado : Numero de argumentos : 3
Argumento num. 0 : C:\TESTE.EXE Argumento num. 1 : Bom
Argumento num. 2 : dia
Note que argv[0] é sempre o nome do programa sendo executado e o seu caminho de localização no disco.
Ponteiros para funções : Uma função pode ser executada por meio de ponteiro. Por exemplo:
#include <iostream.h>
void doisbeep(void); // protótipo da função void main( )
{
void (*pf)(void); /* declara ponteiro para função do tipo void, sem argumentos */ pf = doisbeep /* (sem parênteses) atribui o endereço da função doisbeep( ) à pf */ (*pf) ( ); // chama a função através do ponteiro
}
void doisbeep( void) {
cout << ‘\x07’; // soa o beep for (inti=0; i<500; i++); // dá um tempo
cout << ‘\x07’; // soa o beep novamente }
Observ. : Em void (*pf) (void); os parênteses são necessários. void *pf ( void);
será interpretado como o protótipo de uma função que retorna um ponteiro void. pf = doisbeep; // sem parênteses
o nome de uma função desacompanhado de parênteses é o seu endereço. pf = doisbeep( ) // com parênteses
atribui a pf o valor de retorno da função, não o seu endereço. (*pf) ( ); é equivalente a doisbeep( );
e indica uma chamada à função.
Ponteiros para funções como argumentos : Veja o protótipo: void func ( char * (*p) (char*) );
e o significado: (*p) - ponteiro para função
(char *) - tipo do argumento da função
char * - valor de retorno da função
Matrizes de ponteiros para funções : Os ponteiros para funções oferecem uma maneira eficiente de executar uma entre uma série de funções, com base em alguma escolha dependente de parâmetros conhecidos somente em tempo de execução.
Exemplo: programa com menu de opções ao usuário #include <iostream.h>
void func0(void), func1(void), func2(void); // protótipos void main( )
{
void (*ptf[3]) (void) = { func0, func1, func2 }; /* declara e inicializa uma matriz de ponteiros para funções do tipo void, sem argumentos */
do
{ int i;
cout << “ \n0 - Abrir “; cout << “ \n1 - Fechar “; cout << “ \n2 - Salvar “;
cout << “ \n\nEscolha um item : “; cin >> i;
if( i<0 || i>2) break;
(*ptf[i] ) ( ) ; // chama função i } while (TRUE);
}
void func0( )
{ cout << “ \n\n*** Estou em func0( ) *** “; } void func1( )
{ cout << “ \n\n*** Estou em func1( ) *** “; } void func2( )
{ cout << “ \n\n*** Estou em func2( ) *** “; } Exercícios
1) Qual o significado da palavra void em cada uma das seguintes instruções:
a) void *p; b) void p( ); c) void p(void); d) void (*p) ( );
2) Se p é um ponteiro para um objeto da classe data, então quais das seguintes instruções executam a função-membro printdata( )
a ) p.printdata( ) b) *p.printdata( ) c) p->printdata( ) d) *p->printdata( )
3) Se p é uma matriz de ponteiros para objetos da classe data, escreva uma
instrução que execute a função-membro printdata() do objeto apontado pelo terceiro elemento de p.
4) Assumindo a declaração:
Para poder escrever a instrução p = itens; a variável p deve ser declarada como:
a ) char p; b) char *p; c) char **p; d) char ***p;
5) O que declara cada uma das seguintes instruções:
a ) int (*ptr)[10] b) int *ptr[10]; c) int (*ptr)(); d) int *ptr(); e) int (*ptr[10])();
Prática XI