













Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Curso completo de linguagem de programação em C da Uninter
Tipologia: Notas de aula
1 / 21
Esta página não é visível na pré-visualização
Não perca as partes importantes!














Esta aula tem como base os livros Fundamentos da Programação de Computadores: Algoritmos , Pascal , C/C++ e Treinamento em Linguagem C. Em caso de dúvidas ou para aprofundamento, consulte-os em nossa Biblioteca Virtual Pearson. A aula apresenta a seguinte estrutura de conteúdo:
A memória de um computador é dividida em bytes , numerados de zero até o limite de memória da máquina. Esses números são chamados endereços de bytes , usados como referências, pelo computador, para localizar as variáveis (Mizrahi, 2008). Toda variável tem uma localização na memória, e o endereço de identificação desta variável é o primeiro byte ocupado por ela, conforme explicado anteriormente. Se o programa contém a informação somente do endereço do primeiro byte da variável, como ele sabe quais endereços deve ler? Bom, para obter esta resposta, o programa deve saber que toda variável está armazenada em bytes sequenciais e, identificando o tamanho desta variável pelo seu tipo, infere até onde a leitura dos endereços deve ir. Por exemplo, uma variável do tipo int em C com tamanho 4 bytes, ou seja, sabendo o endereço inicial, sabe que, a partir, dele temos mais três endereços sequenciais que correspondem à variável desejada. Quando o programa é carregado na memória, ocupa certa quantidade de bytes , e toda variável e função desse programa terão seu espaço e endereço
operador “ ***** ” antes da variável e o operador “ & ”^1 na chamada do parâmetro (Mizrahi, 2008). O resultado do operador &, "endereço de", sempre será o endereço de memória do elemento em questão, normalmente é o local onde uma variável está alocada na memória. Isto é, esse operador gera um ponteiro. A função scanf() espera que o usuário digite algum dado de entrada e o operador ‘ & ’, acompanhado da variável, serve para especificar o lugar certo onde esse dado vai ficar posicionado na memória. Portanto, o uso do operador de endereço para essa função se faz necessário (Ascencio, 2012). O operador oposto é o * (asterisco), que pega o valor apontado pelo endereço. No exemplo do algoritmo da Figura 1, foram declaradas três variáveis inteiras. Obtivemos como saída a impressão dos seus endereços em hexadecimal com o uso do operador &. O endereço alocado depende de vários fatores, dentre eles, o tamanho da palavra^2 , se há ou não outros programas usando a memória, entre outros. Por essas razões, podemos encontrar endereços diferentes na passagem de parâmetros e execução do algoritmo (Mizrahi, 2008) para cada nova execução de um problema. Faça o teste você mesmo. Implemente o exemplo anterior no seu compilador e mande-o executar diversas vezes. Cada nova execução gerará valores diferentes de endereços alocados. Mizrahi (2008) descreve memória como uma unidade organizada logicamente em palavras. Uma palavra é uma unidade lógica de informação constituída por um número de bits de único endereço, consequentemente, um conjunto de palavras armazenadas na memória é um programa, e pode ser dividido em duas categorias: Instruções – operações (programa propriamente dito) realizadas pela máquina; Dados – variáveis, ou valores, processadas nessas operações. Cada palavra é identificada por meio de um endereço de memória sem ambiguidade. Observe a Tabela 1. (^1) O operador unário & retorna o endereço na memória de seu operando (Mizrahi, 2008). (^2) Unidade de informação para cada tipo de computador (Mizrahi, 2008).
Tabela 1 – Exemplo de endereços de palavras Ordem na memória Endereço na memória Palavras 0 000 Palavra 0 1 001 Palavra 1 2 010 Palavra 2 3 011 Palavra 3 4 100 Palavra 4 5 101 Palavra 5 6 110 Palavra 6 7 111 Palavra 7 A capacidade, ou tamanho, de uma memória vai depender do número de palavras que ela pode suportar. A posição de uma palavra dentro da memória é tida como o seu endereço. A primeira palavra da memória tem o endereço 000, a próxima, 001, e assim por diante (Mizrahi, 2008).
O ponteiro é uma ferramenta poderosa oferecida em linguagens de programação e considerada, pela maioria dos programadores, um dos tópicos mais difíceis (Mizrahi, 2008; Ascencio, 2012). Apontadores, ou ponteiros, são variáveis que armazenam o endereço de outras variáveis na memória. Ou seja, em vez de termos um valor numérico ou caracteres, por exemplo, armazenado na variável, temos um endereço. Dizemos que um ponteiro “aponta” para uma variável na memória quando este contém o endereço daquela variável. O uso de ponteiros é muito útil quando um dado deve ser acessado na memória em diferentes partes de um programa. Assim, podem existir vários ponteiros espalhados, indicando a localidade da variável que contém o dado desejado. Caso este dado seja atualizado, todas as partes que apontam para a variável serão atualizados simultaneamente (Ascencio, 2012). De acordo com Mizrahi (2008), estas são algumas razões para o uso de ponteiros:
A Figura 4 mostra a saída do algoritmo acima após a sua execução. Figura 4 – Saída do algoritmo Figura 5 – Exemplo de ponteiros A Figura 6 mostra a saída do algoritmo acima após a sua execução. Figura 6 – Saída do algoritmo
Figura 7 – Exemplo de ponteiros A Figura 8 mostra a saída do algoritmo acima após a sua execução. Figura 8 – Saída do algoritmo
Um ponteiro também é uma variável e também ocupa espaço na memória. Normalmente, o tamanho de um ponteiro independe do tipo de dados da variável da qual está apontando e ocupa o espaço de um inteiro (Mizrahi, 2008). Para obter o tamanho de um tipo de variável na linguagem de programação C, utiliza-se a função sizeof. A Figura 9 mostra um algoritmo que imprime o tamanho das variáveis mais usadas na escrita de um programa em linguagem de programação C (Mizrahi, 2008; Ascencio, 2012).
Trabalha-se com ponteiros quando existe a necessidade de ter os valores das variáveis alterados diretamente na memória mostra um. A Figura 12 mostra um algoritmo que evidencia esse conceito. Figura 12 – Manipulação de dados com ponteiros A Figura 13 mostra a saída do algoritmo acima após a sua execução. Figura 13 – Saída do algoritmo No momento em que declarou as variáveis c e d , também se fixaram os valores 5 e 3, respectivamente. Após a execução das instruções, conforme mostrado na Figura 6, seus valores foram alterados para 0 e 8 com o uso de ponteiros.
Vetores unidimensionais, ou arrays , consistem em um conjunto de dados de mesmo tipo armazenados em posições sequenciais na memória, caracterizando uma estrutura de dados homogênea. O nome do vetor é um
ponteiro que aponta para o primeiro elemento do vetor. Observe o algoritmo da Figura 14. Figura 14 – Ponteiros e vetores A Figura 15 mostra a saída do algoritmo acima após a sua execução. Figura 15 – Saída do algoritmo As instruções acima são usadas para criar um ponteiro que vai apontar para o primeiro elemento do vetor x[ ]. A expressão “ pont = x; ” faz com que o ponteiro “ pont ” atribua o endereço do primeiro elemento do vetor x[ ]. A Figura 16 ilustra a atribuição do endereço ao ponteiro “ pont ”. Figura 16 – Representação de um ponteiro com o endereço de um vetor
Figura 18 – Exemplo de ponteiro e vetor A Figura 19 mostra a saída do algoritmo acima após a sua execução. Figura 19 – Saída do algoritmo
Figura 20 – Exemplo de ponteiro e vetor A Figura 21 mostra a saída do algoritmo acima após a sua execução. Figura 21 – Saída do algoritmo
A Figura 25 mostra a saída do algoritmo da Figura 24 após a sua execução. Figura 25 – Saída do algoritmo Para acessar os elementos de pont[0], pont[1], pont[2] e pont[3], basta manipular os ponteiros utilizando o operador ‘*’ e indicar o índice desejado. Conforme mostrado abaixo: *pont[0] – é o valor 1, o conteúdo do endereço 116, ou seja, x[0] e o mesmo valor pode ser obtido com a instrução *pont[1] – é o valor 4, o conteúdo do endereço 128, ou seja, y[0]; *pont[2] – é o valor 7, o conteúdo do endereço 140, ou seja, z[0]; *pont[3] – é o valor 10, o conteúdo do endereço 152, ou seja, w[0]. Esse exemplo é ilustrado na Figura 26. Figura 26 – Vetor de ponteiros do tipo inteiro
Figura 27 – Exemplo de vetor de ponteiros A Figura 28 mostra a saída do algoritmo da Figura 27 após a sua execução. Figura 28 – Saída do algoritmo
Uma das vantagens obtidas com ponteiros é a possibilidade de alterar o valor de variáveis que estão lugares diferentes do programa. O asterisco é utilizado para indicar que as variáveis são ponteiros e guardam o endereço de outras variáveis simples na memória. Portanto, o conteúdo destas variáveis simples também pode ser modificado diretamente na memória quando passados seus endereços por meio
Figura 32 – Saída do algoritmo
Nesta aula, aprendemos os principais conceitos e temas das abordagens sobre ponteiro e sua aplicação em algoritmos computacionais; vimos como um dado é acessado na memória; bem como sua relação com vetores e funções.