Ponteiros em C

Você também pode gostar

Fazer download em pdf ou txt
Fazer download em pdf ou txt
Você está na página 1de 23

Ponteiros em C

Introdução ao Uso de Ponteiros na Linguagem C

Pedro Botelho
Engenharia de Computação (UFC)
Variáveis do Programa
● Conceito: Posição de memória de um certo tamanho que guarda um valor.
○ Obviamente pode ser modificada.
○ Caso contrário será uma constante.
● Variáveis comuns tem:
○ Endereço: Onde ela está localizada na memória (a posição da variável).
○ Tamanho: Quantos bytes ela ocupa.
○ Nome: Como identificá-la no programa.
○ Valor: O que está guardado nela.
○ Tipo: Como o valor guardado deve ser interpretado.
● Modificadores extras podem alterar a forma como a variável se comporta.
● O compilador trata de manejar os endereços do programa.
○ No nosso caso o gcc.
Pedro Botelho
Engenharia de Computação (UFC)
Variáveis do Programa
● Exemplo:

int i = 0;

● Sobre a variável:
○ Endereço: ?
○ Tamanho: 4 bytes.
○ Nome: i.
○ Valor: 0.
○ Tipo: Número Inteiro.
● Como obter o endereço da variável i?

Pedro Botelho
Engenharia de Computação (UFC)
Operador de Endereço (&)
● Podemos aplicar o operador & a uma variável para obter seu endereço.
● O endereço de i pode ser obtido usando &i.
● Geralmente usamos esse operador para passar parâmetros para funções.
● Exemplo:

int tamanho = 0;

scanf(“%d”, &tamanho);

● Como podemos guardar, e manejar, o endereço de uma variável?

Pedro Botelho
Engenharia de Computação (UFC)
Ponteiros
● Conceito: Variáveis que armazenam endereços.
○ Ao invés de armazenar um valor podem armazenar o endereço de outras variáveis.
● Usar um asterisco (*) na declaração: tipo *nome = endereço;
○ Tanto faz tipo* nome ou tipo *nome.
○ O tipo do ponteiro é o tipo do valor guardado no endereço.
● Exemplo:
int *ptr = &i;
● O ponteiro ptr guarda o endereço de i.
● Dizemos que um ponteiro aponta para uma outra variável.
○ Tipo do ponteiro e da variável deve ser o mesmo para poder usá-lo.
● Isso porque podemos acessar a variável a partir do ponteiro.
Pedro Botelho
Engenharia de Computação (UFC)
Ponteiros
● Comparação Variáveis Comuns V.s. Ponteiros: Dois pontos chave.
○ Variável: Valor é uma quantidade nomeada e o endereço é uma quantidade derivada.
○ Ponteiro: Endereço é uma quantidade nomeada e o valor é uma quantidade derivada.
● Exemplos:
int i = 0;
int *ptr = &i;
printf(“%d”, i); // imprime 0
printf(“%p”, ptr); // imprime um endereço
● Como podemos acessar o valor do endereço guardado no ponteiro?
Pedro Botelho
Engenharia de Computação (UFC)
Operador de Dereferenciação (*)
● O operador asterisco * fornece o valor guardado em um endereço:
● Sintaxe: valor = *(endereço)
● Exemplo: Interessante notar que:
● i e *ptr são iguais.
int i = 10; ● &i e ptr são iguais.

int *ptr = &i; // faz ptr igual a &i, não *ptr


printf(“%d”, *ptr); // imprime 10
● Não confundir com:
○ Asterisco da Declaração do Vetor: int* ptr (Tipo de Dado)
○ Asterisco da Multiplicação: a * b (Dois operandos).
○ O asterisco que retorna o valor de um endereço só tem um operando: *ptr

Pedro Botelho
Engenharia de Computação (UFC)
Inicialização de Ponteiros
● O tipo do ponteiro deve ser o mesmo da variável apontada.
● Por mais que o endereço de um tipo pareça o de outro, há duas diferenças:
○ Tamanho dos tipos é diferente.
○ Formatos internos para armazenamento de dados também são diferentes.
● Portanto:
○ char *caractere; // só pode apontar para um char.
○ int *contador; // só pode apontar para um int
○ double *resultado; // só pode apontar para um double
● Ou seja, inicializamos ponteiros para tipos específicos.
● Um ponteiro armazena um endereço, logo todos têm o mesmo tamanho.
○ No x86-32 e no ARM: o endereço contém 32-bits, ou 4 bytes.
○ No x86-64: o endereço contém 64-bits, ou 8 bytes.

Pedro Botelho
Engenharia de Computação (UFC)
Tamanho das Variáveis no x86-64:

