PR1022804 2025 1 AULA10: mudanças entre as edições

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
Douglas (discussão | contribs)
Douglas (discussão | contribs)
Sem resumo de edição
Linha 7: Linha 7:
:*Criar uma Estrutura;
:*Criar uma Estrutura;
:*Passar uma Estruturas por parâmetro;
:*Passar uma Estruturas por parâmetro;
:*Inicializar dados em estruturas;  
:*Inicializar dados em estruturas; e
:*Fazer cópias de estruturas;
:*Fazer cópias de estruturas.
:*Definir e utilizar ponteiros;
:*Definir um vetor de ponteiros;
:*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.
;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.


;INTRODUÇÃO: O C foi desenvolvido quando os computadores eram muito menos potentes do que são hoje e menos eficiente com relação a velocidade e ao uso de memória que – muitas vezes não era apenas desejável – mas vital. A capacidade "bruta" de trabalhar com locais de memória específicos era obviamente uma opção útil. Algumas tarefas hoje em dia, como programar microcontroladores, ainda precisam disso. No entanto, a maioria dos programadores modernos não precisa de um controle tão preciso e as complicações do uso de ponteiros tornam os programas menos claros para serem entendidos e aumentam as maneiras pelas quais eles podem dar errado. Então, por que os ponteiros ainda são tão usados ​​em C e em seu sucessor, C++? Descubra você.
;INTRODUÇÃO: Na linguagem C é possível criar tipos de dados que representam uma estrutura. Dessa forma podemos dizer que uma estrutura agrupa várias variáveis numa só. Funciona como uma ficha pessoal que tenha nome, telefone e endereço. Uma ficha seria uma estrutura.  
 
==Estruturas==
 
Na linguagem C é possível criar tipos de dados que representam uma estrutura. Dessa forma podemos dizer que uma estrutura agrupa várias variáveis numa só. Funciona como uma ficha pessoal que tenha nome, telefone e endereço. Uma ficha seria uma estrutura.  


Para se criar uma estrutura usa-se o comando '''struct'''. Sua forma geral é:
Para se criar uma estrutura usa-se o comando '''struct'''. Sua forma geral é:

Edição das 18h55min de 3 de julho de 2025

1 Estruturas (struct) | Ponteiros (pointers)

OBJETIVOS
O aluno deverá saber:
  • Criar uma Estrutura;
  • Passar uma Estruturas por parâmetro;
  • Inicializar dados em estruturas; e
  • Fazer cópias de 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.
INTRODUÇÃO
Na linguagem C é possível criar tipos de dados que representam uma estrutura. Dessa forma podemos dizer que uma estrutura agrupa várias variáveis numa só. Funciona como uma ficha pessoal que tenha nome, telefone e endereço. Uma ficha seria uma estrutura.

Para se criar uma estrutura usa-se o comando struct. Sua forma geral é:

struct nome_do_tipo_da_estrutura
{
    tipo_1 nome_1;
    tipo_2 nome_2;
    ...
    tipo_n nome_n;
} variáveis_estrutura;

O nome_do_tipo_da_estrutura é o nome para a estrutura. As variáveis_estrutura são opcionais e seriam nomes de variáveis que o usuário já estaria declarando e que seriam do tipo nome_do_tipo_da_estrutura.

EXEMPLO 1

Vamos criar uma estrutura de endereço:

struct tipo_endereco
{
   char rua [50];
   int numero;
   char bairro [20];
   char cidade [30];
   char sigla_estado [3];
   long int CEP;
};
EXEMPLO 2

No exemplo abaixo vamos ver a estrutura tipo usuáiro para ser utilizada no controle de acesso:

#include <stdio.h>

struct TUsuario /* struct TUsuario é o nome do tipo que está sendo criado */
{ 
  char userID[20];
  char senha[20];
} Usuario; /* aqui é definida uma variável do  tipo struct TUsuario */

struct TUsuario TabelaUsuario[20];

