Mudanças entre as edições de "PR1022804 2022 2 AULA11"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
(Criou página com '=Ponteiros= ;Objetivos *Introdução ao uso de ponteiros no C; *Vetor de ponteiros; *Argc e argv; *Ponteiros para qualquer coisa; *Ponteiros para estruturas. ;Para pensar:...')
 
 
(9 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
 
=Ponteiros=
 
=Ponteiros=
  
;Objetivos
 
  
*Introdução ao uso de ponteiros no C;
+
;OBJETIVOS
*Vetor de ponteiros;
 
*Argc e argv;
 
*Ponteiros para qualquer coisa;
 
*Ponteiros para estruturas.
 
  
 +
:O aluno será capaz de:
  
;Para pensar:
+
:*Fazer uso de ponteiros no C;
 +
:*Conhecer os Vetores de ponteiros;
 +
:*Utilizar Ponteiros para qualquer coisa; e
 +
:*Ponteiros para estruturas.
  
*A memória de um computador pode ser vista como um vetor de bytes.  
+
 
*Cada byte possui um endereço.  
+
;METODOLOGIA: A aula será expositiva e dialogada, utilizando apresentação de texto base na Internet, onde serão mostrados exemplos testados programas no microcomputador do laboratório de informática.
*O tamanho da memória é definido pelo tamanho do barramento de endereços usado para acessá-la.  
+
 
*Uma variável ocupa uma área da memória.  
+
 
*Tipicamente uma variável to tipo ''char'' se utiliza de um ''byte''.  
+
;PARA PENSAR
*Já uma variável do tipo ''int'' pode (dependendo do sistema) usar 4 ''bytes'' contíguos.
+
 
 +
:*A memória de um computador pode ser vista como um vetor de bytes.  
 +
:*Cada byte possui um endereço.  
 +
:*O tamanho da memória é definido pelo tamanho do barramento de endereços usado para acessá-la.  
 +
:*Uma variável ocupa uma área da memória.  
 +
:*Tipicamente uma variável to tipo ''char'' se utiliza de um ''byte''.  
 +
:*Já uma variável do tipo ''int'' pode (dependendo do sistema) usar 4 ''bytes'' contíguos.
  
 
   
 
   
Linha 25: Linha 30:
 
*Portanto a variável ponteiro também possui um endereço e contém um endereço como conteúdo.
 
*Portanto a variável ponteiro também possui um endereço e contém um endereço como conteúdo.
  
<blockquote style="background:#FFF5EE; border: 2px solid red; margin-left: 200px; margin-right: 200px; padding: 2em;">
+
<blockquote style="background:#FFF5EE; border: 2px solid red; margin-left: 300px; margin-right: 300px; padding: 2em;">
  
 
;Atenção:<span style="color:red;">'''Seu professor adverte: O uso descuidado de ponteiros pode causar dor de cabeça!</span>
 
;Atenção:<span style="color:red;">'''Seu professor adverte: O uso descuidado de ponteiros pode causar dor de cabeça!</span>
Linha 56: Linha 61:
  
  
;Exemplo 1: Considere o programa abaixo:
+
;EXEMPLO 1: Considere o programa abaixo:
 +
 
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
void main()
 
void main()
Linha 67: Linha 73:
 
Complete o código para copiar o conteúdo de x para y, sem que qualquer variável apareçam no lado esquerdo de um sinal de atribuição. Ou seja, sem envolver diretamente x e y.
 
Complete o código para copiar o conteúdo de x para y, sem que qualquer variável apareçam no lado esquerdo de um sinal de atribuição. Ou seja, sem envolver diretamente x e y.
  
;Exemplo 2: Tente inferir qual seria o valor da variável y no final do programa abaixo:
+
;EXEMPLO 2: Tente inferir qual seria o valor da variável y no final do programa abaixo:
 +
 
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
void main()
 
void main()
Linha 80: Linha 87:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
;Exemplo 3: Tente inferir qual seria o valor da variável y no final do programa abaixo:
+
;EXEMPLO 3: Tente inferir qual seria o valor da variável y no final do programa abaixo:
 +
 
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
void main()
 
void main()
Linha 96: Linha 104:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
;Exemplo 4: Qual seria o valor das variáveis '''y''' e '''x''' no final do programa abaixo:
+
;EXEMPLO 4: Qual seria o valor das variáveis '''y''' e '''x''' no final do programa abaixo:
 +
 
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
#include <stdio.h>
 
#include <stdio.h>
Linha 114: Linha 123:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
  
 
==Ponteiro para ''char''==
 
==Ponteiro para ''char''==
Linha 145: Linha 155:
 
No caso é 1 (tamanho de um ''char'' é um byte).
 
No caso é 1 (tamanho de um ''char'' é um byte).
  
;Exemplo: Sem executar o programa abaixo, determine o valor de y no final do programa:
+
 
 +
;EXEMPLO: Sem executar o programa abaixo, determine o valor de y no final do programa:
 +
 
 +
 
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
void main()
 
void main()
Linha 156: Linha 169:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
  
 
==Apontando para um vetor de inteiros==
 
==Apontando para um vetor de inteiros==
Linha 182: Linha 196:
  
 
'''OBSERVE''' que p++ incrementa em 4 unidades.
 
'''OBSERVE''' que p++ incrementa em 4 unidades.
 +
  
 
==Usando ponteiro na passagem de parâmetros==
 
==Usando ponteiro na passagem de parâmetros==
Linha 239: Linha 254:
  
 
==Ponteiros para ponteiros==
 
==Ponteiros para ponteiros==
 +
 
Um ponteiro para um ponteiro é como se você anotasse o endereço de um ponteiro na agenda que tem o endereço da casa do seu amigo. Pode-se declarar um ponteiro para ponteiro com a seguinte notação:
 
Um ponteiro para um ponteiro é como se você anotasse o endereço de um ponteiro na agenda que tem o endereço da casa do seu amigo. Pode-se declarar um ponteiro para ponteiro com a seguinte notação:
  
  
:;tipo_da_variavel **nome_da_variavel_ponteiro;
+
tipo_da_variavel **nome_da_variavel_ponteiro;
  
  
Linha 263: Linha 279:
  
 
'''NOTE''': Para acessar o valor apontado por um ponteiro para ponteiro, o operador asterisco deve ser aplicado duas vezes.
 
'''NOTE''': Para acessar o valor apontado por um ponteiro para ponteiro, o operador asterisco deve ser aplicado duas vezes.
 +
  
 
=Vetor de ponteiros=
 
=Vetor de ponteiros=
Linha 294: Linha 311:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
[[imagem:Fig1Aula24PrgITele.jpg|700px]]
+
[[imagem:Fig1Aula24PrgITele.jpg|center|700px]]
  
 
Observe que vp é um vetor de ponteiros para char e cada elemento aponta para uma cadeia de caracteres.
 
Observe que vp é um vetor de ponteiros para char e cada elemento aponta para uma cadeia de caracteres.
Linha 541: Linha 558:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
=Material de Apoio=
 
 
[1] [https://drive.google.com/file/d/1xt3pF05rYewUaub4C1Gv_Aqp4kKB8Q4w/view?usp=sharing Videoaula | Ponteiros]
 
 
  
 
=Referências=
 
=Referências=
Linha 563: Linha 575:
  
 
-----
 
-----
[[Imagem:icone_voltar.png|link=PR1022804_2022_1_AULA10]]
+
[[Imagem:icone_voltar.png|link=PR1022804_2022_2_AULA10]]
[[Imagem:icone_menu.png|link=PR1022804_2022_1#Aulas]]
+
[[Imagem:icone_menu.png|link=PR1022804_2022_2#Aulas]]
[[Imagem:icone_prox.png|link=PR1022804_2022_1_AULA12]]
+
[[Imagem:icone_prox.png|link=PR1022804_2022_2_AULA12]]

Edição atual tal como às 10h33min de 3 de novembro de 2022

Ponteiros

OBJETIVOS
O aluno será capaz de:
  • Fazer uso de ponteiros no C;
  • Conhecer os Vetores de ponteiros;
  • Utilizar Ponteiros para qualquer coisa; e
  • Ponteiros para estruturas.


METODOLOGIA
A aula será expositiva e dialogada, utilizando apresentação de texto base na Internet, onde serão mostrados exemplos testados programas no microcomputador do laboratório de informática.


PARA PENSAR
  • A memória de um computador pode ser vista como um vetor de bytes.
  • Cada byte possui um endereço.
  • O tamanho da memória é definido pelo tamanho do barramento de endereços usado para acessá-la.
  • Uma variável ocupa uma área da memória.
  • Tipicamente uma variável to tipo char se utiliza de um byte.
  • Já uma variável do tipo int pode (dependendo do sistema) usar 4 bytes contíguos.


Uma variável possui um endereço e um conteúdo (dados).
  • Uma variável ponteiro tem como conteúdo um endereço.
  • Portanto a variável ponteiro também possui um endereço e contém um endereço como conteúdo.
Atenção
Seu professor adverte: O uso descuidado de ponteiros pode causar dor de cabeça!

Ponteiro para inteiro

Observe o programa abaixo. A variável p é um ponteiro para inteiro. Isto significa que ela pode armazenar um endereço de um inteiro.

#include <stdio.h>

void main()
{
  int x;
  int *p;

  x=5;
  printf("Valor de x antes = %d\n", x);
  
  p = &x;
  *p=10;

  printf("Valor de x depois = %d\n", x);
  printf("Valor de p = %p\n", p);
}

Observe que para se referenciar o conteúdo da posição de memória apontada por p deve-se usar o asterisco: *p.


EXEMPLO 1
Considere o programa abaixo:
void main()
{
  int x=10;
  int y, *p;

}

Complete o código para copiar o conteúdo de x para y, sem que qualquer variável apareçam no lado esquerdo de um sinal de atribuição. Ou seja, sem envolver diretamente x e y.

EXEMPLO 2
Tente inferir qual seria o valor da variável y no final do programa abaixo:
void main()
{
  int x,y,w,*p1,*p2;
  x = 20;
  w = 30;
  p1 = &x;
  p2 = &w;
  y = *p1 + *p2;
}
EXEMPLO 3
Tente inferir qual seria o valor da variável y no final do programa abaixo:
void main()
{
  int x,y,w,*p1,*p2, *p3;
  x = 20;
  w = 30;
  p1 = &x;
  p2 = &w;
  y = *p1 + w;
  p3 = &y;
  *p3 = *p3 + 10;
  y = *p1 + *p2 + *p3;
}
EXEMPLO 4
Qual seria o valor das variáveis y e x no final do programa abaixo:
#include <stdio.h>

void main()
{
	int x,y;
	int *p;
	y=0;
	p=&y;
	x=*p; 	
	x=4; 	
	(*p)++;	
	x--;	
	(*p) += x; 
	printf("\ny=%d x=%d\n",y,x);
}


Ponteiro para char

Os ponteiro para char são muito utilizados pois permitem apontar para strings. A ideia é que ele aponte para o primeiro caracter (char) da string. Veja o exemplo abaixo.

#include <stdio.h>

void main()
{
   char x[10]="ifsc";
   char *p;

   p = &x[2];

   printf("x[2] = %c\n", *p);

   p = x;

   printf("string %s\n", p);

   while (*p!=0) {
       printf("Endereco %p conteúdo %c\n", p,*p);
       p++;
   }	
}

Neste foi usado o incremento de um ponteiro, o que implica em adicionar ao endereço armazenado em p uma quantidade relativa ao tamanho do tipo apontado. No caso é 1 (tamanho de um char é um byte).


EXEMPLO
Sem executar o programa abaixo, determine o valor de y no final do programa:


void main()
{
   char x[10]="ifsc";
   char *p, y;
   
   p = x + 2;
   y= *p;
}


Apontando para um vetor de inteiros

Da mesma forma que usamos um ponteiro para char para apontar uma string, podemos fazer um ponteiro para int apontar para para um elemento de um vetor de inteiros.

#include <stdio.h>

void main()
{
   int x[10]= {0,1,2,3,4,5,6,7,8,9};
   int *p;
   int i;
   
   p = x;

   i=0;
   while (i<10) {
       printf(" endereco %p e conteudo %d\n", p, *p);
       p++;
       i++;       
   }	
}

OBSERVE que p++ incrementa em 4 unidades.


Usando ponteiro na passagem de parâmetros

Observe como podemos usar ponteiros na passagem de parâmetros.

#include <stdio.h>

void str_cpy(char *pdest, char *pfonte)
{
   while (*pfonte!=0) {
        *pdest++ = *pfonte++;
   }
   *pdest = 0;
}


int str_len (char *p)
{
   int i=0;
   while (*p++!=0)
	i++;
   return i;
}

void main()
{
   char fonte[10]="ifsc";
   char destino[10];

   str_cpy(destino, fonte);
   printf("string destino = %s\n", destino);

   printf("tamanho de dest = %d\n", str_len(destino));
}

Um ponto interessante é que ponteiros permitem, na chamada de uma função, passar valores por referência:

void alfa(int *p)
{
  *p=10;
}

void main()
{
  int x;
  x =5;
  printf("Valor de x antes da chamada de alfa = %d\n", x);
  alfa(&x);
  printf("Valor de x depois da chamada de alfa = %d\n", x);
}

Ponteiros para ponteiros

Um ponteiro para um ponteiro é como se você anotasse o endereço de um ponteiro na agenda que tem o endereço da casa do seu amigo. Pode-se declarar um ponteiro para ponteiro com a seguinte notação:


tipo_da_variavel **nome_da_variavel_ponteiro;


Sendo que o **nome_da_variavel_ponteiro é o conteúdo final da variável apontada, e *nome_da_variavel_ponteiro é o conteúdo do ponteiro intermediário.

NOTE: Na linguagem C pode-se declarar ponteiros para ponteiros para ponteiros para ponteiros... e assim por diante.

#include <stdio.h>

void main()
{
	float fpi=3.1415, *pf, **ppf;
	pf=&fpi;		// pf armazena o endereco de fpi
	ppf=&pf;		// ppf armazena o endereco de pf
	printf("\n%f", **ppf);	// imprime o valor de fpi por ppf
	printf("\n%f", *pf);	// imprime o valor de fpi por pf
}

NOTE: Para acessar o valor apontado por um ponteiro para ponteiro, o operador asterisco deve ser aplicado duas vezes.


Vetor de ponteiros

Como visto em aulas anteriores, variáveis ponteiros possuem como conteúdo um endereço. É perfeitamente possível construir vetores e matrizes de ponteiros.

EXEMPLO
Veja o programa abaixo:
#include <stdio.h>

int main()
{
  int i;

  char *vp[4];
  char alfa[5]="IFSC";
  char beta[5]="TELE";
  char delta[5]="RAC";
  char gamma[5]="CGER";

  vp[0] = alfa;
  vp[1] = beta;
  vp[2] = delta;
  vp[3] = gamma;  

  for(i=0;i<4;i++)
	printf("%s\n", vp[i]);
}
Fig1Aula24PrgITele.jpg

Observe que vp é um vetor de ponteiros para char e cada elemento aponta para uma cadeia de caracteres.

Argumentos de linha de comando

Um bom exemplo de vetor de ponteiros é a passagem de parâmetros na linha de comando. Cada parâmetro é tratado como uma cadeia de caracteres apontada por um elemento do vetor argv. O número de parâmetros é passado em argc. Note que argv[0] aponta para uma string que indica o nome do programa.

Exemplo
Teste o programa abaixo:
#include <stdio.h>

int main(int argc, char *argv[])
{
  int i;

  for (i=0;i<argc;i++) {
       printf("%s\n", argv[i]);
  }
  printf("Numero de parametros passados = %d\n", argc-1); /* o primeiro é o nome do arquivo executavél" */
}

Apontando para estruturas

Ponteiros podem apontar para qualquer "objeto" de qualquer tipo. Vamos verificar como é possível apontar para uma estrutura:

#include <stdio.h>

struct TRegistro {
   char nome[20];
   int idade;
} Tabela[4] = {
          {"joao",18,},
          {"maria",18,},
          {"jose",19,},
          {"lara",17,},
}
;

struct TRegistro *p;

void main()
{
  p = &Tabela[3]; /*p aponta para o registro 3 da tabela */
  printf("O nome na posição 3 é %s e idade = %d\n", p->nome,p->idade);
}

NOTE que o uso de p->nome é uma alternativa ao uso de (*p).nome

No primeiro caso pode-se ler: o campo nome do objeto que é apontado por p.

Retornando uma estrutura em uma função

No exemplo a abaixo a função RetornarStruct() retorna um ponteiro para uma estrutura. O cuidadado que se deve ter é que a função não deveria apontar para uma estrutura que foi criada localmente na função!

#include <stdio.h>
struct TRegistro {
   char nome[20];
   int idade;
} Tabela[4] = {
          {"joao",18,},
          {"maria",18,},
          {"jose",19,},
          {"lara",17,},
}
;

struct TRegistro *p;

struct TRegistro * RetornarStruct(int indice)
{
  return &Tabela[indice];
}

void main()
{
  p = RetornarStruct(2); /*p aponta para o registro 3 da tabela */
  printf("O nome na posição 2 é %s e idade = %d\n", p->nome,p->idade);
}

Passando uma estrutura como parâmetro

#include <stdio.h>
struct TRegistro {
   char nome[20];
   int idade;
} Tabela[4] = {
          {"joao",18,},
          {"maria",18,},
          {"jose",19,},
          {"lara",17,},
};

struct TRegistro *p;

void MudarStruct(struct TRegistro *p1, int indice)
{
  Tabela[indice] = *p1;
}

void main()
{
  struct TRegistro aux = {"luisa",16};

  MudarStruct(&aux,2);
  p = &Tabela[2];
  printf("O nome na posição 2 é %s e idade = %d\n", p->nome,p->idade);
}

Exercício: No programa acima construir uma função que imprime a Tabela usando ponteiros. A função deve receber como parâmetro um ponteiro para o início da tabela e o tamanho da tabela.

Exercícios

1. Implementar a função str_cat que concatena duas strings usando ponteiros.

2. Ordenar valores de um vetor de inteiros passando por referencia o ponteiro para esse vetor.

3. Implememtar um programa que recebe 3 parâmetros na linha de comando: dois números reais e um operador (char). Operador pode ser + ou menos. O programa deve mostrar o resultado da operação.

Exemplo: calcula 3.5 + 2.6
para usar a função atof para converter string em float.

4.Implementar um programa chamado cmpcadeia que testa se duas strings passadas na linha de comando são iguais. O programa deve imprimir uma mensagem indicando se são iguais ou diferentes. Usar a função strcmp da biblioteca. Caso sejam passados mais ou menos que dois parâmetros o programa deve se encerrar mostrando uma indicão do tipo:

cmpcadeia: dois parametros devem ser passados.

5. Renomeie o executável e veja seja a mensagem de erro mostra o nome correto do programa.

6. Implementar um programa para ler dados para dentro das variáveis x e y e somar o conteúdo das mesmas colocando o resultado em x SEM referenciar estas variáveis no scanf ou na expressão de soma. 2. Implementar uma função que compara duas strings passadas como parâmetro. A função retorna 0 se as strings forem iguais e 1 se diferentes. Usar ponteiros. 7. Implementar uma função que recebe como parâmetro o endereço de duas variáveis float que contêm a parte real e imaginária de um número complexo no formato polar (ângulo em radianos). A função deve converter do formato polar retangular colocando a coordenada x no primeira variável cujo endereço foi fornecido como parâmetro e a coordenada y na segunda variável (Olhar AULA 15).

void converte_polar_retang(float *parte1, float *parte2)
{
}

void main()
{
  float num1=1.5, num2=10.6;

  /*chamar a função aqui */

  /* imprimir os valores de num1 e num2 aqui */
}

8. Implemantar uma função que recebe como parâmetro o endereço de duas variáveis do tipo char e após a chamada da função os valores das variáveis devem ser convertidos para caixa alta (maiúsculas).

void main()
{
  char alfa='a', beta='b';

  capitaliza(&alfa, &beta);
  
  /* aqui os valores de alfa e beta deverão ser A e B */
}

9. Implementar uma função que recebe uma string contendo uma cadeia de caracteres com dígitos numéricos e retorna o valor inteiro da string. Usar ponteiros.

int a_toi(char *p)
{
}

void main()
{
  char *p="123";
  int x;

  x = a_toi(p);
  
  /* neste ponto x deve conter 123 */
}

10. O código abaixo implementa a série responsável pelo cálculo da raiz quadrada de um número.

#include <stdio.h>

float raiz_quadrada(float numero);

int main( int argc, char **argv)
{  
    float numero;
   
    printf("Entre com um número positivo por favor : ");
    scanf("%f",&numero);
   
    printf("A raiz quadrada de %.3f é %.5f \n",numero,raiz_quadrada(numero));

    return(0);
}


float raiz_quadrada (float numero)
{
    int n;
    float recorre = numero;
   
    for (n = 0; n < 10; ++n)
          recorre = recorre/2 + numero/(2*recorre);
           
    return(recorre);    
}

11. O código abaixo implementa uma variação em que número é passado por parâmetro através do programa principal e retorna a raiz quadrada de um número para o SO.

#include <stdio.h>
#include <stdlib.h>
 
float raiz_quadrada (float numero)
{
    int n;
    float recorre = numero;
 
    for (n = 0; n < 10; ++n)
          recorre = recorre/2 + numero/(2*recorre);
 
    return(recorre);    
}
 
int main( int argc, char *argv[])
{  
    float numero;

    if(argv[1]==NULL){
	printf("\n%s: falta número",argv[0]);
    }
    
    numero=atof(argv[1]);

    printf("\n%.4f \n",raiz_quadrada(numero));
 
    return(0);
}

Referências

[1] http://pw1.netcom.com/~tjensen/ptr/ch1x.htm

[2] http://eternallyconfuzzled.com/tuts/languages/jsw_tut_pointers.aspx

[3] http://duramecho.com/ComputerInformation/WhyCPointers.html

[4] http://boredzo.org/pointers/ http://boredzo.org/pointers/

[5] http://www.mtm.ufsc.br/~azeredo/cursoC/aulas/c600.html




Icone voltar.png Icone menu.png Icone prox.png