Pedro Botelho
Engenharia de Computação (UFC)
Modificando variáveis por ponteiros Endereço Valor

1000
● Podemos acessar uma variável por meio de:
○ Seu nome; 1001
20 -> 30
○ Seu endereço; (valor)
1002
● Logo, podemos modificá-la usando um ponteiro
1003
que aponta para ela.
● Exemplo: 1004

1005
int valor = 20; 1000
1006 (ptr)
int *ptr = &valor;
1007
*ptr = 30;
Pedro Botelho
Engenharia de Computação (UFC)
Passagem de Parâmetro para Função
● Existem duas formas de passar parâmetros para funções:
○ Por valor: é passado uma cópia do valor da variável para a função.
■ Na função se tem acesso ao valor da variável, sendo somente uma cópia.
■ Se alterar o valor dentro da função não reflete na variável original.
■ Exemplo: Funções printf e pow.

int value2 = pow(value);


○ Por referência: é passado o endereço da variável para a função.
■ Dentro da função tem-se acesso ao endereço de uma variável externa.
■ O que é feito na função com o endereço reflete na variável original.
■ Logo, de dentro da função é possível modificar uma variável em outro lugar do código.
■ Exemplo: Funções scanf e strcpy.

strcpy(str1, str2);

Pedro Botelho
Engenharia de Computação (UFC)
Função swap e Ponteiros nos Argumentos
● Criar uma função que irá trocar duas variáveis de lugar.
● Trocar a e b: colocar o valor de b em a, e o de a em b.
● Como criar uma função que modifique os parâmetros?
● Ponteiros nos Argumentos: Função recebe endereços como parâmetros.
○ Dessa forma variáveis externas podem ser modificados dentro da função apenas por meio de seu endereço!
● Protótipo da Função: void swap(int *a, int *b);
○ A função swap recebe dois endereços, troca os valores de lugar, e retorna nada.
○ Porém, ao final da função, as variáveis terão seus valores trocados!

void swap(int *a, int *b) {


int temp = *a;
*a = *b;
*b = temp;
} Pedro Botelho
Engenharia de Computação (UFC)
Vetores
● Estrutura de Dados: Coleção de Dados.
○ Lista, Pilha, Fila, Árvore, etc…
● Estrutura de Dados Indexada: Acessar valores baseado em um índice.
○ Armazena uma determinada quantidade de valores do mesmo tipo.
○ Tem um tamanho máximo: Quantidade de elementos que consegue comportar.
● Manipular vários dados usando apenas um identificador.
● Localizar um Dado: Utilizar um inteiro chamado de “índice”.
○ Vai de 0 (primeira posição) até tamanho - 1.

Pedro Botelho
Engenharia de Computação (UFC)
Vetores
● Inicialização: Tipo nome_vetor[quantidade_dados];
○ Tipo refere-se ao tipo dos elementos do vetor.
● Exemplo: int array[8];

0 1 2 3 4 5 6 7

● Indexação inicia-se em 0 e vai até o tamanho do vetor (size) menos 1.


○ Tamanho do Vetor = Quantidade Máxima de Elementos = Número de Posições
● Apenas usar o nome do vetor referencia a primeira posição do vetor.
○ Ou seja, retorna seu endereço!
● Podemos inicializar o array com os elementos: int array[] = {1, 2, 3}, tamanho é 3.
● Argumento da Função: int sumArray(int array[]);
● Quantidade de Elementos Variável: int array[n];
Pedro Botelho
Engenharia de Computação (UFC)
Vetores
● Exemplo: Função para percorrer um vetor e somar seus elementos.

int sumArray(int array[], int n) {


int soma = 0;
for(int i = 0; i < n; i++) {
soma += array[i];
}
return soma;
}
Pedro Botelho
Engenharia de Computação (UFC)
Vetores e Ponteiros
● Vetores são na verdade ponteiros que apontam para o primeiro elemento.
○ Os dados dos vetores são guardados em endereços sequenciais.
○ É possível indexar todos os elementos a partir do primeiro.
○ Aritmética de Ponteiros: Somar um distanciamento i a um endereço irá retornar o elemento na
posição i.
● Forma de Indexação : *(array + i)
○ array representa o endereço.
○ array + i representa o endereço do elemento na posição i.
○ *(array + i) representa o valor do elemento na posição i.
● Exemplo: Com int array[n]:
○ Primeiro Elemento: *(array + 0)
○ Segundo Elemento: *(array + 1)
○ Último Elemento: *(array + n - 1)
● Argumentos de uma Função: int sumArray(int *array);
○ As notações array[i] e *(array + i) são equivalentes.
○ A inicialização sempre é a mesma: int array[tamanho].
Pedro Botelho
Engenharia de Computação (UFC)
Strings
● Sequência de caracteres, logo, um vetor de chars.
○ O C não tem um tipo string: Usamos um vetor de caracteres terminado pelo caractere ‘\0’.
○ Portanto, é definido como um vetor de char na forma char string[tamanho] = “conteudo”.
○ O conteúdo deve ficar entre aspas duplas.
○ O compilador colocará um caractere ‘\0’ ao final automaticamente de todas as strings.
○ Exemplo: printf(“Hello World”), a string será refatorada para “Hello World\0”.
○ Cada char tem um byte.
● Para não confundir:
○ Caractere: char caractere = ‘A’, entre aspas simples.
○ String: char string[12] = “Hello World”, entre aspas duplas (11 letras e 1 do \0).
○ Se criar um char caractere02[] = “A” teremos uma string na forma “A\0”, de dois bytes.

