PR1022804 2025 1 AULA11: 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 1: Linha 1:
=Listas Encadeada=
==Ponteiros==


;PARA PENSAR


;OBJETIVOS
*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.


:O aluno deverá conhecer:
;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.


:*Listas encadeadas;  
<blockquote style="background:#FAF0E6; border: 2px solid #A020F0; margin-left: 250px; margin-right: 250px; padding: 2em;">
:*Algumas aplicações.


;ATENÇÃO:<span style="color:red;">'''Seu professor adverte: O uso descuidado de ponteiros pode causar dor de cabeça!</span>


;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.
</blockquote>




;INTRODUÇÃO: A Lista Encadeada nada mais é que uma representação de uma sequência de objetos, do mesmo tipo, na memória do computador. Cada elemento da sequência é armazenado em uma célula da lista: o primeiro elemento na primeira célula, o segundo na segunda e assim por diante. ''Linked list'' ou lista encadeada e um tipo de estrutura de dados que contém um grupo de nós (conjunto de dados) interligados através de ponteiros, onde o ponteiro dentro da estrutura aponta para o próximo nó até que o ponteiro seja '''NULL''' indicando assim o fim da lista.
===Ponteiro para inteiro===


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


Uma lista encadeada  (''linked list'') é uma sequência de células onde cada célula contém um objeto de algum tipo e o endereço da célula seguinte.
<syntaxhighlight lang=c>
#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);
}
</syntaxhighlight>


Vamos supor que os objetos armazenados nas células são do tipo '''int'''. A estrutura de cada célula de uma determinada lista pode ser definida assim:
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:
<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
struct cel {
void main()
    int conteudo;  
{
    struct cel *prox;
  int x=10;
};
  int y, *p;
 
}
</syntaxhighlight>
</syntaxhighlight>
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:
<syntaxhighlight lang=c>
void main()
{
  int x,y,w,*p1,*p2;
  x = 20;
  w = 30;
  p1 = &x;
  p2 = &w;
  y = *p1 + *p2;
}
</syntaxhighlight>


{| border="1" cellpadding="5" cellspacing="0"
;EXEMPLO 3: Tente inferir qual seria o valor da variável y no final do programa abaixo:
! style="background: #FAF0E6;" | 123
<syntaxhighlight lang=c>
! style="background: #FAF0E6;" | -->
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;
}
</syntaxhighlight>


;EXEMPLO 4: Qual seria o valor das variáveis '''y''' e '''x''' no final do programa abaixo:
<syntaxhighlight lang=c>
#include <stdio.h>


;SENDO:
void main()
:'''123''': conteudo
{
:'''-->''': *prox
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);
}
</syntaxhighlight>


É conveniente tratar as células como um novo '''tipo de dados''' (struct) e atribuir um nome a esse novo tipo:
 
===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.


<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
typedef struct cel celula; // célula
#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++;
  }
}
</syntaxhighlight>
</syntaxhighlight>


Uma célula  c  e um ponteiro p para uma célula podem ser declarados assim:
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).


celula  c;
;EXEMPLO: Sem executar o programa abaixo, determine o valor de y no final do programa:
celula *p;
<syntaxhighlight lang=c>
void main()
{
  char x[10]="ifsc";
  char *p, y;
 
  p = x + 2;
  y= *p;
}
</syntaxhighlight>




Se '''c''' é uma célula então  '''c.conteudo'''  é o conteúdo da célula e  '''c.prox'''  é o endereço da próxima célula.  Se  '''p''' é o endereço de uma célula, então  '''p->conteudo'''  é o conteúdo da célula e  '''p->prox'''  é o endereço da próxima célula. Se '''p''' é o endereço da última célula da lista então: '''p->prox''' vale  '''NULL'''.
===Apontando para um vetor de inteiros===


{| border="1" cellpadding="5" cellspacing="0"
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.
! style="background: #FAF0E6;" | 123
! style="background: #FAF0E6;" | -->
<syntaxhighlight lang=c>
! style="background: #FAF0E6;" | 234
#include <stdio.h>
! style="background: #FAF0E6;" | -->
! style="background: #FAF0E6;" | 345
! style="background: #FAF0E6;" | -->
! style="background: #FAF0E6;" | 456
! style="background: #FAF0E6;" | -->
! style="background: #FAF0E6;" | 567
! style="background: #FAF0E6;" | -->
! style="background: #FAF0E6;" | 678
! style="background: #FAF0E6;" | NULL
|}


==Listas com cabeça e sem cabeça==
void main()
{
  int x[10]= {0,1,2,3,4,5,6,7,8,9};
  int *p;
  int i;
 
  p = x;


Uma lista encadeada pode ser organizada de duas maneiras diferentes.
  i=0;
  while (i<10) {
      printf(" endereco %p e conteudo %d\n", p, *p);
      p++;
      i++;     
  }
}
</syntaxhighlight>
 
;OBSERVE: Que p++ incrementa em 4 unidades.


;LISTA COM CABEÇA:  O conteúdo da primeira célula é irrelevante: ela serve apenas para marcar o início da lista. A primeira célula é a cabeça (= ''head cell'' = ''dummy cell'') da lista.  Digamos que ini é o endereço da primeira célula. Então  ini->prox == NULL se e somente se a lista está vazia. Para criar uma lista vazia, basta fazer:


celula c, *ini;
===Usando ponteiro na passagem de parâmetros===
c.prox = NULL;
ini = &c;


ou, se preferir alocar a primeira célula dinamicamente,
Observe como podemos usar ponteiros na passagem de parâmetros.


celula *ini;
<syntaxhighlight lang=c>
ini = malloc(sizeof (celula));
#include <stdio.h>
ini->prox = NULL;
 
void str_cpy(char *pdest, char *pfonte)
{
  while (*pfonte!=0) {
        *pdest++ = *pfonte++;
  }
  *pdest = 0;
}


;LISTA SEM CABEÇA:  O conteúdo da primeira célula é tão relevante quanto o das demais. Nesse caso, a lista está vazia se o endereço de sua primeira célula é NULL.  Para criar uma lista vazia basta fazer:


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


É preferível as listas sem cabeça porque são mais simples, porém, a vida do programador fica mais fácil quando as listas têm cabeça.
void main()
{
  char fonte[10]="ifsc";
  char destino[10];


;EXEMPLOS: Para imprimir o conteúdo de uma lista encadeada com cabeça:
  str_cpy(destino, fonte);
  printf("string destino = %s\n", destino);
 
  printf("tamanho de dest = %d\n", str_len(destino));
}
</syntaxhighlight>
 
Um ponto interessante é que ponteiros permitem, na chamada de uma função, passar valores por referência:


<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
// Imprime o conteúdo de uma lista encadeada
// com cabeça. O endereço da primeira célula é ini.


void imprima(celula *ini) {
void alfa(int *p)
  celula *p;
{
  for (p = ini->prox; p != NULL; p = p->prox)  
  *p=10;
      printf( "%d\n", p->conteudo);
}
 
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);
}
}
</syntaxhighlight>
</syntaxhighlight>


:Mesma função para lista sem cabeça:
 
===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.


<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
// Imprime o conteúdo de uma lista encadeada ini.
#include <stdio.h>
// A lista não tem cabeça.


void imprima(celula *ini) {
void main()
  celula *p;
{
  for (p = ini; p != NULL; p = p->prox)  
float fpi=3.1415, *pf, **ppf;
      printf( "%d\n", p->conteudo);
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
}
}
</syntaxhighlight>
</syntaxhighlight>


;NOTE: Que o tipo de dados '''ini''' não inicializa no próximo (ini->prox) como no exemplo acima.
;NOTE: Para acessar o valor apontado por um ponteiro para ponteiro, o operador asterisco deve ser aplicado duas vezes.


==Busca em uma lista encadeada==
==Vetor de ponteiros==


Veja como é fácil verificar se um inteiro x pertence a uma lista encadeada, ou seja, se é igual ao conteúdo de alguma célula da lista:
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:


<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
// Esta função recebe um inteiro x e uma lista
#include <stdio.h>
// encadeada ini de inteiros, com celula-cabeça.
// A função devolve o endereço de uma celula que
// contém x ou devolve NULL se tal celula não
// existe.


celula *busca( int x, celula *ini)
int main()
{
{
  celula *p;
  int i;
  p = ini->prox;
 
  while (p != NULL && p->conteudo != x)
  char *vp[4];
      p = p->prox;  
  char alfa[5]="IFSC";
  return p;  
  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]);
}
}
</syntaxhighlight>
</syntaxhighlight>


=Exercícios=
[[imagem:Fig1Aula24PrgITele.jpg|700px]]
 
Observe que vp é um vetor de ponteiros para char e cada elemento aponta para uma cadeia de caracteres.
 
===Argumentos de linha de comando===


Por vezes não se conhece o tamanho dos dados que se vai manipular e o uso de uma lista pode ser conveniente para
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.
armazená-los. Um sistema de estoque de produtos, por exemplo, poderia ser armazenado na forma de uma lista.


;EXEMPLO: de lista ligada.
;EXEMPLO: Teste o programa abaixo:


<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>


/*========================*/
int main(int argc, char *argv[])
/** OPERAÇÔES COM LISTA LIGADA ******/
{
/*========================*/
  int i;


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


struct TProduto{
===Apontando para estruturas===
  int codigo;
  struct TProduto *next;
} *head, *tail;


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


/*
<syntaxhighlight lang=c>
  adiciona item a cabeça da lista
#include <stdio.h>
  retorna 0 se tudo ok e -1 se erro
*/
int add_nodo_head(int codigo)
{


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


/*
struct TRegistro *p;
  adiciona item ao final  lista
 
  retorna 0 se tudo ok e -1 se erro
void main()
*/
int add_nodo_tail(int codigo)
{
{
  struct TProduto *p = malloc (sizeof(struct TProduto));
  p = &Tabela[3]; /*p aponta para o registro 3 da tabela */
  if (!p)
  printf("O nome na posição 3 é %s e idade = %d\n", p->nome,p->idade);
        return -1;
}
</syntaxhighlight>
 
;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===


  p->codigo = codigo;
No exemplo a abaixo a função ''RetornarStruct()'' retorna um ponteiro para uma estrutura.
  p->next = NULL;
O cuidadado que se deve ter é que a função não deveria apontar para uma estrutura que foi criada localmente
na função!


  if (tail==NULL) {
<syntaxhighlight lang=c>
      /* lista vazia */
#include <stdio.h>
      tail = head = p;
struct TRegistro {
  }else {
  char nome[20];
    /*lista não vazia */
  int idade;
      tail->next = p;
} Tabela[4] = {
      tail = p;
          {"joao",18,},
  }
          {"maria",18,},
  return 0;
          {"jose",19,},
}
          {"lara",17,},
};


/*
struct TRegistro *p;
  imprimir lista
*/


void print_list(struct TProduto *ini)
struct TRegistro * RetornarStruct(int indice)
{
{
      struct TProduto *p;
  return &Tabela[indice];
      for (p = ini->next; p != NULL; p = p->next)
      printf( "%d\n", p->codigo);
}
}
 
void main()
void main()
{
{
   int i;
   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);
}
</syntaxhighlight>
 
===Passando uma estrutura como parâmetro===


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


  for (i=0;i<5;i++)
struct TRegistro *p;
    add_nodo_tail(i);


  print_list (head);
void MudarStruct(struct TRegistro *p1, int indice)
{
  Tabela[indice] = *p1;
}
}
</syntaxhighlight>


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


;EXERCÍCIO 1: Para o exemplo anterior:
  MudarStruct(&aux,2);
  p = &Tabela[2];
  printf("O nome na posição 2 é %s e idade = %d\n", p->nome,p->idade);
}
</syntaxhighlight>


* Implementar a função add_node_head()
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.
* Implementar a função print_list()
* Implementar a função delete_node(int codigo)


=Exercícios=


;EXERCÍCIO 2: Considere um sistema de estoque de uma livraria representado por uma tabela conforme abaixo. Elabore as funções para adicionar, remover e listar um livro na/da tabela. Considere que uma entrada livre possui o ponteiro titulo igual a NULL.
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.
 
{{collapse top|bg=#E6E6FA|Solução 1}}
<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
#include <stdio.h>
#include <stdio.h>
#define TAM 10
#include <string.h>
/**********************************************/
/*** PROGRAMA DE CONTROLE DE ACESSO  **/
/** Autor: Turma ENG.TELECOM - 2013.1 */
/**********************************************/
   
   
struct tLivro {
/** VARIÁVEIS GLOBAIS DESTE MÓDULO ****/
  char *titulo;
  char *autor;
struct TRegistroUsuario {
  char *isbn;
char UserId[10];
  float *preco;
char Senha[10];
  int estoque;
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");
}


typedef struct tLivro TLivro;
/** 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;
      }         
  }
}
   
   
TLivro Livros[10]; /* iniciar a tabela com NULL */
/** Função que valida um usuário e abre a porta **/
   
   
 
void tratar_usuario()
TLivro *retornar_entrada_livre()
{
{
  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");
  }
}
}
   
   
int adicionar_livro()
void main()
{
{
  char aux_isbn[20];
  for(;;) {
  TLivro *p;
    mostrar_menu_entrada_usuario();
    scanf("%s",userID);
    if (strcmp(userID, "admin")==0) {
          administrar();
    } else {
        tratar_usuario();
    }
 
}
</syntaxhighlight>
{{collapse bottom}}
2. Implementar uma funcionalidade do administrador para desbloquear o usuário bloqueado.


  /* Ler ISBN */
{{collapse top|bg=#E6E6FA|Solução 2}}
if(verificar_livro_existe(aux_isbn)==1)
<syntaxhighlight lang=c>
    return 0;
#include <stdio.h>
  if((p=retornar_entrada_livre())==NULL)
#include <string.h>
    return -1;
   
/**********************************************/
/*** PROGRAMA DE CONTROLE DE ACESSO          */
/** Autores: Daniel Trevisan Tatsch          */
/**          Ricardo Amorim                  */
/**********************************************/
   
/** VARIÁVEIS GLOBAIS DESTE MÓDULO ****/
   
   
  /* Ler os dados do livro pelo teclado e colocar na estrutura
struct TRegistroUsuario {
    apontada por p*/
    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");
}
}
   
   
/* retorna 0 se removido com sucesso e -1 caso contrário */
/** Função que implementa as tarefas do administrador **/
int remover_livro(char *isbn)
void administrar()
{
{
 
    int i;
    for(i=0;i<4;i++)
TabelaUsuarios[i].ativo=1;
    printf("\nTodos os usuários foram liberados!\n");
}
}
   
   
void imprimir_dados_livro(char *isbn)
/** 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. 
}
}
   
   
main()
void main()
{
{
  /* testar as funções aqui */
  for(;;) {
    mostrar_menu_entrada_usuario();
    scanf("%s",userID);
    if (strcmp(userID, "admin")==0) {
          administrar();
    } else {
        tratar_usuario();
    }
}
}
</syntaxhighlight>
</syntaxhighlight>
{{collapse bottom}}
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! <br>
4. Implementar na função administrar a inserção da mensagem no exercício anterior.<br>
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.<br>
6. Implementar a função ''str_cat'' que concatena duas ''strings'' usando ponteiros.


;EXERCÍCIO 3: Refazer o exercício anterior usando filas.
7. Ordenar valores de um vetor de inteiros passando por referencia o ponteiro para esse vetor.


;EXERCÍCIO 4: Seja a seguinte estrutura:
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'''.