void main()
{
  scanf("%s", Usuario.userID);
  scanf("%s", Usuario.senha);
  scanf("%s", TabelaUsuario[10].userID);
  scanf("%s", TabelaUsuario[10].senha);
}

Neste exemplo, foi definido um tipo (modelo) para o registro (struct TUsuario) e foi criada uma variável chamada Usuario a partir deste tipo. Na sequência foi criada mais uma variável (um vetor de estruturas) chamada TabelaUsuario. Note que basta usar as palavras chave struct Usuario para criar novas variáveis. O tipo completo é definido uma única vez no início.

EXERCÍCIOS
  1. Criar um programa que define uma struct para armazenamento do nome e das notas bimestrais de um aluno. Atualizar a estrutura usando o scanf.
  2. Alterar o programa para que ele calcule e imprima a média de cada aluno.
Resposta
#include <stdio.h>

#define NUM_MAX 3

struct TAluno {
  char nome[30];
  char matricula[11];
  float b1,b2,b3,b4;
} Turma[NUM_MAX];

void print_aluno(struct TAluno aux)
{
  printf("Nome -> %s\n", aux.nome);
  printf("Matrícula -> %s\n", aux.matricula);
  printf("Bimestre 1 -> %f\n", aux.b1);
  printf("Bimestre 2 -> %f\n", aux.b2);
  printf("Bimestre 3 -> %f\n", aux.b3);
  printf("Bimestre 4 -> %f\n", aux.b4);          
}

void main()
{
  int i;
  
  for(i=0;i<NUM_MAX;i++) {
  	printf("Entre com o nome do aluno\n");
  	scanf("%s", Turma[i].nome);
  	printf("Entre com a matrícula do aluno\n");
  	scanf("%s", Turma[i].matricula);
  	printf("Entre com a nota do bimestre 1\n");
  	scanf("%f", &Turma[i].b1);
  	printf("Entre com a nota do bimestre 2\n");
  	scanf("%f", &Turma[i].b2);
  	printf("Entre com a nota do bimestre 3\n");
  	scanf("%f", &Turma[i].b3);
  	printf("Entre com a nota do bimestre 4\n");
  	scanf("%f", &Turma[i].b4);
  }
  for(i=0;i<NUM_MAX;i++) {
    printf("=========== Aluno %d ============\n", i);  
  	print_aluno(Turma[i]); 
  }      
}

1.1 Copiando estruturas

O exemplo a seguir demonstra como se pode copiar uma variável struct para outra do mesmo tipo.

#include <stdio.h>
  
struct THoras{
   int hora;
   int minuto;
   int segundo;
};

struct THoras Ontem = {2,10,57};

void main()
{
     struct THoras Hoje;
     Hoje = Ontem;

     printf("Hora hoje = %d, Minuto hoje = %d e Segundo hoje %d\n", Hoje.hora, Hoje.minuto, Hoje.segundo);
}

1.2 Estruturas dentro de estruturas

Vamos ver um exemplo com estruturas definidas dentro de estruturas:

#include <stdio.h>
  
struct TEndereco{
     char rua[50];
     char numero[10];
};

struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
  int num_filhos;
};

void main()
{
  struct TCidadao Cidadao;

  printf("Entre com o nome\n");
  scanf ("%s",Cidadao.nome); // substitua por gets()

  printf("Entre com o cpf\n");
  scanf ("%s",Cidadao.cpf);

  printf("Entre a rua\n");
  scanf ("%s",Cidadao.endereco.rua); // substitua por gets()

  printf("Entre a numero\n");   
  scanf ("%s",Cidadao.endereco.numero);

  printf("Entre com o número de filhos\n");
  scanf ("%d",&Cidadao.num_filhos);
  
}

Exercício 1: Faça um código adicional para imprimir o conteúdo lido na estrutura.


Resposta
#include <stdio.h>
 
struct TEndereco{
     char rua[50];
     char numero[10];
};
 
struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
  int num_filhos;
};

