Tabela de conteúdos
Ponteiros
Conceitos
A Linguagem C implementa o conceito de ponteiro. Um ponteiro é um tipo de dado como int, char ou float. A diferença do ponteiro em relação aos outros tipos de dados é que uma variável que seja ponteiro irá guardar um endereço de memória
.
Através deste endereço pode-se acessar a informação, dizendo que a variável ponteiro aponta
para uma posição de memória. O maior problema em relação ao ponteiro é entender que quando se está trabalhando com o seu valor (endereço de memória) e quando se está trabalhando com a informação apontada por ele (conteúdo).
Por ser um endereço deve-se especificar que tipo de variável será encontrado na posição apontada pelo ponteiro. Assim é informado que foi criado um ponteiro para um inteiro (no endereço indicado pelo ponteiro será encontrado um valor inteiro e o compilador deve gerar código para tratar este endereço). Ponteiros podem ser utilizados para uma estrutura ou um ponteiro para um arquivo.
Definição de Ponteiros
Sintaxe:
Para se definir uma variável do tipo ponteiro, deve-se colocar um asterisco (*
) na frente de uma definição normal daquele tipo. O asterisco
deve ser colocado entre o tipo e o nome da variável.
A definição de um ponteiro é somente a definição de um espaço de memória que conterá outro endereço. Portanto ao definir um ponteiro somente é alocado o espaço do endereço e não do valor. Para utilizar um ponteiro, é preciso sempre inicializar o mesmo, ou seja, colocar um endereço válido para depois realizar o acesso.
Veja o exemplo:
int main (void) { int *piInteiro; /*ponteiro para inteiro */ char *pcCaractere; /*ponteiro para um caractere */ float *pfPontoFlutuante; /*ponteiro para um ponto flutuante */ return 0; }
Uso de Ponteiros
Um ponteiro pode ser utilizado de duas maneiras distintas. Uma maneira é trabalhar com o endereço armazenado no ponteiro e outro modo é trabalhar com a área de memória apontada pelo ponteiro. É importantíssimo diferenciar estes dois modos para não causar problemas.
Quando se quiser trabalhar com o endereço armazenado no ponteiro, utiliza-se o seu nome sem o asterisco na frente. Sendo assim qualquer operação realizada será feita no endereço do ponteiro.
Na maioria dos casos, se deseja trabalhar com a memória apontada pelo ponteiro, alterando ou acessando este valor. Para isto deve-se colocar um asterisco antes do nome do ponteiro. Quando isto for feito o compilador irá gerar o código para acessar a memória apontada e não com o valor do endereço.
/* programa_ponteiro01.c */ #include <stdio.h> int main(void) { int * piA; /* ponteiro para inteiro */ int iVariavel; iVariavel = 10; piA = &iVariavel; /* O ponteiro piA recebe o endereço de memória da variável iVariavel */ printf("\nEndereço: %d", piA); printf("\nValor : %d", *piA); *piA = 1975; /* Indica que endereço de memória, representado pelo ponteiro, irá receber o valor 1975 */ printf("\nValor alterado: %d", iVariavel); printf("\nValor : %d", *piA); return 0; }
Parâmetros de Saída
Para fazer a saída de valores via parâmetros de função, deve-se definir este parâmetro como sendo do tipo ponteiro. Na chamada da função deve-se colocar o endereço de uma variável local ou global neste parâmetro. Para retornar um valor deve-se portanto utilizar o asterisco antes do nome do parâmetro, indicando assim que esta sendo mudando o valor naquele endereço passado como parâmetro.
/* programa_ponteiro02.c */ #include <stdio.h> /* Indica que o último parâmetro é um ponteiro para inteiro. */ void soma (int iValorA, int iValorB, int *piValor) { *piValor = iValorA + iValorB; return; } int main(void) { int iValor_a, iValor_b, iResultado; printf("\nEntre com os valores:"); scanf("%d %d", &iValor_a, &iValor_b); /* Como está sendo passado o endereço de memória da variável (ponteiro), qualquer alteração será realizada na memória. */ soma(iValor_a, iValor_b, &iResultado); printf ("Soma : %d\n", iResultado); return 0; }
Exemplo trocando 2 valores:
/* programa_ponteiro03.c */ #include <stdio.h> void troca(int * piValor_a, int * piValor_b) { int iAux; iAux = *piValor_a; *piValor_a = *piValor_b; *piValor_b = iAux; return; } int main(void) { int iValor_a, iValor_b; iValor_a = 10; iValor_b = 20; troca(&iValor_a, &iValor_b); printf("\nValor a = %d", iValor_a); printf("\nValor b = %d", iValor_b); return 0; }
Operações com Ponteiros
Pode-se realizar as operações de soma e subtração do valor do ponteiro, ou seja, do endereço armazenado na variável.
Um detalhe a ser observado é que esta soma estará condicionada ao tamanho do tipo que o ponteiro aponta. Suponha que exista um ponteiro para um inteiro, que ocupa 4 bytes na memória. Ao se somar uma unidade neste ponteiro (+ 1) o compilador interpretará que se deseja que some um valor que permita acessar o próximo inteiro e irá gerar código para somar 4 unidades no endereço do ponteiro.
/* programa_ponteiro04.c */ #include <stdio.h> int main(void) { int *piInt; int iValor; char *pcChar; char cValor; piInt = &iValor; pcChar = &cValor; printf("Endereco de piInt = %d\n", piInt); printf("Endereco de pcChar = %d\n", pcChar); piInt++; pcChar++; printf("Endereco de piInt = %d\n", piInt); printf("Endereco de pcChar = %d\n", pcChar); return 0; }
Ponteiros e Matrizes
Quando é passado um vetor ou matriz como parâmetro, a Linguagem C coloca o endereço na pilha. Pode-se então definir o tipo do parâmetro como um ponteiro e acessar a matriz dentro da função como se fosse um ponteiro.
/* programa_ponteiro05.c */ #include <stdio.h> void imprime(int * piVet) { int i; for (i=0; i < 5; i++) { /* Seria o equivalente: imprima vet[i]; i++ */ printf("\nConteudo na matriz na posicao %d=%d",i, *piVet); printf("\nEndereço de memória = %d", piVet ); piVet++; } printf ("\n"); return; } int main(void) { int matriz[5] = {1, 2, 3, 4, 5}; printf("\nTamanho da matriz = [%d]", sizeof(matriz)); imprime(matriz); return 0; }
Ponteiros e Strings
Acessar um vetor como ponteiro e vice-versa é muito comum quando é utilizado strings. Quando é definido um vetor de caracteres, pode-se acessar o mesmo através de um ponteiro para caractere. Este ponteiro estará sempre apontando para um único caractere da string e através de operações sobre o ponteiro (incremento ou decremento) pode-se caminhar no vetor.
/* programa_ponteiro06.c */ #include <stdio.h> int main(void) { char sNome[30] = "Marcos Aurelio"; char *pcCaracter; /* Aponta para o primeiro caractere da string ou vetor. */ pcCaracter = (char *) &sNome; /* Pegando o tamanho da variável na memória e não o tamanho da matriz. */ printf("\nTamanho da string = %d", sizeof(sNome)); printf("\nEndereço da 1a. posicao = %d\n", pcCaracter ); while (*pcCaracter != NULL) { putchar(*pcCaracter); /* Seria o equivalente: */ pcCaracter++; /* imprima sNome[i]; i++; */ } putchar ('\n'); printf("\nEndereço da última posicao = %d", pcCaracter ); return 0; }
Argumentos de Entrada
De dentro de um programa C pode-se acessar a linha de comando que ativou o programa, permitindo assim passar valores para o programa na sua chamada.
Os valores passados para o programa são chamados de argumentos e pode-se acessá-los colocando-se dois parâmetros na definição da função main. O primeiro parâmetro deve ser do tipo inteiro e conterá a quantidade de argumentos passados na linha de comando. É importante observar que o nome do programa é um argumento e portanto será contado como tal. Posto isto, vale dizer que sempre este parâmetro irá considerar o nome do programa como argumento.
O outro parâmetro que deve ser colocado é um vetor de ponteiros. Cada ocorrência deste vetor será um ponteiro para uma string contendo o argumento passado para o programa.
/* programa_ponteiro07.c */ #include <stdio.h> /* argc - Contém o número de argumentos passados. Será sempre pelo menos 1, pois o nome do programa é sempre passado como 1º argumento. argv - Conterá os argumentos passados. Os argumentos são separados por um espaço em branco ao ser passado na linha de comando. */ int main (int argc, char *argv[]) { int i; printf ("Argumentos digitados\n"); for (i=0; i < argc; i++) { printf ("Argumento %d - %s\n", i + 1, argv[i]); } return 0; }
Lista de funções
— Marcos Laureano 2009/05/11 18:46