Mudanças entre as edições de "AULA 17 - Programação 1 - Engenharia"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
 
(91 revisões intermediárias por 5 usuários não estão sendo mostradas)
Linha 1: Linha 1:
===Objetivos===
+
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
  
*iniciação ao uso de ponteiros no C;
+
=Objetivos=
 +
</blockquote>
 +
 
 +
Ao final desta aula o aluno deverá ser capaz de:
 +
 
 +
*conceituar ponteiros no C mostrando um diagrama de memória e a possibilidade de manipular posições de memória com ponteiros;
 +
*saber definir ponteiros para quaisquer tipos de variáveis;
 +
*saber iniciar e manipular o conteúdo de outras variáveis usando ponteiros;
 +
*saber operar sobre arranjos e estruturas usando ponteiros;
 +
*usar ponteiros em parâmetros de funções para implementar passagem por referência;
 +
*operar sobre strings usando ponteiros;
 +
*construir e usar arranjos de ponteiros e, em particular, aplicar em passagem de parâmetros na linha de comando.
  
 
===Referências===
 
===Referências===
Linha 12: Linha 23:
 
[http://boredzo.org/pointers/]
 
[http://boredzo.org/pointers/]
  
 +
[https://www.embarcados.com.br/ponteiro-em-c-definicao/ Site Embarcados]
 +
 +
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
 +
=Conceito de Ponteiro=
 +
</blockquote>
  
===Ponteiros===
+
*[https://drive.google.com/file/d/16aH_cxGBafeDbGLMi4bxahQ2wRZtwr1N/view?usp=sharing Vídeo Explicativo de Ponteiros no C]
  
 
A memória de um computador pode ser vista como um vetor de bytes.  
 
A memória de um computador pode ser vista como um vetor de bytes.  
Linha 23: Linha 39:
 
   Uma variável possui um endereço e um conteúdo (dados).
 
   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 possui um endereço e contém um endereço como conteúdo.
  
Uma variável ponteiro tem como conteúdo um endereço. Portanto a variável ponteiro possui um endereço e contém um endereço como conteúdo.
+
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
  
===Ponteiro para inteiro===
+
=Ponteiro para inteiro=
 +
</blockquote>
 +
 
 +
 
 +
*[https://drive.google.com/file/d/1vyDfMRymjvL2-SUe3VJWpxbhvH5USUrF/view?usp=sharing Vídeo Explicativo desta seção]
  
 
Observe o programa abaixo. A variável ''p'' é um ponteiro para inteiro. Isto significa que ela pode armazenar um endereço
 
Observe o programa abaixo. A variável ''p'' é um ponteiro para inteiro. Isto significa que ela pode armazenar um endereço
de um inteiro.
+
de um inteiro. O operador ''&'' é usado para capturar o endereço da variável.
 
 
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
#include <stdio.h>
 
#include <stdio.h>
  
main()
+
void main()
 
{
 
{
 
   int x;
 
   int x;
Linha 44: Linha 64:
 
    
 
    
 
   p = &x;
 
   p = &x;
   *p=10;
+
   *p = 10;
  
 
   printf("Valor de x depois = %d\n", x);
 
   printf("Valor de x depois = %d\n", x);
Linha 54: Linha 74:
  
 
EXERCÍCIO 1: Considere o programa:
 
EXERCÍCIO 1: Considere o programa:
 +
 +
*[https://drive.google.com/file/d/18A8aeRjIYZJ4qWGKtPWCslljIoRZhBq3/view?usp=sharing Vídeo Explicativo Exercício 1]
 +
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
main()
+
int main(void)
 
{
 
{
 
   int x=10;
 
   int x=10;
Linha 63: Linha 86:
 
</syntaxhighlight>
 
</syntaxhighlight>
 
Faça um código para copiar o conteúdo de x para y, sem que estas variáveis apareçam no lado esquerdo de um sinal de atribuição.
 
Faça um código para copiar o conteúdo de x para y, sem que estas variáveis apareçam no lado esquerdo de um sinal de atribuição.
 +
 +
{{collapse top | solução Ex. 1}}
 +
<syntaxhighlight lang=c>
 +
int main(void)
 +
{
 +
  int x=10;
 +
  int y, *p, *w;
 +
 
 +
  p = &x;
 +
  w = &y;
 +
  *w = *p; 
 +
 +
  printf("valor copiado para y : %d\n",y);
 +
  return 0;
 +
}
 +
</syntaxhighlight>
 +
{{collapse bottom}}
  
 
EXERCÍCIO 2: Tente inferir qual seria o valor da variável y no final do programa abaixo.
 
EXERCÍCIO 2: Tente inferir qual seria o valor da variável y no final do programa abaixo.
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
main()
+
int main(void)
 
{
 
{
 
   int x,y,w,*p1,*p2;
 
   int x,y,w,*p1,*p2;
Linha 74: Linha 114:
 
   p2 = &w;
 
   p2 = &w;
 
   y = *p1 + *p2;
 
   y = *p1 + *p2;
 +
  return 0;
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
{{collapse top | solução Ex. 2}}
 +
<syntaxhighlight lang=c>
 +
y = 50
 +
</syntaxhighlight>
 +
{{collapse bottom}}
  
 
EXERCÍCIO 3: Tente inferir qual seria o valor da variável y no final do programa abaixo.
 
EXERCÍCIO 3: Tente inferir qual seria o valor da variável y no final do programa abaixo.
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
main()
+
int main(void)
 
{
 
{
 
   int x,y,w,*p1,*p2, *p3;
 
   int x,y,w,*p1,*p2, *p3;
Linha 90: Linha 137:
 
   *p3 = *p3 + 10;
 
   *p3 = *p3 + 10;
 
   y = *p1 + *p2 + *p3;
 
   y = *p1 + *p2 + *p3;
 +
  return 0;
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Ponteiro para ''char''===
+
{{collapse top | solução Ex. 3}}
 +
<syntaxhighlight lang=c>
 +
y = 110
 +
</syntaxhighlight>
 +
{{collapse bottom}}
 +
 
 +
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;">
 +
 
 +
=Ponteiro para ''char''=
 +
</blockquote>
 +
 
  
 
Os ponteiro para ''char'' são muito utilizados pois permitem apontar para ''strings''. A ideia é que ele aponte para o primeiro caracter da ''string''. Veja o exemplo abaixo.
 
Os ponteiro para ''char'' são muito utilizados pois permitem apontar para ''strings''. A ideia é que ele aponte para o primeiro caracter da ''string''. Veja o exemplo abaixo.
Linha 100: Linha 158:
 
#include <stdio.h>
 
#include <stdio.h>
  
main()
+
int main(void)
 
{
 
{
 
   char x[10]="ifsc";
 
   char x[10]="ifsc";
   char *p;
+
   char alfa='X', *p;
 +
 
 +
  p = &alfa;    /* p aponta para alfa */
 +
 
 +
  printf("O caracter apontado por p é %c", *p);
  
   p = &x[2];
+
   p = &x[2];   /* p aponta para o caracter que está
 +
                    na posição 2 do vetor x */
  
 
   printf("x[2] = %c\n", *p);
 
   printf("x[2] = %c\n", *p);
Linha 116: Linha 179:
 
       printf("Endereco %p conteúdo %c\n", p,*p);
 
       printf("Endereco %p conteúdo %c\n", p,*p);
 
       p++;
 
       p++;
   }
+
   }
 +
   
 +
  return 0;
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Linha 125: Linha 190:
 
EXERCÍCIO: Sem executar o programa abaixo, determine o valor de y no final do programa:
 
EXERCÍCIO: Sem executar o programa abaixo, determine o valor de y no final do programa:
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
main()
+
int main(void)
 
{
 
{
 
   char x[10]="ifsc";
 
   char x[10]="ifsc";
Linha 131: Linha 196:
 
    
 
    
 
   p = x + 2;
 
   p = x + 2;
   y= *p;
+
   y = *p;
 +
  return 0;
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
{{collapse top | solução}}
 +
<syntaxhighlight lang=c>
 +
y = 's'
 +
</syntaxhighlight>
 +
{{collapse bottom}}
  
===Apontando para um vetor de inteiros===
+
=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.
+
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. Notar que o ponteiro na prática deve apontar para um elemento específico do vetor. Se o ponteiro for incrementado ele apontará para o próximo elemento.
 
   
 
   
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
#include <stdio.h>
 
#include <stdio.h>
  
main()
+
int main()
 
{
 
{
 
   int x[10]= {0,1,2,3,4,5,6,7,8,9};
 
   int x[10]= {0,1,2,3,4,5,6,7,8,9};
Linha 155: Linha 226:
 
       p++;
 
       p++;
 
       i++;       
 
       i++;       
   }
+
   }
 +
  return 0;
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
  
 
  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=
 
 
Observe como podemos usar ponteiros na passagem de parâmetros.
 
  
 +
Observe como podemos usar ponteiros na passagem de parâmetros. O exemplo abaixo mostra a passagem de dois vetores para a função str_cpy. Os dois parâmetros formais da função são ponteiros para char. Pode-se analisar o código da seguinte forma: pdest e pfonte são parâmetros (varíaveis) que recebem os endereços dos vetores destino e fonte. Desta forma, é possível manipular as strings contidas nestes vetores através dos parâmetros pdest e pfonte.
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
Linha 187: Linha 257:
 
}
 
}
  
main()
+
int main(void)
 
{
 
{
 
   char fonte[10]="ifsc";
 
   char fonte[10]="ifsc";
Linha 196: Linha 266:
  
 
   printf("tamanho de dest = %d\n", str_len(destino));
 
   printf("tamanho de dest = %d\n", str_len(destino));
 +
  return 0;
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Um ponto interessante é que ponteiros permitem, na chamada de uma função, passar valores por referência:
+
Um ponto interessante é que ponteiros permitem, na chamada de uma função, passar valores por referência (de forma "simulada"):
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
Linha 218: Linha 289:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
EXERCíCIO 1: Implementar a função ''str_cat'' que concatena duas ''strings'' usando ponteiros.
+
==Exercícios==
  
 +
<ol>
 +
<li> Rever a aula da UFMG em [http://www.mtm.ufsc.br/~azeredo/cursoC/aulas/c600.html Link Aula Ponteiros UFMG] e fazer os exercícios de fixação. Obs: Se necessário, ao ler no browser, troque a codificação de UTF8 para Ocidental. Eu tive problemas na leitura da página.</li>
  
 +
<li> Implemente um programa que realize o swap de duas variáveis inteiras passadas como parâmetro. Use ponteiros.
 +
 +
 +
<!--
 +
{{collapse top | solução 1:}}
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
 +
int swap (int *px, int *py){
 +
 +
  int temp;
 +
 +
  temp = *px;
 +
  *px = *py;
 +
  *py = temp;
 +
}
 +
 +
int main (void){
 +
 +
  int a=1, b=2;
 +
 +
  printf("Valor de a=%d, valor de b=%d\n", a, b);
 +
 +
  swap(&a,&b);
 +
 +
  printf("Valor de a=%d, valor de b=%d\n", a, b);
 +
  return (0);
 +
}
 +
</syntaxhighlight>
 
{{collapse bottom}}
 
{{collapse bottom}}
 +
-->
 +
</li>
 +
 +
<li>
 +
Implementar a função ''str_cat'' cujo esqueleto é fornecido abaixo, de forma a concatenar duas ''strings'' passadas como parâmetro através de ponteiros. A segunda string deve ser colocada no final da primeira string. A função deve retornar um ponteiro para a string concatenada.
 +
 +
<syntaxhighlight lang=c>
 +
char *str_cat(char *p1, const char *p2)
 +
{
 +
 +
}
 +
 +
/* exemplo de uso da função */
 +
int main()
 +
{
 +
  char vet1[10]="IFSC";
 +
  char vet2[5]="-SC";
 +
 
 +
  p = str_cat(vet1,vet2);
 +
  printf("%s",vet1); /* aqui deveria imprimir "IFSC-SJ" */
 +
  printf("%s",p);    /* aqui também deveria imprimir "IFSC-SJ" */
 +
  return (0);
 +
}
 +
</syntaxhighlight>
 +
 +
{{collapse top | solução A:}}
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
 +
char *str_cat(char *p1, const char *p2)
 +
{
 +
  char *pdest;
 +
 +
  pdest = p1; /*salva o ponteiro mpara o inicio */
 +
 +
  while (*p1 != '\0')
 +
          p1++; /* encontra o final da string 1 */
  
[http://www.mtm.ufsc.br/~azeredo/cursoC/aulas/c600.html Link Aula Ponteiros UFMG]
 
  
{{collapse top | Aula dia 22/05/2014}}
+
  while(*p2 != '\0' ){ /* copia até o final da string apontada por p2 */
 +
    *p1++ = *p2++;
 +
  };
  
Viagem para Porto Alegre
+
  *p1 = '\0'; /* coloca o NULL no final da string concatenada */
  
 +
  return pdest;
 +
}
 +
 +
/* exemplo de uso da função */
 +
int main(void)
 +
{
 +
  char vet1[30]="IFSC";
 +
  char vet2[20]="-SJ";
 +
 +
  printf("%s\n",str_cat(vet1,vet2));
 +
  return (0);
 +
}
 +
</syntaxhighlight>
 
{{collapse bottom}}
 
{{collapse bottom}}
  
{{collapse top | Aula dia 23/05/2014}}
+
{{collapse top | solução B:}}
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
 +
char *str_cat(char *p1, char *p2)
 +
{
 +
  char *pdest = p1;
 +
 
 +
  while (*p1)
 +
    p1++;  /* localiza po final da string */
 +
  while (*p1++ = *p2++) /* copia, avalia a expressão - se 0 encerra o while - incrementa os ponteiros */
 +
      ;
 +
  return pdest;
 +
}
 +
 +
/* exemplo de uso da função */
 +
int main(void)
 +
{
 +
    char vet1[30]="IFSC";
 +
    char vet2[20]="-SJ";
 +
    char *p;
 +
 
 +
    p = str_cat(vet1,vet2);
 +
    printf("%s\n",p);   
 +
    printf("%s\n",vet1);
 +
    return (0);
 +
}
 +
</syntaxhighlight>
 +
{{collapse bottom}}
  
Viagem para Porto Alegre
+
{{collapse top | Solução C:}}
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
 +
/* extraído do site stackoverflow */
 +
char *str_cat(char *p1, char *p2)
 +
{
 +
    int i,j;
 +
    for (i = 0; p1[i] != '\0'; i++)
 +
        ;  /* Localiza o final da string - no final i contém o índice do NULL */
 +
    for (j = 0; p2[j] != '\0'; j++)
 +
        p1[i+j] = p2[j]; /* faz a cópia - no final j contém o ídnice do NULL*/
 +
    p1[i+j] = '\0';
 +
    return p1;
 +
}
 +
 +
/* exemplo de uso da função */
 +
int main(void)
 +
{
 +
  char vet1[30]="IFSC";
 +
  char vet2[20]="-SJ";
 +
  char *p;
  
Exercícios Adicionais ponteiros
+
  p = str_cat(vet1,vet2);
 +
  printf("%s\n",p);   
 +
  printf("%s\n",vet1);
 +
  return (0);
 +
}
 +
</syntaxhighlight>
 +
{{collapse bottom}}
 +
</li>
  
1.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
+
<li>
referenciar estas variáveis no scanf ou na expressão de soma.
+
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.
  
 +
{{collapse top | solução Ex. 4}}
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
#include <stdio.h>
 
#include <stdio.h>
main()
+
 
 +
int main(void)
 
{
 
{
 
   float x,y;
 
   float x,y;
 +
  float *p1,*p2;
 +
 +
  p1=&x,
 +
  p2=&y; 
 +
  printf("Entre com número 1\n");
 +
  scanf("%f",p1);
 +
  printf("Entre com número 2\n");
 +
  scanf("%f",p2);
 +
  *p1=*p1+*p2;
 +
  printf("valor de x é %f\n", x);
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
{{collapse bottom}}
 +
</li>
 +
 +
<li>
 +
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.
 +
 +
{{collapse top| solução Ex. 5}}
 +
<syntaxhighlight lang=c>
 +
//Autor:Victor Cesconetto de Pieri
 +
#include <stdio.h>
 +
 +
int str_cmp(char * p1, char * p2) {
 +
 +
  while ( * p1 != 0 || * p2 != 0) {
  
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.
+
    if ( * p1 == * p2) { //compara os conteúdos apontados por p1 e p2
Usar ponteiros.
+
      p1++; //próxima posição de p1
 +
      p2++; //próxima posição de p2   
 +
      //retorna 1 se forem diferentes
 +
    } else {
 +
      return 1;
 +
    } //se percorrer a string totalmente e nao encontrar nada diferente retorna 0         
  
3.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.
+
  }
 +
  return 0;
 +
}
 +
 
 +
int main(void) {
 +
  char vet1[20] = "IFSC";
 +
  char vet2[20] = "IFSCC";
 +
 
 +
  printf("%d\n", str_cmp(vet1, vet2));
 +
  return (0);
 +
}
 +
</syntaxhighlight>
 +
{{collapse bottom}}
 +
</li>
 +
 
 +
<li>
 +
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.
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
 
+
void converte_polar_retang(float *parte1, float *parte2)
void converte_polar_retang(float *parte1, float parte2)
 
 
{
 
{
 
}
 
}
  
main()
+
int main(void)
 
{
 
{
 
   float num1=1.5, num2=10.6;
 
   float num1=1.5, num2=10.6;
Linha 269: Linha 524:
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
4.Implemantar uma funçao que recebe como parâmetro o endereço de duas variáveis do tipo char e
+
{{collapse top | solução Ex. 6}}
após a chamada da função os valores das variáveis devem estar maiúsculos(caso elas contenham letras minúsculas).
+
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
#include <math.h>
 +
 
 +
void converte_polar_retang(float *parte1, float *parte2)
 +
{
 +
float real, img;
 +
real = *parte1 * cos(*parte2);//parte real
 +
img = *parte1 * sin(*parte2);//parte imaginaria
 +
*parte1 = real;
 +
*parte2 = img;
 +
}
 +
 +
int main(void)
 +
{
 +
  float num1=1.5, num2=10.6;
 +
 +
  /*chamar a função aqui */
 +
  converte_polar_retang(&num1,&num2);  // passa-se o endereço das variáveis como parâmetro
 +
 
 +
  /* imprimir os valores de num1 e num2 aqui */
 +
  printf("%f %f\n",num1,num2);
 +
  return (0);
 +
}
 +
</syntaxhighlight>
 +
{{collapse bottom}}
 +
</li>
 +
 
 +
<li>
 +
Implementar 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 estar maiúsculos (caso elas contenham letras minúsculas).
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
main()
+
void capitaliza(char *c1, char *c2)
 +
{
 +
}
 +
 
 +
int main(void)
 
{
 
{
 
   char alfa='a', beta='b';
 
   char alfa='a', beta='b';
Linha 281: Linha 569:
 
   /* aqui os valores de alfa e beta deverão ser A e B */
 
   /* aqui os valores de alfa e beta deverão ser A e B */
 
}
 
}
 +
</syntaxhighlight>
 +
 +
{{collapse top | solução Ex. 7}}
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
 +
void capitaliza(char *c1, char *c2)
 +
{
 +
*c1 = *c1-32;//subtrai do valor do char -32 para transformar o 'a' em 'A'
 +
*c2 = *c2-32;
 +
}
 +
 +
int main(void)
 +
{
 +
  char alfa='a', beta='b';
 +
 +
  capitaliza(&alfa, &beta);
  
 +
  printf("alfa : %c e beta: %c\n",alfa,beta);
 +
 +
  /* aqui os valores de alfa e beta deverão ser A e B */
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
{{collapse bottom}}
 +
</li>
  
5.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.
+
<li>
 +
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.
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
Linha 302: Linha 614:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
{{collapse top | solução Ex. 8}}
 +
 +
<!--
 +
<syntaxhighlight lang=c>
 +
//Autor: Victor Cesconetto
 +
#include <stdio.h>
 +
int a_toi(char *p)
 +
{
 +
  int ;
 +
  for(i=0;*p!=0;i++){
 +
  teste = teste*10 + *p - '0';
 +
  p++;
 +
  }
 +
  return teste;
 +
}
 +
 +
int main()
 +
{
 +
  char *p="123";
 +
  int x;
 +
 +
  x = a_toi(p);
 +
 +
  printf("%d\n",x);
 +
 +
  /* neste ponto x deve conter 123 */
 +
}
 +
</syntaxhighlight>
 +
-->
 +
{{collapse bottom}}
 +
 +
</li>
 +
 +
<li>
 +
Construir uma função usando ponteiros que retorna a média de um vetor de inteiros passado como parâmetro. O tamanho do vetor também deve ser fornecido.
 +
 +
<syntaxhighlight lang=c>
 +
float media_vet(int *vet, int tamanho)
 +
{
 +
}
 +
 +
/* exemplo de uso */
 +
 +
main()
 +
{
 +
  int x[10]= {0,1,29,3,42,5,61,7,82,9};
 +
  float media;
 +
 +
  media = media_vet(x,10); /* em media_vet deve ficar a média do vetor */
 +
}
 +
 +
</syntaxhighlight>
 +
 +
{{collapse top | solução Ex. 9}}
 +
<syntaxhighlight lang=c>
 +
 +
float media_vet(int *vet, int tamanho)
 +
{
 +
float media, total;
 +
int i;
 +
for(i=0;i<tamanho;i++){
 +
    total = total+*vet;
 +
    printf("tao : %f\n",*vet);
 +
    vet++;
 +
}
 +
 +
media = total/tamanho;
 +
 +
}
 +
 +
/* exemplo de uso */
 +
 +
main()
 +
{
 +
  int x[10]= {0,1,29,3,42,5,61,7,82,9};
 +
  float media;
 +
 +
  media = media_vet(x,10); /* em media_vet deve ficar a média do vetor */
 +
  //printf("%f\n",media);
 +
}
 +
 +
</syntaxhighlight>
 +
{{collapse bottom}}

Edição atual tal como às 10h12min de 5 de dezembro de 2023

Objetivos

Ao final desta aula o aluno deverá ser capaz de:

  • conceituar ponteiros no C mostrando um diagrama de memória e a possibilidade de manipular posições de memória com ponteiros;
  • saber definir ponteiros para quaisquer tipos de variáveis;
  • saber iniciar e manipular o conteúdo de outras variáveis usando ponteiros;
  • saber operar sobre arranjos e estruturas usando ponteiros;
  • usar ponteiros em parâmetros de funções para implementar passagem por referência;
  • operar sobre strings usando ponteiros;
  • construir e usar arranjos de ponteiros e, em particular, aplicar em passagem de parâmetros na linha de comando.

Referências

[1]

[2]

[3]

[4]

Site Embarcados

Conceito de Ponteiro

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 possui um endereço e contém um endereço como conteúdo.

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. O operador & é usado para capturar o endereço da variável.

#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

EXERCÍCIO 1: Considere o programa:

int main(void)
{
  int x=10;
  int y, *p, *w;

}

Faça um código para copiar o conteúdo de x para y, sem que estas variáveis apareçam no lado esquerdo de um sinal de atribuição.

solução Ex. 1
int main(void)
{
  int x=10;
  int y, *p, *w;
  
  p = &x;
  w = &y;
  *w = *p;  

  printf("valor copiado para y : %d\n",y);
  return 0;
}

EXERCÍCIO 2: Tente inferir qual seria o valor da variável y no final do programa abaixo.

int main(void)
{
  int x,y,w,*p1,*p2;
  x = 20;
  w = 30;
  p1 = &x;
  p2 = &w;
  y = *p1 + *p2;
  return 0;
}
solução Ex. 2
y = 50

EXERCÍCIO 3: Tente inferir qual seria o valor da variável y no final do programa abaixo.

int main(void)
{
  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;
  return 0;
}
solução Ex. 3
y = 110

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 da string. Veja o exemplo abaixo.

#include <stdio.h>

int main(void)
{
   char x[10]="ifsc";
   char alfa='X', *p;

   p = &alfa;    /* p aponta para alfa */

   printf("O caracter apontado por p é %c", *p);

   p = &x[2];    /* p aponta para o caracter que está 
                     na posição 2 do vetor x */

   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++;
   }
    
   return 0;	
}

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).

EXERCÍCIO: Sem executar o programa abaixo, determine o valor de y no final do programa:

int main(void)
{
   char x[10]="ifsc";
   char *p, y;
   
   p = x + 2;
   y = *p;
   return 0;
}
solução
y = 's'

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. Notar que o ponteiro na prática deve apontar para um elemento específico do vetor. Se o ponteiro for incrementado ele apontará para o próximo elemento.

#include <stdio.h>

int 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++;       
   }
   return 0;	
}
OBSERVE que p++ incrementa em 4 unidades.

Usando ponteiro na passagem de parâmetros

Observe como podemos usar ponteiros na passagem de parâmetros. O exemplo abaixo mostra a passagem de dois vetores para a função str_cpy. Os dois parâmetros formais da função são ponteiros para char. Pode-se analisar o código da seguinte forma: pdest e pfonte são parâmetros (varíaveis) que recebem os endereços dos vetores destino e fonte. Desta forma, é possível manipular as strings contidas nestes vetores através dos parâmetros pdest e pfonte.

#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;
}

int main(void)
{
   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));
   return 0;
}

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

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

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);
}

Exercícios

  1. Rever a aula da UFMG em Link Aula Ponteiros UFMG e fazer os exercícios de fixação. Obs: Se necessário, ao ler no browser, troque a codificação de UTF8 para Ocidental. Eu tive problemas na leitura da página.
  2. Implemente um programa que realize o swap de duas variáveis inteiras passadas como parâmetro. Use ponteiros.
  3. Implementar a função str_cat cujo esqueleto é fornecido abaixo, de forma a concatenar duas strings passadas como parâmetro através de ponteiros. A segunda string deve ser colocada no final da primeira string. A função deve retornar um ponteiro para a string concatenada.
    char *str_cat(char *p1, const char *p2)
    {
    
    }
    
    /* exemplo de uso da função */
    int main()
    {
      char vet1[10]="IFSC";
      char vet2[5]="-SC";
      
      p = str_cat(vet1,vet2);
      printf("%s",vet1); /* aqui deveria imprimir "IFSC-SJ" */
      printf("%s",p);    /* aqui também deveria imprimir "IFSC-SJ" */
      return (0);
    }
    
    solução A:
    #include <stdio.h>
     
    char *str_cat(char *p1, const char *p2)
    {
      char *pdest;
    
      pdest = p1; /*salva o ponteiro mpara o inicio */
    
      while (*p1 != '\0')
              p1++; /* encontra o final da string 1 */
    
    
      while(*p2 != '\0' ){ /* copia até o final da string apontada por p2 */
         *p1++ = *p2++;
      };
    
      *p1 = '\0'; /* coloca o NULL no final da string concatenada */
    
      return pdest;
    }
     
    /* exemplo de uso da função */
    int main(void)
    {
      char vet1[30]="IFSC";
      char vet2[20]="-SJ";
     
      printf("%s\n",str_cat(vet1,vet2));
      return (0);
    }
    
    solução B:
    #include <stdio.h>
     
    char *str_cat(char *p1, char *p2)
    {
      char *pdest = p1;
    
      while (*p1)
        p1++;  /* localiza po final da string */
      while (*p1++ = *p2++) /* copia, avalia a expressão - se 0 encerra o while - incrementa os ponteiros */
          ;
      return pdest;
    }
     
    /* exemplo de uso da função */
    int main(void)
    {
        char vet1[30]="IFSC";
        char vet2[20]="-SJ";
        char *p;
    
        p = str_cat(vet1,vet2);
        printf("%s\n",p);     
        printf("%s\n",vet1);
        return (0);
    }
    
    Solução C:
    #include <stdio.h>
     
    /* extraído do site stackoverflow */
    char *str_cat(char *p1, char *p2)
    {
        int i,j;
        for (i = 0; p1[i] != '\0'; i++)
            ;   /* Localiza o final da string - no final i contém o índice do NULL */ 
        for (j = 0; p2[j] != '\0'; j++)
            p1[i+j] = p2[j]; /* faz a cópia - no final j contém o ídnice do NULL*/
        p1[i+j] = '\0';
        return p1;
    }
     
    /* exemplo de uso da função */
    int main(void)
    {
      char vet1[30]="IFSC";
      char vet2[20]="-SJ";
      char *p;
    
      p = str_cat(vet1,vet2);
      printf("%s\n",p);     
      printf("%s\n",vet1);
      return (0);
    }
    
  4. 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.
    solução Ex. 4
    #include <stdio.h>
    
    int main(void)
    {
      float x,y;
      float *p1,*p2;
    
      p1=&x,
      p2=&y;  
      printf("Entre com número 1\n");
      scanf("%f",p1);
      printf("Entre com número 2\n");
      scanf("%f",p2);
      *p1=*p1+*p2;
      printf("valor de x é %f\n", x);
    }
    
  5. 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.
    solução Ex. 5
    //Autor:Victor Cesconetto de Pieri
    #include <stdio.h>
    
    int str_cmp(char * p1, char * p2) {
    
      while ( * p1 != 0 || * p2 != 0) {
    
        if ( * p1 == * p2) { //compara os conteúdos apontados por p1 e p2
          p1++; //próxima posição de p1
          p2++; //próxima posição de p2    	 
          //retorna 1 se forem diferentes
        } else {
          return 1;
        } //se percorrer a string totalmente e nao encontrar nada diferente retorna 0          
    
      }
      return 0;
    }
    
    int main(void) {
      char vet1[20] = "IFSC";
      char vet2[20] = "IFSCC";
    
      printf("%d\n", str_cmp(vet1, vet2));
      return (0);
    }
    
  6. 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.
    void converte_polar_retang(float *parte1, float *parte2)
    {
    }
    
    int main(void)
    {
      float num1=1.5, num2=10.6;
    
      /*chamar a função aqui */
    
      /* imprimir os valores de num1 e num2 aqui */
    }
    
    solução Ex. 6
    #include <stdio.h>
    #include <math.h>
    
    void converte_polar_retang(float *parte1, float *parte2)
    {
    	float real, img;
    	real = *parte1 * cos(*parte2);//parte real
    	img = *parte1 * sin(*parte2);//parte imaginaria
    	*parte1 = real;
    	*parte2 = img;
    }
     
    int main(void)
    {
      float num1=1.5, num2=10.6;
     
      /*chamar a função aqui */
      converte_polar_retang(&num1,&num2);   // passa-se o endereço das variáveis como parâmetro
      
      /* imprimir os valores de num1 e num2 aqui */
      printf("%f %f\n",num1,num2);
      return (0);
    }
    
  7. Implementar 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 estar maiúsculos (caso elas contenham letras minúsculas).
    void capitaliza(char *c1, char *c2)
    {
    }
    
    int main(void)
    {
      char alfa='a', beta='b';
    
      capitaliza(&alfa, &beta);
      
      /* aqui os valores de alfa e beta deverão ser A e B */
    }
    
    solução Ex. 7
    #include <stdio.h>
    
    void capitaliza(char *c1, char *c2)
    {
    *c1 = *c1-32;//subtrai do valor do char -32 para transformar o 'a' em 'A'
    *c2 = *c2-32;
    }
     
    int main(void)
    {
      char alfa='a', beta='b';
     
      capitaliza(&alfa, &beta);
    
      printf("alfa : %c e beta: %c\n",alfa,beta);
     
      /* aqui os valores de alfa e beta deverão ser A e B */
    }
    
  8. 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)
    {
    }
    
    main()
    {
      char *p="123";
      int x;
    
      x = a_toi(p);
      
      /* neste ponto x deve conter 123 */
    }
    
    solução Ex. 8
  9. Construir uma função usando ponteiros que retorna a média de um vetor de inteiros passado como parâmetro. O tamanho do vetor também deve ser fornecido.
    float media_vet(int *vet, int tamanho)
    {
    }
     
    /* exemplo de uso */
     
    main()
    {
       int x[10]= {0,1,29,3,42,5,61,7,82,9};
       float media;
     
       media = media_vet(x,10); /* em media_vet deve ficar a média do vetor */
    }
    
    solução Ex. 9
    float media_vet(int *vet, int tamanho)
    {
    float media, total;
    int i;
    for(i=0;i<tamanho;i++){
        total = total+*vet;
        printf("tao : %f\n",*vet);
        vet++;
    }
    
    media = total/tamanho;
    
    }
     
    /* exemplo de uso */
     
    main()
    {
       int x[10]= {0,1,29,3,42,5,61,7,82,9};
       float media;
     
       media = media_vet(x,10); /* em media_vet deve ficar a média do vetor */
       //printf("%f\n",media);
    }