void print_endereco(struct TEndereco aux)
{
  printf ("Rua %s Número %s\n", aux.rua, aux.numero); 
}

void print_cidadao(struct TCidadao aux)
{
  printf("Nome: %s CPF: %s ", aux.nome, aux.cpf);
  print_endereco(aux.endereco);
  printf("Numero de filhos %d\n", aux.num_filhos);
}

void main()
{
  struct TCidadao Cidadao;
 
  printf("Entre com o nome\n");
  scanf ("%s",Cidadao.nome);
 
  printf("Entre com o cpf\n");
  scanf ("%s",Cidadao.cpf);
 
  printf("Entre a rua\n");
  scanf ("%s",Cidadao.endereco.rua);
 
  printf("Entre a numero\n");   
  scanf ("%s",Cidadao.endereco.numero);
 
  printf("Entre com o número de filhos\n");
  scanf ("%d",&Cidadao.num_filhos);
 
}

1.3 Iniciando estruturas na definição

Como toda variável, é possível dar valores para uma variável do tipo struct definida no programa:

#include <stdio.h>
 
struct TEndereco{
     char rua[50];
     char numero[10];
};
 
struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
  int num_filhos;
};
 
void main()
{
  struct TCidadao Cidadao = {"Maria",
                             "42342342234",
                             {"Rua AlfaBeta","145"},
                             5
                            };
 
  printf("Rua do cidadao = %s\n", Cidadao.endereco.rua);
 
}

1.4 Passando estruturas como parâmetro e retornando estruturas

Se não for usado o operador "&" , um parâmetro que é estrutura será passado por cópia. Não apresentaremos agora a passagem por endereço pois necessita do conceito de ponteiro. Observe o exercício abaixo.

#include <stdio.h>
  
struct TEndereco{
     char rua[50];
     char numero[10];
};

struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
  int num_filhos;
};

void print_struct (struct TCidadao aux)
{
  printf("nome=%s cpf=%s\n", aux.nome, aux.cpf);
  printf("endereço inicial do aux %p\n", &aux);
}

void main()
{
  struct TCidadao Cidadao;

  printf("Entre com o nome\n");
  scanf ("%s",Cidadao.nome);

  printf("Entre com o cpf\n");
  scanf ("%s",Cidadao.cpf);

  printf("Entre a rua\n");
  scanf ("%s",Cidadao.endereco.rua);

  printf("Entre a numero\n");   
  scanf ("%s",Cidadao.endereco.numero);

  printf("Entre com o número de filhos\n");
  scanf ("%d",&Cidadao.num_filhos);
  
  print_struct(Cidadao);

  printf("endereço inicial do Cidadao %p\n", &Cidadao);
}
O que podemos concluir com os endereços que foram mostrados??? Vamos a mais um exemplo.
#include <stdio.h>
  
struct TEndereco{
     char rua[50];
     char numero[10];
};

struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
  int num_filhos;
};

struct TCidadao ler_struct()
{
  struct TCidadao aux;

  printf("Entre com o nome\n");
  scanf ("%s",aux.nome);

  printf("Entre com o cpf\n");
  scanf ("%s",aux.cpf);

  printf("Entre a rua\n");
  scanf ("%s",aux.endereco.rua);

  printf("Entre a numero\n");   
  scanf ("%s",aux.endereco.numero);

  printf("Entre com o número de filhos\n");
  scanf ("%d",&aux.num_filhos);

  return aux;
}

void print_struct (struct TCidadao aux)
{
  printf("nome=%s cpf=%s\n", aux.nome, aux.cpf);
  printf("endereço inicial do aux %p\n", &aux);
}

void main()
{
  struct TCidadao Cidadao;

  Cidadao = ler_struct();

  print_struct(Cidadao);

  printf("endereço inicial do Cidadao %p\n", &Cidadao);
}

1.5 Aplicação no Controle de Acesso