<syntaxhighlight lang=c>
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:
struct tipo_carro {
:cmpcadeia: dois parametros devem ser passados.
  char *marca;
  char *modelo;
  int  potencia;
};


typedef tipo_carro tcarro;
10. Renomeie o executável e veja seja a mensagem de erro mostra o nome correto do programa.
</syntaxhighlight>


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.


:Implementar as funções abaixo:
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).
<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
/* cria dinamicamente uma estrutura,
 
  preenche os dados dos campos
void converte_polar_retang(float *parte1, float *parte2)
  e retorna um ponteiro para a estrutura criada
  Retorna NULL caso não consiga alocar área
*/
void tcarro *ler_carro()
{
{
}


void main()
{
  float num1=1.5, num2=10.6;
  /*chamar a função aqui */
  /* imprimir os valores de num1 e num2 aqui */
}
}
 
</syntaxhighlight>
/*
14. Implemantar uma função que recebe como parâmetro o endereço de duas variáveis do tipo char e
  recebe dois ponteiros para estruturas do tipo carro e
após a chamada da função os valores das variáveis devem ser convertidos para caixa alta (maiúsculas).
  retorna -1 caso pelo menos um dos ponteiros seja NULL,
<syntaxhighlight lang=c>
  retorna 0 se os modelos forem iguais
void main()
  e retorna 1 se os modelos forem diferentes */