Pedro Botelho
Engenharia de Computação (UFC)
Strings
● Inicializando Strings: Assim como vetores.
○ Inicialização por Lista: char str[3] = {‘O’, ‘i’, ‘\0’};
○ char str[3] = “Oi”;
○ char str[] = “Oi”;
○ char str[1024] = “Oi”;
○ Se tentar adicionar caracteres ao final de uma string que não tenha espaço sobrando haverá
erro.
● Indexando Caracteres: Semelhante a vetores:
○ str[i] retorna o caractere na posição i.
○ str retorna o endereço do primeiro caractere.
○ str[3] = ‘X’ muda o caractere da posição 3.

Pedro Botelho
Engenharia de Computação (UFC)
Adicionar Caractere ao Final da String
● Primeiramente deve-se ter certeza que a string tem espaço sobrante.
● Algorítmo:
○ Descobrir onde é o final da string, isto é, achar o \0 (sua posição i).
○ Colocar o novo caractere nessa posição.
○ Escrever o ‘\0’ na posição seguinte.

void append(char *str, char new_char) {


int i = 0;
while(str[i] != ‘\0’) i++;
str[i] = new_char;
str[i + 1] = ‘\0’;
} Pedro Botelho
Engenharia de Computação (UFC)
Funções de Manipulação de Strings
● Para mandar a string para funções: Enviar uma referência para o primeiro
elemento.
○ Assim como com vetores: Só usar o nome da string (referencia o primeiro elemento).
● char *gets(char *str): Obtém uma string do teclado, coloca em str e retorna
um ponteiro para str.
● void puts(char *str): Imprime a str no terminal.
● void scanf(const char *format, …): Obtém entradas do usuário de acordo
com os formatos da string de formatação.
● void printf(const char *format, …): Imprime os parâmetros no terminal de
acordo com a string de formatação.

Pedro Botelho
Engenharia de Computação (UFC)
Funções de Manipulação de Strings
● void strcpy(char *str1, char *str2): Copia o conteúdo de str2 para str1.
● int strcmp(char *str1, char *str2): Compara str1 com str2 e retorna:
○ 1 se str1 é “maior” que str2.
○ -1 se str2 é “maior” que str1.
○ 0 se forem iguais.
● void strcat(char *str1, char *str2): Concatena str2 em str1.
● int strlen(char *str): Retorna o tamanho da string.

Pedro Botelho
Engenharia de Computação (UFC)
Ponteiros Nulos
● Deve-se tomar cuidado ao criar e referenciar ponteiros:
○ Ao inicializar um ponteiro temos um espaço para guardar um endereço.

int *ptr; // espaço para guardar um endereço


○ Se não colocarmos um endereço no ponteiro e usarmos o operador *, o que acontecerá?

*ptr = 10; // onde o 10 será colocado?


● Devemos atribuir ao ponteiro um endereço antes de usar o operador *.
● Inicializamos os ponteiros com NULL caso ainda não tenham um endereço.
○ Indica que o ponteiro não está apontando para um valor na memória.

int *ptr = NULL;


Pedro Botelho
Engenharia de Computação (UFC)
Ponteiros Nulos
● Devemos:
○ Inicializar os ponteiros que não tem endereço inicial atribuído com NULL.
○ Verificar se o ponteiro é nulo antes de usar o operador * (identificado pelo nome do ponteiro)
● Muitas funções retornam NULL para indicar que não foi possível retornar um endereço.
● Exemplo:

int *array = NULL;

obterValores(array);

if(array != NULL) {

printf(“Resultado: %d”, somaArray(array));

Pedro Botelho
Engenharia de Computação (UFC)

Você também pode gostar