O exemplo a seguir implementa uma parte do programa de controle de acesso usando estruturas. Neste exemplo a tabela de usuários já vem inicializada nos campos UserID e Senha.

#include <stdio.h>
#include <string.h>
 
/**********************************************/
/*** PROGRAMA DE CONTROLE DE ACESSO  **/
/** Autor: TurmaENG.TELECOM - 2012.2 */
/**********************************************/
 
/** VARIÁVEIS GLOBAIS DESTE MÓDULO ****/

struct TRegistroUsuario {
	char UserId[10];
	char Senha[10];
};

/* Tabela de Usuários */
struct TRegistroUsuario TabelaUsuarios[4] = {
         {"joao","abcd"},
         {"maria","xxxx"},
         {"jose","yyyy"},
         {"lara","zzzz"},
};

 
char userID[20];
 
 
/** FUNÇÔES DESTE MÓDULO ****/
 
void mostrar_menu_entrada_usuario()
{
  printf("*******************************\n");
  printf("Entre com o seu USERID para ter acesso\n"); 
  printf("*******************************\n");
}
 
/** Função que implementa as tarefas do administrador **/
 
void  administrar()
{
}
 
/** Função que valida um usuário e abre a porta **/
 
void tratar_usuario()
{
  char senha[10];
  int userEncontrado=1;
  int i;
 
 
 /* 
     Loop para encontrar o usuário na tabela. 
     Ao final do loop a variavel i conterá o índice do usuário (se ele estiver
     na tabela
  */
  for (i=0;i<4 && userEncontrado; i++) {
       if( strcmp(userID, TabelaUsuarios[i].UserId)==0)
             userEncontrado=0;
  }
 
  /* se usuário encontrado abre a porta */
  if (userEncontrado==0) {
	printf("Bom dia %s! Entre com a senha\n", userID);
  	scanf("%s",senha);
	i--; /* o indice do sujeito é i-1 */
	if(strcmp(senha,TabelaUsuarios[i].Senha)==0) 
	       printf("Abrir porta!!!\n");
	else
		printf("Senha Inválida\n");
  }
}
 
void main()
{
 for(;;) {
     mostrar_menu_entrada_usuario();
     scanf("%s",userID);
     if (strcmp(userID, "admin")==0) {
          administrar();
     } else {
         tratar_usuario();
     }
 }   
}

1.6 Desafios com Structs

DESAFIO 1
Implementar uma função converte_para_polar que recebe como parâmetro um número complexo na forma retangular (representado por uma struct). A função deve retornar uma struct contendo o número complexo na forma polar.Usar as funções sqrtf e atanf da [matemáticas biblioteca matemática]. Como converter:
mod=x2+y2
ϕ=arctanyx ou ϕ=tan1yx
NOTE
Que as funções atanf e similares retornam valores em RADIANOS.
Solução
#include <stdio.h>
#include <math.h>

struct tipo_ret {
 	float x;
 	float y;
};

struct tipo_polar {
 	float mod;
 	float ang;
};


/* Função para converter complexo retangular em polar */

struct tipo_polar converter_ret_pol(struct tipo_ret num_ret)
{
  struct tipo_polar num_polar;
  float aux;
  
  aux = num_ret.x*num_ret.x + num_ret.y*num_ret.y;
  
  /* falta a lógica para detectar o quadrante */
  num_polar.mod = sqrtf(aux);
  num_polar.ang = atanf(num_ret.y/num_ret.x);
  return num_polar; 
}

/* Função para imprimir complexo retangular */
void imprimir_complexo_ret(struct tipo_ret num_ret)
{
  printf("Coordenada x = %f", num_ret.x);
  printf("Coordenada y = %f\n", num_ret.y);
}

/* Função para imprimir complexo retangular */
void imprimir_complexto_pol(struct tipo_ret num_ret)
{
  printf("Coordenada x = %f", num_ret.x);
  printf("Coordenada y = %f\n", num_ret.y);
}