int compara_modelo(tcarro *p1, tcarro *p2)
{
{
  char alfa='a', beta='b';


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


/* libera a área da estrutura passada como parâmetro */
</syntaxhighlight>
void deleta_estrutura(tcarro *p)
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.
<syntaxhighlight lang=c>
 
int a_toi(char *p)
{
{
}
}


void main()
void main()
{
{
   /*testar as funções aqui */
   char *p="123";
   /* criar dois carros */
  int x;
   /* comparar o modelo dos dois carros. Testar o retorno */
 
   /* liberar a área das estruturas */
   x = a_toi(p);
    
   /* neste ponto x deve conter 123 */
}
}
</syntaxhighlight>
</syntaxhighlight>
 
16. O código abaixo implementa a série responsável pelo cálculo da raiz quadrada de um número.
==EXEMPLO DA AULA==
 
<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>


struct TFicha {
float raiz_quadrada(float numero);
    int codigo;
    char nome[40];
    char fone[20];
    struct TFicha *prox;
} *cliente,*cabeca;


void Cadastrar(){
int main( int argc, char **argv)
struct TFicha *p =  malloc (sizeof(struct TFicha));
{
     printf("\nDigite codigo: ");
    float numero;
     scanf("%d",&p->codigo);
 
     printf("\nDigite Nome: ");
     printf("Entre com um número positivo por favor : ");
    fflush(stdin);
     scanf("%f",&numero);
    scanf("%[^\n]",p->nome);
 
    printf("\nDigite Telefone: ");
     printf("A raiz quadrada de %.3f é %.5f \n",numero,raiz_quadrada(numero));
    fflush(stdin);
    scanf("%[^\n]",p->fone);


     if (cliente==NULL) {
     return(0);
      /* lista vazia */
      cliente = cabeca = p;
  }else {
    /*lista não vazia */
      cliente->prox = p;
      cliente = p;
  }
}
}


void Imprimir(struct TFicha *ini) {
 
  struct TFicha *p;
float raiz_quadrada (float numero)
  printf("\n\nCodigo  Nome                Fone");
{
   for (p = ini; p != NULL; p = p->prox){
    int n;
      printf( "\n%-d", p->codigo);
    float recorre = numero;
      printf( "\t%-20s", p->nome);
    
      printf( "\t%-20s", p->fone);
    for (n = 0; n < 10; ++n)
   }
          recorre = recorre/2 + numero/(2*recorre);
         
    return(recorre);   
}   
</syntaxhighlight>
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.
<syntaxhighlight lang=c>
#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]);


void main(){
     printf("\n%.4f \n",raiz_quadrada(numero));
 
    cliente=NULL;
    return(0);
    int opcao;
     while (1){
        printf("\n\nEscolha:\n");
        printf("1 - Cadastrar\n");
        printf("2 - Imprimir\n");
        printf("3 - Sair\n");
        printf("-> ");
        scanf("%d",&opcao);
        switch (opcao)
        {
        case 1:
                Cadastrar(cliente);
                break;
            case 2:
                Imprimir(cabeca);
                break;
            case 3:
                return 0;
        }
    }
}
}
</syntaxhighlight>
</syntaxhighlight>
Linha 413: Linha 776:
=Referências=
=Referências=


[1] http://www.ime.usp.br/~pf/algoritmos/aulas/lista.html
[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





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

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

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.

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

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.

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

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.

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

4 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