main()
{
  struct tipo_ret num1;
  struct tipo_polar num2;
  
  num1.x = 5;
  num1.y = 10;
  num2 = converter_ret_pol (num1);  
}
DESAFIO 2
Implementar uma função que some dois números complexos no formato retangular e retorne a soma como um complexo retangular.
DESAFIO 3
Implementar uma função que some dois números complexos no formato polar e retorna a soma no formato polar.

1.1 Ponteiros

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!


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


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


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


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


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

1.2 Vetor de ponteiros

Como visto até agora, 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]);
}

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

1.2.1 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" */
}

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

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

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

2 Exercícios

1. Implementar um contador de acesso que permita bloquear o usuário após 3 tentativas seguidas. Note que caso o usuário acerte a senha, este contador deverá ser zerado.

Solução 1
#include <stdio.h>
#include <string.h>
 
/**********************************************/
/*** PROGRAMA DE CONTROLE DE ACESSO  **/
/** Autor: Turma ENG.TELECOM - 2013.1 */
/**********************************************/
 
/** VARIÁVEIS GLOBAIS DESTE MÓDULO ****/
 
struct TRegistroUsuario {
	char UserId[10];
	char Senha[10];
	int contador;
};
 
/* Tabela de Usuários */
struct TRegistroUsuario TabelaUsuarios[4] = {
         {"joao","abcd",0},
         {"maria","xxxx",0},
         {"jose","yyyy",0},
         {"lara","zzzz",0},
};
 
 
char userID[20];
 
 
/** FUNÇÔES DESTE MÓDULO ****/
 
void mostrar_menu_entrada_usuario()
{
  printf("*******************************\n");
  printf("Entre com o seu USERID para ter acesso\n"); 
  printf("*******************************\n");
}

/** Função que implementa as tarefas do administrador **/
 
void  administrar()
{
  char aux_senha[10];
  int userEncontrado=1;
  int i;
    
  printf("Entre com a senha do admin \n");
  scanf ("%s", aux_senha);
  
  if(strcmp(aux_senha,"123456")==0) {
      /* senha valida do admin - agora entre com userid a ser desbloqueado */
      printf("Entre com userdID a ser desbloqueado\n");
      scanf("%s",userID);
      for (i=0;i<4 && userEncontrado; i++) {
         if( strcmp(userID, TabelaUsuarios[i].UserId)==0)
             userEncontrado=0;
      } 
      if (userEncontrado==0) {
         i--;
         TabelaUsuarios[i].contador=0;
      }           
  }
}
 
/** Função que valida um usuário e abre a porta **/
 
void tratar_usuario()
{
  char senha[10];
  int userEncontrado=1;
  int i;
 
 
 /* 
     Loop para encontrar o usuário na tabela. 
     Ao final do loop a variavel i conterá o índice do usuário (se ele estiver
     na tabela
  */
  for (i=0;i<4 && userEncontrado; i++) {
       if( strcmp(userID, TabelaUsuarios[i].UserId)==0)
             userEncontrado=0;
  }
 
  /* se usuário encontrado abre a porta */
  if (userEncontrado==0) {
  	 i--; /* o indice do sujeito é i-1 */
    if (TabelaUsuarios[i].contador<3){
    
	   printf("Bom dia %s! Entre com a senha\n", userID);
  	   scanf("%s",senha);

	   if(strcmp(senha,TabelaUsuarios[i].Senha)==0) {
	       printf("Abrir porta!!!\n");
	       TabelaUsuarios[i].contador=0;
	   }
	   else {
		   TabelaUsuarios[i].contador++;
		   printf("Senha Inválida\n");
		   printf("Tentativas restantes %d\n", 3-TabelaUsuarios[i].contador);
		}
    } else {
      printf("Usuário bloqueado\n");
    }
  } else {
    printf("Usuário não encontrado\n");
  }
}
 
void main()
{
 for(;;) {
     mostrar_menu_entrada_usuario();
     scanf("%s",userID);
     if (strcmp(userID, "admin")==0) {
          administrar();
     } else {
         tratar_usuario();
     }
 }   
}

2. Implementar uma funcionalidade do administrador para desbloquear o usuário bloqueado.

Solução 2
#include <stdio.h>
#include <string.h>
 
/**********************************************/
/*** PROGRAMA DE CONTROLE DE ACESSO           */
/** Autores: Daniel Trevisan Tatsch           */
/**          Ricardo Amorim                   */
/**********************************************/
 
/** VARIÁVEIS GLOBAIS DESTE MÓDULO ****/
 
struct TRegistroUsuario {
    char UserId[10];
    char Senha[10];
    int ativo;
};
 
/* Tabela de Usuários */
struct TRegistroUsuario TabelaUsuarios[4] = {
         {"joao","abcd",1},
         {"maria","xxxx",1},
         {"jose","yyyy",1},
         {"lara","zzzz",1},
};
 
char userID[20];
 
/** FUNÇÔES DESTE MÓDULO ****/
 
void mostrar_menu_entrada_usuario()
{
  printf("\n********************************************");
  printf("\nEntre com o seu USERID para ter acesso: "); 
  printf("\n********************************************\n");
}
 
/** Função que implementa as tarefas do administrador **/
 
void administrar()
{
    int i;
    for(i=0;i<4;i++)
	TabelaUsuarios[i].ativo=1;
    printf("\nTodos os usuários foram liberados!\n"); 
}
 
/** Função que valida um usuário e abre a porta **/
 
void tratar_usuario()
{
  char senha[10];
  int userEncontrado=1;
  int i, cont = 0;
 
 /* 
     Loop para encontrar o usuário na tabela. 
     Ao final do loop a variavel i conterá o índice do usuário (se ele estiver
     na tabela
  */
  for (i=0;i<4 && userEncontrado; i++) {
       if( strcmp(userID, TabelaUsuarios[i].UserId)==0)
             userEncontrado=0;    
  }
  
  if (userEncontrado==0) {  // se usuário encontrado...
      for(;;){
	      if(TabelaUsuarios[i-1].ativo){ // se usuário ativo (1)...
		 printf("Bom dia %s! Entre com a senha\n", userID);
		 scanf("%s",senha);
		 if(strcmp(senha,TabelaUsuarios[i-1].Senha)==0){ // se senha confere (0)...
		    printf("Abrir porta!!!\n");
		    cont=0;
		    break;
		 } else {
		    printf("Senha Inválida\n");
		    cont++;
		    if(cont==3){
		       printf("\nUsuário Bloqueado!\n");    
		       TabelaUsuarios[i-1].ativo = 0;
		       break;
		    }
		 }
	      } else {
		 printf("\nUsuário Bloqueado!\n");  // usuario bloqueado ativo (0)    
		 break;
	      }
	} // fim do for(;;)
  } else
        printf("\nUsuário não encontrado!\n"); // se usuario nao encontrado.   
}
 
void main()
{
 for(;;) {
     mostrar_menu_entrada_usuario();
     scanf("%s",userID);
     if (strcmp(userID, "admin")==0) {
          administrar();
     } else {
         tratar_usuario();
     }
 }   
}

3. No programa de controle de senha inserir um campo na estrutura do usuário de forma a acomodar uma mensagem de boas vindas particularizada para cada usuário. A mensagem "DEFAULT" é Bom dia!
4. Implementar na função administrar a inserção da mensagem no exercício anterior.
5. Na solução acima criar uma função que procura usuário na tabela (já que este código é utilizado em mais do que um luga). A função deve receber o UserID a ser procurado e deve retornar um inteiro correspondente ao índice do usuário encontrado ou -1 se não for encontrado.
6. Implementar a função str_cat que concatena duas strings usando ponteiros.

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

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

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

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

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

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

13. 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 */
}

14. 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 */
}

15. 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 */
}

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

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

3 Referências

[1] https://pt.wikibooks.org/wiki/Programar_em_C/Estruturas

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

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

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