Monitoria de Programação
PRG1 - PROGRAMAÇÃO I
EMENTA
Introdução a lógica de programação e algoritmos. Constantes, variáveis e tipos de dados. Operadores aritméticos, relacionais e lógicos. Concepção de fluxograma e pseudocódigo. Estruturas de decisão e estruturas de repetição. Introdução a linguagem de programação c. Vetores de caracteres e multidimensionais. Ponteiros e aritmética de ponteiros. Funções: chamada por valor e por referência. Chamada recursiva de funções. Tipos de dados compostos. Operação com arquivos textos e binários.
Bibliografia Básica
- SCHILDT, Herbert. C Completo e Total - 3.ed. [S.l.]: Makron, 1997. 830p. ISBN 978-8534605953
Referências Complementares
- Apostila adotada: Curso de Linguagem C - Engenharia Elétrica - UFMG
- Implementar uma função em C que recebe 5 caracteres e retorna o número de ocorrência do caracter 'a'.
- Implementar uma modificação da função do exercício anterior em que o caracter a ser verificado nas ocorrências, é repassado como sexto parâmetro.
Indentação
Exercícios
- Implementar uma FUNÇÂO que converte temperaturas de graus Fahrenheit (passado como parâmetro) para Celsius (retornado).
- Implementar um programa em C para ler dois números inteiros e imprimir uma mensagem indicando se os números lidos são iguais ou diferentes. Caso sejam diferentes, computar a média dos mesmos.
- Implementar um programa para ler 4 números inteiros e imprimir uma mensagem se a soma dos dois primeiros for igual ou menor a soma dos dois últimos.
- Implementar um programa para ler dois números reais e, na sequência, um número inteiro. Se o número inteiro for 1 os dois números iniciais deverão ser somados, se for 2 eles serão subtraídos, se for 3 eles serão multiplicados e se for 4 serão divididos. Mostrar mensagem de erro se o número inteiro não estiver na faixa de 1 a 4. Mostrar mensagem caso a divisão não seja possível.
- Implementar duas FUNÇÕES em C para receber a resistência em ohms de 2 resistores e então calcular a resistência série e paralela dos mesmos.
- Dado o código de cores dos resistores, fazer um programa que permite mostrar o valor de resistência em Kilo - ohms.Tabela de Cores
- Faça um programa que leia valores de moedas e some as quantidades de tipos de moedas informadas. Para sair do programa o usuário deve digitar um número negativo. Valores inexistentes devem ser ignorados. Por exemplo, se o usuário digitar 25, 50, 25, 5, 10, 5, o programa deve informar: 2 moedas de 5 centavos, 1 moeda de 10 centavos, 2 moedas de 25 centavos, 1 moeda de 50 centavos. São aceitos apenas valores de moedas de 1, 5, 10, 25 e 50 centavos. Seu programa deve ler 10 valores de moedas, e então apresentar o resultado.
- Incrementar o programa anterior para calcular o total em reais equivalente as moedas lidas.
- Incrementar o programa anterior para que no final do programa uma mensagem seja dada para o usuário que possui mais do que 5 moedas de 50 e 3 moedas de 25 e mais do que 2 reais. A mensagem deve mandar o usuário comprar um X-salada.
- Um estudo sobre sensibilidade de pessoas a temperaturas da água identificou que a maioria das pessoas considera fria a água com temperaturas abaixo de 25 graus, morna entre 25 e 30 graus, e quente acima de 30 graus. Escreva um algoritmo na forma de fluxograma que mostre as palavras "fria", "morna" ou "quente" dependendo da temperatura da água que for informada;
Exercícios da Avaliação
1.Considere o fluxograma abaixo. a) Elabore um programa em C equivalente. Considere que TODAS as variáveis são inteiras. b) Coloque todos os valores finais das variáveis do programa.
2.Implementar um programa em C para ler 5 números inteiros e imprimir uma mensagem se a média dos dois primeiros for igual ou menor a soma dos três últimos. 3.Elaborar um fluxograma e um programa para ler 10 números reais para um vetor e, em seguida, computar a média de todos os números menores ou iguais a 11.5 E maiores que 5.5. A média deve ser impressa. 4.Implementar um programa em C para receber a resistência em ohms de 2 resistores e então calcular a resistência série e paralela dos mesmos. Se uma (ou ambas) resistências forem negativas, mostrar uma mensagem e encerrar o programa.
Exercícios de Revisão
Construir um fluxograma correspondente a uma função que recebe dois vetores de char que contem uma string. A função retorna 0 se as strings forem iguais e 1 se diferentes.
VETORES DE STRINGS
Na aula passada aprendemos vetores de caracteres e como usá-los para armazenamento de strings. Note que é possível construir vetores de strings. Vamos ao exemplo do controle de acesso.
PROBLEMA: Suponha que existe uma Tabela global de usuários chamada TabUserID. Suponha também que esta tabela tem tamanho finito de 20 posições. Posições não usadas estão com string VAZIA (0 na primeira posição). Construir uma função chamada LocalizarUserID, que recebe um UserID (string) como parâmetro (a tabela não precisa ser passada pois é GLOBAL) e retorna o índice onde se encontra o usuário UserID na tabela. Se o usuário não for encontrado, a função deve retornar -1.
EXERCÌCIO: Implementar uma função TratarUsuario() que se utiliza de duas tabelas: a TabUserID e a TabPassword para cada usuário na primeira tabela existe uma senha na segunda tabela. A função deve ler o UserID, usar a função LocalizarUserID para determinar o índice do usuário, ler a senha do usuário e validá-la usando o índice encontrado.
|}
Estruturas de Repetição |
---|
Estruturas de RepetiçãoObjetivosO aluno deverá ser capaz de utilizar os comandos de repetição:
Estruturas de RepetiçãoExistem 4 estruturas/comandos que permitem implementar loops ou repetições de blocos de código:
NOTA 1: Observe que repetir o código siginifica voltar a executá-lo, normalmente sobre o controle de uma expressão lógica. Revisitando o comando while()NOTE que no exemplo anterior o contador inicialmente DEVE conter um valor válido. Comando do whileO comando do while() permite a repetição de uma ou mais instruções, com controle do loop no final. Isto permite que o bloco seja executado pelo menos uma vez. A estrutura do comando, informalmente, é: do instrução_simples; while (expressão); ou do { lista_de_instruções } while (expressão); Comando for()O comando for() permite uma forma mais elaborada de loop, com controle no início do bloco de repetição. A estrutura do comando é: for(expressão_inicial;expressão_de_controle; expressão_de_final_de _bloco) { instrução_simples; ou for(expressão_inicial;expressão_de_controle; expressão_de_final_de _bloco) { lista_de_instruções } Comando gotoO comando goto é um dos mais antigos da programação. A ideia é comandar um salto para um determinado ponto específico do programa marcado por um rótulo (LABEL). Para utilizá-lo deve-se, portanto, marcar o ponto para onde será feito o salto usando um LABEL. Exemplo: main()
{
int i;
i=0;
PONTO1:
printf("Laço de número %d\n", i);
i++;
if (i<10)
goto PONTO1;
}
Devido a ser uma instrução "desestruturante", em geral NÂO se recomenda o uso deste comando. Em alguns casos de tratamento de erro pode ser interessante o uso do goto. Leia um pouco mais sobre o goto aqui. Loop InfinitoÉ possível implementar loops infinitos com qualquer uma das instruções acima. Exemplo com comando for: main()
{
for(;;) {
/* Este bloco se executará infinitamente */
}
}
ou com o comando while: main()
{
while(1) {
/* Este bloco se executará infinitamente */
}
}
Uso de break para sair de loopsEm exercícios anteriores, a finalização de um loop normalmente se dá pela expressão de controle de loop associado a instrução usada. É possível sair de um loop na força bruta usando a instrução break: #include <stdio.h>
main()
{
int i,j;
for (i=0;i<10;i++) {
if (i==5)
break;
}
printf("valor de i=%d\n", i);
}
Note que o break sempre sai do loop mais próximo a ele. #include <stdio.h>
main()
{
int i,j;
for (i=0;i<3;i++) {
for (j=0;j<4;j++) {
if (j==1) {
break;
}
printf("valor de j = %d\n", j);
}
if (i==2)
break;
printf("valor de i = %d\n", i);
}
}
EXERCÍCIOS1.Estude o programa (referência) abaixo: /* rand example: guess the number */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main ()
{
int iSecret, iGuess;
/* initialize random seed: */
srand ( time(NULL) );
/* generate secret number: */
iSecret = rand() % 10 + 1;
do {
printf ("Guess the number (1 to 10): ");
scanf ("%d",&iGuess);
if (iSecret<iGuess)
printf ("The secret number is lower\n");
else if (iSecret>iGuess)
printf ("The secret number is higher\n");
} while (iSecret!=iGuess);
printf ("Congratulations!\n");
return 0;
}
Explique o significado das instruções: srand ( time(NULL) ); iSecret = rand() % 10 + 1; 2.Faça uma versão "politicamente incorreta" deste programa fazendo um loop infinito com o do while() e usando uma instrução goto para sair do loop. 3.Ainda sobre o exercício 1, implemente uma versão usando o comando while(). 4.Usando o comando for, implemente uma função da forma: int plot_retangulo(int lado1, int lado2, int margem_esquerda, char caracter) Se a função for chamada da forma: plot_retangulo(10,3,5,'a'); ela deve produzir: aaaaaaaaaa a a aaaaaaaaaa Se houver inconsistência nos parâmetros retornar um código de erro -1 senão retornar 0. Soulação:/* Contribuição do aluno Mathias */
#include <stdio.h>
int plot_retangulo(int lado1, int lado2, int margem_esquerda, char letra)
{
int x, y, aux, aux2;
/* teste dos parâmetros */
if (lado1 < 1 || lado2 <1 || margem_esquerda <0)
return -1;
aux=lado1+margem_esquerda;
for(y=1;y<=lado2;y++) { /* para cada linha faz */
for(x=1;x<=aux;x++) { /* imprime a margem */
if(x<=margem_esquerda)
printf(" ");
else {
if(y==1||y==lado2) /* se for uma linha da extremidade, imprime cheio*/
printf("%c", letra);
else { /* se não for extremidade imprime vazado */
if(x==(margem_esquerda+1) || x==aux)
printf("%c", letra);
else
printf(" ");
}
}
}
printf("\n");
}
return 0;
}
int main()
{
plot_retangulo(2,3,0,'h');
}
|
Lista de Exercícios |
---|
Lista de ExercíciosEXERCÍCIOS (nível fácil)
EXERCÍCIOS (nível médio)
EXERCÍCIOS (nível difícil)
|
Avaliação 01 |
---|
Avaliação 01AVALIAÇÃO 1.Implementar um programna para calcular y dado x, onde 2.Implementar uma função que calcula a área de um retângulo (float) dado a base e a altura. O programa principal deve ler pelo teclado a base e a altura referente a dois triângulos. Uma mensagem deve ser dada se a área do primeiro triângulo é menor, maior ou igual ao segundo. 3.Implementar uma função da forma: void plotar_fig(int margem, int lado, char car1, char car2, char c3) Exemplo de uso: plotar_fig(6,5,'A','B','X') A figura deverá ser desenhada da forma (onde aparece 'b' é espaço em branco: bbbbbbA bbbbbbAA bbbbbbAAA bbbbbbAAAA bbbbbbAAAAA XXXXXXXXXXX bbbbbbBBBBB bbbbbbBBBB bbbbbbBBB bbbbbbBB bbbbbbB 4.Implementar um programa correspondente a um jogo da seguinte forma: Inicialmente o programa mostra para o usuário a seguinte sequência 0 1 2 3 4 5 6 7 O programa sorteia 2 posições onde serão colocados dois diamantes. Exemplo: posições dos números 2 e 7. O programa pede então para o usuário entrar com números até coletar os dois diamantes. A cada jogada os números devem ser atualizados conforme a jogada. Por exemplo, na primeira tentativa, supondo os diamantes em 3 e 7, se o usuário teclar 4, deve aparecer: 0 1 2 3 X 5 6 7 Na segunda tentativa, se o usuário colocar 3 (onde está o diamante), deve aparecer: 0 1 2 D X 5 6 7 No final, deve ser mostrado o número de tentativas (de X). SUGESTÃO: criar uma variável para cada posição (var0, var1 etc). Inicialmente a var0 é igual a 0, a var1 igual a 1 etc. Criar duas variáveis que contém o sorteio. O sorteio deve ser realizado antes.
PROVA 2 1.Implementar um programna para calcular y dado x, onde 2.Implementar uma função que calcula a área de um círculo (float) dado o raio. Se o parâmetro for menor ou igual a zero, a função deve retornar -1. O programa principal deve ler pelo teclado dois raios equivalentes a dois círculos. Uma mensagem deve ser dada se a área do primeiro círculo é menor, maior ou igual ao segundo. O programa deve testar situações de erro da função (retorno -1) e notificar através de uma mensagem. 3.Implementar uma função da forma: void plotar_fig(int margem, int lado, char car1, char car2, char c3) Exemplo de uso: plotar_fig(6,5,'A','B','X') A figura deverá ser desenhada da forma (onde aparece 'b' é espaço em branco: bbbbbbAAAAA bbbbbbAAAA bbbbbbAAA bbbbbbAA bbbbbbA XXXXXXXXXXX bbbbbbB bbbbbbBB bbbbbbBBB bbbbbbBBBB bbbbbbBBBBB
0 1 2 3 4 5 6 7 O programa sorteia 2 posições onde serão colocados dois diamantes. Exemplo: posições dos números 2 e 7. O programa pede então para o usuário entrar com números até coletar os dois diamantes. A cada jogada os números devem ser atualizados conforme a jogada. Por exemplo, na primeira tentativa, supondo os diamantes em 3 e 7, se o usuário teclar 4, deve aparecer: 0 1 2 3 X 5 6 7 Na segunda tentativa, se o usuário colocar 3 (onde está o diamante), deve aparecer: 0 1 2 D X 5 6 7 No final, deve ser mostrado o número de tentativas (de X). SUGESTÃO: criar uma variável para cada posição (var0, var1 etc). Inicialmente a var0 é igual a 0, a var1 igual a 1 etc. Criar duas variáveis que contém o sorteio. O sorteio deve ser realizado antes. |
Vetores |
---|
VetoresConceito de Vetores em ProgramaçãoRever aula 5. VetoresUm vetor pode ser facilmente definido no C: main()
{
float x[10]; /* vetor com 10 floats */
int i;
x[0] = 22.5; /* colocando 22.5 na posição 0 do vetor */
x[9] = x[0] + 2.5;
printf("Entrar com o número na posição 5\n");
scanf("%f",&x[5]);
/* usando uma expressão como índice */
i=2;
x[i*2]=i*1.5;
/*usando loop para acessar o vetor */
while (i<8) {
x[i]=0.0;
i++;
}
}
NOTA: vetores na Linguagem C sempre começam na posição 0 Pode-se iniciar um vetor da forma: #include <stdio.h>
void main()
{
int x[10] = {2,4,7,-5,3,2,3,4,9,10}
printf("%d\n", x[2]);
}
Exercícios
Vetor de CharÉ possível definir vetores do tipo char. Tais vetores permitem definir cadeias de caracteres. Para marcar um final de cadeia usa-se o número 0 (NULL), Exemplo: Fazer um programa para computar o número de caracteres de uma cadeia (string) lida pelo teclado.Use o comando while.#include <stdio.h>
void main ()
{
char alfa[50];
int i=0;
printf ("Entre com a cadeia: ");
scanf("%s",alfa);
while(alfa[i]!=0)
i++;
printf ("\nNumero de caracteres em %s = %d \n", alfa, i);
}
Exercício
Iniciando uma cadeia na declaração#include <stdio.h>
void main ()
{
char alfa[50]="IFSC-SJ";
printf ("\nNumero de caracteres em %s\n", alfa);
}
Como passar um vetor de caracteres como parâmetroint str_len(char x[])
{
int i=0;
while (x[i]!=0)
i++;
return i;
}
main()
{
int tam;
tam = str_len("teste");
}
NOTE que vetores são SEMPRE passados como referência: #include <stdio.h>
void capitalizar(char x[])
{
int i=0;
while (x[i]!=0) {
if(x[i]>='a'&&x[i]<='z')
x[i]-=0x20;
i++;
}
}
main()
{
char cadeia[50]="teste";
capitalizar(cadeia);
printf("%s\n",cadeia);
}
A variável cadeia será moidifcada e será impresso: TESTE Exercícios
x = comp_ult("alfa","omega") O valor de x após a execução deve ser 1. Para a chamada: x = comp_ult("alfa","epson") O valor de x deve ser -1. OBS: USE como apoio a função str_len já desenvolvida.
char alfa[50]="IFSC; char beta[50]="-SJ"; str_cat(alfa,beta) Após a execução, dentro da variável alfa teremos a cadeia "IFSC-SJ" ATENÇÂO: LEMBREM_SE DOS ESTILOS DE INDENTAÇÂO http://en.wikipedia.org/wiki/Indent_style#K.26R_style
|
Usando o gdb para depurar programas |
---|
Usando o gdb para depurar programasÈ possível controlar a execução de um programa usando um outro programa, chamado depurador (debugger), para controlar a execução do primeiro. A GNU desenvolveu o debugger gdb que é hoje amplamente utilizado por desenvolvedores. Seja o programa armazenado no arquivo teste.c:#include <stdio.h>
main()
{
int x,y;
x = 2;
y = 0;
while (y<5)
x++;
printf ("Valor de x = %d\n",x);
}
Para que um programa possa ser depurado, devemos compilá-lo da forma: gcc -g teste.c -o teste
O gdb pode então ser chamado da forma: gdb teste Um breakpoint pode ser colocado em qualquer linha ou entrada de função do programa. Para colocar um breakpoint na entrada da função pode-se fazer: b main Para executar o programa basta fazer o comando run: r A execução para no breakpoint. A instrução mostrada ainda vai ser executada. Para acompanhar o valor de variáveis pode-se colocá-las em display: display x display y Para execução passo a passo pode-se utilizar o comando next: n Para ver o Para ver o conteúdo de uma variável pode-se ainda fazer o comando print: print x
|
Exercícios de Revisão |
---|
Exercícios de RevisãoObjetivos
Exercícios
|
Strings |
---|
StringsObjetivosO aluno deverá, após a aula;
Processamento de stringsNa aula anterior vimos vetores. Vimos que é possível armazenar strings em vetores de char. O processamento de strings é de grande interesse em programação. Vamos continuar a ver alguns aspectos deste processamento. Ainda na aula aula passada vimo como computar o tamanho de uma string usando a função str_len(). V Vamos elaborar mais algumas funções para comp Computando o tamanho de uma stringEm aulas anteriores já havíamos visto que podemos computar o tamanho de uma string da forma: int str_len(char x[])
{
int i=0;
while (x[i]!=0)
i++;
return i;
}
main()
{
char teste[]="IFSC-SJ";
int tamanho;
tamanho = str_len(teste);
}
Copiando stringsImplementar e testar uma função que copia uma cadeia de caracteres de um vetor de strings fonte para um vetor de destino, de forma similar a função strcpy.#include <stdio.h>
void str_cpy(char auxs1[], char auxs2[])
{
int i;
for(i=0;auxs2[i]!=0;i++)
auxs1[i]=auxs2[i];
auxs1[i]=0;
}
main()
{
char str1[100], str2[100];
printf("Entre com a string => ");
scanf ("%s", str2);
str_cpy(str1, str2);
printf("\nString copiada = %s\n", str1);
}
#include <stdio.h>
void str_cpy(char auxs1[], char auxs2[])
{
int i=0;
do {
auxs1[i]=auxs2[i];
}while(auxs2[i++]!=0);
}
main()
{
char str1[100], str2[100];
printf("Entre com a string => ");
scanf ("%s", str2);
str_cpy(str1, str2);
printf("\nString copiada = %s\n", str1);
}
Concatenado strings
Comparando stringsExercício: Implementar uma função chamada str_cmp que recebe duas strings como parâmetro e retona 0 se elas são iguais ou 1 se elas forem diferentes. A função é case sensitive. Exercícios sobre strings1.Implementar uma função para adicionar (append) n caracteres iniciais de uma string2 para o final de uma string1. Retornar 0 se sucesso ou -1 se detectado algum problema. int str_ncat(char string1[], char string2[], int n) #include <stdio.h>
int str_len(char x[])
{
int i=0;
printf ("Endereço de x é %p\n", x);
while (x[i]!=0)
i++;
return i;
}
int str_ncat(char string1[], char string2[], int n)
{
int i,j;
if (n<=0)
return -1;
i = str_len(string1);
for (j=0;j<n && string2[j]!=0;j++) {
string1[i] = string2[j];
i++;
}
if(string2[j]!=0)
string1[i] =0;
return 0;
}
main()
{
char x[100]="IFSC-";
char y[100]="Telecom SJ";
str_ncat(x,y,30);
printf("x - > %s\n", x);
}
2.Implementar uma função para adicionar (append) a uma subcadeia da string2 para uma string1. A substring é iniciada no índice determinado por n. int str_nicat(char string1[], char string2[], int n) 3.Implementar uma função para comparar até n primeiros caracteres de duas cadeias passadas como parâmetro. Retornar 0 se iguais, -1 se diferentes. int str_ncmp(char string1[], char string2[], int n) 4.Implementar uma função para comparar uma substring da string2 com os n2 primeiros caracteres de string1. A substring é determinada pelo índice n1 com tamanho dado por n2. Retornar 0 se sucesso e -1 se problemas. int str_nicmp(char string1[],char string2[], int n1, int n2) 5.Implementar uma versão não sensitiva a case da função str_cmp.
|
Matrizes |
---|
MatrizesObjetivos
Como definir e operar com matrizes no CDe forma similar ao vetor, basta definir a matriz usando colchetes para indicar a dimensão da variável. Exemplo: Definir duas matrizes 2x3 já inicializadas e computar a soma das mesmas: #include <stdio.h>
void main()
{
int mA[2][3]={ 11,12,13,
21,22,23},
mB[2][3]={1,2,3,
1,2,3},
mC[2][3];
int i,j;
for(i=0;i<2;i++){
for(j=0;j<3;j++) {
mC[i][j] = mA[i][j] + mB[i][j];
}
}
}
Exercício
Passando matrizes como parâmetro#include <stdio.h>
void somar_mat(int aA[][3],int aB[][3], int cC[][3])
{
int i,j;
for(i=0;i<2;i++){
for(j=0;j<3;j++) {
cC[i][j] = aA[i][j] + aB[i][j];
}
}
}
void main()
{
int mA[2][3]={ 11,12,13,
21,22,23},
mB[2][3]={1,2,3,
1,2,3},
mC[2][3];
somar_mat(mA,mB,mC);
}
OBSERVE que matrizes são sempre passadas como referência. Exercício
Matrizes de caracteres e vetores de stringsUm vetor de strings pode ser construído usando matrizes de char. Cada string será armazenada em uma linha do vetor. Exemplo #include <stdio.h>
main()
{
char TabelaUsuarios[4][10] = {
"joao",
"maria",
"jose",
"lara",
};
int i;
for (i=0;i<4;i++)
printf("%s\n",&TabelaUsuarios[i][0]);
}
Note a forma como é realizada a inicialização da matriz. Exercício
Autor: Beatriz da Silveira
#include <stdio.h>
#include <string.h>
char TabelaUsuarios[4][10] = {
"joao",
"maria",
"jose",
"lara",
};
char TabelaSenhas[4][10]={
"joaozinho",
"mari",
"josezinho",
"larinha",
};
int tratandoAutenticacao(char userId[50], char senha[50]){
int userEncontrado=1;
int senhaEncontrada=1;
int i;
int b=1;
for (i=0;i<4 && userEncontrado; i++) {
if( strcmp(userId, &TabelaUsuarios[i][0])==0)
userEncontrado=0;
}
if (userEncontrado==0){
for (i=0;i<4 && senhaEncontrada; i++) {
if( strcmp(senha, &TabelaSenhas[i][0])==0){
senhaEncontrada=0;}}
if(senhaEncontrada==0){
printf("Abrir porta!!!\n");
b=0;
}else{
printf("Senha inválida\n");
b=1;
}
}else{
printf("User inválido\n");
b=1;
}
return b;
}
int main()
{
char userId[50];
char senha[50];
int aut;
do
{printf("Digite seu userId: \n");
scanf("%s",userId);
printf("Entre com sua senha \n");
scanf("%s", senha);
aut =tratandoAutenticacao(userId, senha);}while(aut == 1);
printf("Usuário e senha corretos");
return 0;
}
Autora: Beatriz da Silveira
#include <stdio.h>
#include <string.h>
int main()
{
int i;
char userId[50];
int userEncontrado=1;
char TabelaUsuarios[5][10] = {
"joao",
"maria",
"jose",
"lara",
"fim" };
do{
printf("Entre com seu usuário");
scanf("%s", userId);
for (i=0;i<5 && userEncontrado; i++) {
if( strcmp(userId, &TabelaUsuarios[i][0])==0 && strcmp(userId,&TabelaUsuarios[4][0])==0){
userEncontrado=0;
printf("FIM Abrir porta\n");}
} }while(userEncontrado==1);
printf("O usuário digitado é : FIM");
return 0;
}
O código abaixo foi o código base para a implementação feita acima
#include <stdio.h>
#include <string.h>
main()
{
char TabelaUsuarios[4][10] = {
"joao",
"maria",
"jose",
"lara",
};
int i;
char userId[50];
int userEncontrado=1;
scanf("%s",userId);
for (i=0;i<4 && userEncontrado; i++) {
if( strcmp(userId, &TabelaUsuarios[i][0])==0)
userEncontrado=0;
}
if (userEncontrado==0)
printf("Abrir porta!!!\n");
}
|
Estruturas |
---|
EstruturasObjetivos
EstruturasNo C é possível criar tipos de dados que representam uma estrutura. Veja o exemplo seguinte #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];
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. Estruturas dentro de estruturasVamos 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);
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);
}
Exercício 1: Faça um código adicional para imprimir o conteúdo lido na estrutura. Exercício 2: Modifique o exercício anterior para que os dados não sejam lidos pelo scanf mas através da inicialização da estrutura. #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",{"João da Silva","350"},10};
printf("Rua do cidadao = %s\n", Cidadao.endereco.rua);
}
Passando estruturas como parâmetro e retornando estruturasSe não for usado o operador "&" , um parâmetro que é estrutura será passado por cópia. 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??? #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);
}
Copiando structsO 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);
}
Aplicação no Controle de AcessoO 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();
}
}
}
Exercício:
Exercícios
#include <math.h>
struct TComplexoRet {
float x,y;
};
struct TComplexoPolar {
float mod,ang;
};
struct TComplexoPolar convert_polar(struct TComplexoRet a)
{
struct TComplexoPolar aux;
aux.mod = sqrtf(powf(a.x,2)+powf(a.y,2));
aux.ang = atan(a.y/a.x);
return aux;
}
main()
{
struct TComplexoRet w;
struct TComplexoPolar y;
w.x = 11.5;
w.y = 4.6;
y = convert_polar(w);
}
Autor: Beatriz da Silveira
#include <stdio.h>
#define NUM_ALUNOS 40
#define TAM_MAT 10
struct TRegistroAluno{
char nome[NUM_ALUNOS];
char matricula[TAM_MAT];
float bim1,bim2,bim3,bim4;
};
struct TRegistroAluno TabelaNotasTurma[4] = {
{"Lara","12222212", 10.0,10.0,9.5,7.6},
{"Joao","44434212", 7.6,4.5,7.8,9.7},
{"Maria","12234272", 8.7,9.0,9.8,9.6},
{"Jose","75656755", 4.5,6.6,5.5,8.9},
};
float media_semestral(char nome[], int semestre)
{
int i,AlunoEncontrado=1;
float media;
if (semestre!=1 && semestre!=2)
return -1;
for(i=0;i<NUM_ALUNOS && AlunoEncontrado;i++) {
if(strcmp(TabelaNotasTurma[i].nome, nome)==0)
AlunoEncontrado=0;
}
if (AlunoEncontrado==0){
i--;
if(semestre==1)
media=(TabelaNotasTurma[i].bim1 + TabelaNotasTurma[i].bim2)/2;
else
media=(TabelaNotasTurma[i].bim3 + TabelaNotasTurma[i].bim4)/2;
}
return media;
}
float media_anual(char matricula[])
{
int i,AlunoEncontrado=1;
float media;
for(i=0;i<NUM_ALUNOS && AlunoEncontrado;i++) {
if(strcmp(TabelaNotasTurma[i].matricula, matricula)==0)
AlunoEncontrado=0;
}
if (AlunoEncontrado==0){
i--;
media = (TabelaNotasTurma[i].bim1 + TabelaNotasTurma[i].bim2+
TabelaNotasTurma[i].bim3 + TabelaNotasTurma[i].bim4)/4;
}
return media;
}
int retorna_index(char matricula[])
{
int i,AlunoEncontrado=1;
for(i=0;i<NUM_ALUNOS && AlunoEncontrado;i++) {
if(strcmp(TabelaNotasTurma[i].matricula, matricula)==0)
AlunoEncontrado=0;
}
if (AlunoEncontrado==0)
i--;
else
i=-1;
return i;
}
void oQueDesejaFazer(int num){
char mat[TAM_MAT];
int semestre;
switch (num)
{
case 1:
printf ("Digite o nome do aluno para saber a média Semestral\n");
char aluno[NUM_ALUNOS];
scanf("%s", aluno);
//int semestre;
printf("Digite 1 0u 2 para saber a nota semestral");
scanf("%d", &semestre);
float media = media_semestral(aluno, semestre);
printf("A média semestral é: %.2f \n", media);
break;
case 2:
printf ("Digite o número da matrícula do aluno, para saber a média anual");
//char mat[TAM_MAT];
scanf("%s", mat);
float mediaAnual= media_anual(mat);
printf("A média anual do aluno é: %.2f\n", mediaAnual);
break;
case 3:
printf ("Digite o nº da matricula para saber o index do aluno\n");
//char mat[TAM_MAT];
scanf("%s", mat);
int index =retorna_index(mat);
printf("O index do aluno é %d", index);
break;
default:
printf ("Você não escolheu nenhuma das opções listadas.\n");
}
}
int main()
{
int opcao=0;
while(1){
printf("O que você deseja fazer\n 1-Para saber média semestral\n 2-Para saber média anual\n 3-Index do aluno na tabela\n 4-Para sair");
scanf("%d", &opcao);
if(opcao==4){
printf("Saindoo");
break;
}
oQueDesejaFazer(opcao);
}
return(0);
}
|
Avaliação 02 |
---|
Avaliação 02OBJETIVOS
AVALIAÇÂO LAB 2 A1.Implementar uma função que recebe como parâmetros dois vetores de floats cujos tamanhos são passados também como parâmetros. A função deve retornar 1 se a média dos elementos do primeiro vetor for maior que o segundo e 0 se for menor ou igual. Ver esqueleto da funçao:#include <stdio.h>
int compara_media_vetores(float vet1[], int tam1, float vet2[], int tam2)
{
/* implementar aqui */
}
main()
{
float x1[5]={2.4,,6.7,8.5,9.6,1.5};
float x2[4]={1.6,2.5,6.7,3.2};
int res;
/* exemplo de uso da função */
res = compara_media_vetores(x1,5,x2,4);
if (res==1)
printf("media de x1 maior que média de x2\n");
}
Autora: Beatriz da Silveira
Resposta da questão 1, da avaliação Lab2A
#include <stdio.h>
int compara_media_vetores(float vet1[], int tam1, float vet2[], int tam2)
{
/* implementar aqui */
int i;
float total1;
float total2;
for(i=0;i<tam1;i++)
total1 = total1 + vet1[i];
total1 = total1/tam1;
printf("valor de total1= %.2f\n", total1);
for(i=0;i<tam2;i++)
total2 = total2 + vet2[i];
total2 = total2/tam2;
printf("valor de total2=%.2f\n", total2);
if(total1>total2){
return 1;
}else{
return 0;
}
}
int main()
{
float x1[5]={2.4,6.7,8.5,9.6,1.5};
float x2[4]={1.6,2.5,6.7,3.2};
int res;
/* exemplo de uso da função */
res = compara_media_vetores(x1,5,x2,4);
if (res==1)
printf("media de x1 maior que média de x2\n");
return 0;
}
int num_vog(char cadeia[])
{
/* implementar aqui */
}
main()
{
/* testar o uso da função aqui */
}
Explicação adicional:Para a cadeia "abacate" a função deveria retornar 1. Autora: Beatriz da Silveira
Resposta da questão 2, avaliação Lab2A
#include <stdio.h>
int num_vog(char cadeia[])
{
int i;
int totalDeA=0;
for(i=0;cadeia[i]!= 'b'; i++)
{
if(cadeia[i]=='a')
totalDeA=totalDeA+1;
}
return totalDeA;
}
int main()
{
char x1[]={'a','b','a','c','a','t','e','\0'};
int x2 = num_vog(x1);
printf("Quantidade de A: %d\n", x2);
return 0;
}
3.Implementar uma tabela global usando structs que permita representar as contas bancários de pessoas físicas. Cada registro deve conter nome, cpf, endereço e o saldo atual da conta. Contas podem estar negativas. Implementar uma função que permita calcular o total de dinheiro do banco em função do saldo das contas e uma função que retorna o saldo de um usuário dado o seu CPF. Autora: Beatriz da Silveira
Resolução da questão 3, Avaliação Lab3A
#include <stdio.h>
#include <string.h>
#define TAM_CLIENTE 40
#define TAM_CPF 60
#define TAM_END 50
struct TRegistroCliente{
char nome[TAM_CLIENTE];
char cpf[TAM_CPF];
char endereco[TAM_END];
float saldo;
};
struct TRegistroCliente TabelaClientes[4] = {
{"Lara","12222212", "kobrasol", 192.97},
{"Joao","44434212", "Campinas", -69.0},
{"Maria","12234272", "Barreiros", 45.90},
{"Jose","75656755", "Centro", 75.00},
};
float totalDinheiro(){
int i;
float saldoTotal=0;
for(i=0; i<4; i++)
{
saldoTotal=TabelaClientes[i].saldo+saldoTotal;
}
return saldoTotal;
}
float saldoUsuario(char cpf[]){
int i,userEncontrado=1;
float saldo;
for(i=0;i<4 && userEncontrado;i++) {
if(strcmp(TabelaClientes[i].cpf, cpf)==0)
userEncontrado=0;
}
if (userEncontrado==0){
i--;
saldo = (TabelaClientes[i].saldo);
}
return saldo;
}
int main(){
int x;
char cpf[TAM_CPF];
while(1){
printf("----------------------------------------------------\n");
printf("Escolha a operação que você deseja realizar\n");
printf("1-saldo total do banco\n2-Saldo do usuário\n");
scanf("%d", &x);
printf("----------------------------------------------------\n");
if(x==1){
printf("O saldo total do banco é de: %.2f\n", totalDinheiro());
}if(x==2){
printf("Insira seu cpf digitando somente numeros\n");
scanf("%s",cpf);
printf("Saldo total do banco é de: %.2f\n", saldoUsuario(cpf));
}
}}
AVALIAÇÂO LAB2B1.Implementar um programa C (não precisa ser função) que lê valores (usando scanf) de uma matriz alfa de dimensão MxN de inteiros (onde M e N são dimensões que devem ser lidas no início). O programa deve mostrar (usando printf) quantas linhas desta matriz possuem valores entre 5 e 10 (inclusive). Exemplo: A matriz: 12 5 3 1 4 17 13 14 10 Esta matriz possui 2 linhas com valores que estão entre 5 e 10. 2.Implementar uma função que recebe um vetor de caracteres como parâmetro. Este vetor conterá uma string terminada em NULL. A função deve retornar o número de vogais 'a' e 'i' que sejam sucedidas pela letra c. Na função main apresentar um teste de uso da funçãoint num_vog(char cadeia[])
{
/* implementar aqui */
}
main()
{
/* testar o uso da função aqui */
}
Explicação adicional:Para a cadeia "abacate" a função deveria retornar 1. 3.Implementar uma tabela global usando structs que permita representar as contas bancários de pessoas físicas. Cada registro deve conter nome, cpf, endereço e o saldo atual da conta. Contas podem estar negativas. Implementar uma função que permita calcular o total contas em negativo e uma função que retorna o saldo de um usuário dado o seu nome. |
Lista Exercícios |
---|
Lista Exercícios
int Jogo[3][3]={
0,0,0,
0,0,0,
0,0,0,
};
unsigned int jogador_vez=0; /* 0 e 1 representam os jogadores */
int jogo=1;
struct Tjogada{
int x,y;
} jogada;
void apresentar_jogo()
{
}
struct Tjogada ler_jogada()
{
}
int validar_jogada(struct Tjogada aux_jogada)
{
}
void verificar_termino(struct Tjogada aux_jogada)
{
}
void anunciar_vitoria()
{
}
main()
{
while (jogo==1) {
apresentar_jogo();
jogada=ler_jogada();
if (validar_jogada(jogada)) {
if (verificar_termino(jogada)==0) {
anunciar_vitoria();
jogo=0;
}
jogador_vez=++jogador_vez%2;
} else {
printf("Jogada inválida\n");
}
}
}
Autora: Beatriz da Silveira
Implementação do Jogo da Velha
#include <stdio.h>
#include <string.h>
#define linha 3
#define coluna 3
int Jogo[3][3]={
{0,0,0},
{0,0,0},
{0,0,0}
};
unsigned int jogador_vez=1; /*São os jogadores, que serão representados pelos nºs 1 e 5*/
int jogo=1;
struct Tjogada{
int x,y;
} jogada;
/*O método abaixo apresenta o tabuleiro ao jogador e caso todas as casas já estejam preenchidas
* finaliza o jogo*/
int apresentar_jogo()
{
int finaliza=9;
int i;
int j;
for(i=0;i<linha;i++)
{
for(j=0;j<coluna;j++)
{
printf("%d\t", Jogo[i][j]);
if(Jogo[i][j]!=0){
finaliza--;
}
}
printf("\n");
}return finaliza;
}
/*Armazena na struct a linha e a coluna que o jogador deseja inserir a jogada*/
struct Tjogada ler_jogada()
{
printf("Digite a linha que deseja inserir a jogada");
scanf("%d", &jogada.x);
printf("Digite a coluna que deseja inserir a jogada");
scanf("%d", &jogada.y);
return jogada;
}
/*Impede que o jogador tente jogar numa casa já preenchida, ou inserir numa
* linha ou coluna fora do escopo*/
int validar_jogada(struct Tjogada aux_jogada)
{
if(Jogo[aux_jogada.x][aux_jogada.y]==0 && aux_jogada.x<linha && aux_jogada.y<coluna){
Jogo[aux_jogada.x][aux_jogada.y]=jogador_vez;
return 0;
}
return 1;
}
int verificar_termino()
{
int i;
int j;
//Confere linha por linha;
for(i=0;i<linha;i++){
int soma=0;
for(j=0;j<coluna;j++)
{
soma = soma+Jogo[i][j];
if(soma==3 || soma == 15){
return 0;
break;
}
}
//Confere coluna por coluna;
}for(j=0;j<coluna;j++){
int soma=0;
for(i=0;i<linha;i++){
soma = soma+Jogo[i][j];
if(soma==3 || soma ==15){
return 0;
break;
}
}
}
//Confere a diagonal principal e a diagonal secundária
int diagonalPrincipal=0;
int diagonalSecundaria=0;
int l;
for(l=0 ; l < linha ; l++)
{
diagonalPrincipal = diagonalPrincipal+Jogo[l][l];
diagonalSecundaria =diagonalSecundaria+Jogo[l][linha-l-1];
if(diagonalPrincipal==3 || diagonalPrincipal==15 || diagonalSecundaria==3 || diagonalSecundaria==15){
return 0;
break;
}
}
return 1;
}
void anunciar_vitoria()
{
apresentar_jogo();
}
int main()
{
while (jogo==1) {
int velha=apresentar_jogo();
if(velha==0){
printf("Deu velha!");
exit(0);
}
jogada=ler_jogada();
if (validar_jogada(jogada)==0) {
if (verificar_termino()==0) {
anunciar_vitoria();
jogo=0;
printf("Terminou o jogo");
}
if (jogador_vez==1){
jogador_vez=5;
}else{
jogador_vez=1;
}
} else {
printf("Jogada inválida\n");
}
}
return 0;
}
|
Ponteiros |
---|
Referênciashttp://pw1.netcom.com/~tjensen/ptr/ch1x.htm http://eternallyconfuzzled.com/tuts/languages/jsw_tut_pointers.aspx http://duramecho.com/ComputerInformation/WhyCPointers.html http://boredzo.org/pointers/
PonteirosA 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).
Ponteiro para inteiroObserve 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>
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: main()
{
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. EXERCÍCIO 2: Tente inferir qual seria o valor da variável y no final do programa abaixo. main()
{
int x,y,w,*p1,*p2;
x = 20;
w = 30;
p1 = &x;
p2 = &w;
y = *p1 + *p2;
}
EXERCÍCIO 3: Tente inferir qual seria o valor da variável y no final do programa abaixo. 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;
}
Ponteiro para charOs 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>
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). EXERCÍCIO: Sem executar o programa abaixo, determine o valor de y no final do programa: main()
{
char x[10]="ifsc";
char *p, y;
p = x + 2;
y= *p;
}
Apontando para um vetor de inteirosDa 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>
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++;
}
}
Usando ponteiro na passagem de parâmetrosObserve 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;
}
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;
}
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íCIO: Implementar a função str_cat que concatena duas strings usando ponteiros. Vetor de ponteirosComo visto em aulas anteiriores, variáveis ponteiros possuem como conteúdo um endereço. É perfeitamente possível construir vetores e matrizes de ponteiros. Por exemplo:
#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. Apontando para estruturasPonteiros podem apontar para qualquer "objeto" de qualquer tipo. Vamos verificar como é possível apontar para uma estrutura: #include <stdio.h>
#include <stdio.h>
struct TRegistro {
char nome[20];
int idade;
} Tabela[4] = {
{"joao",18,},
{"maria",18,},
{"jose",19,},
{"lara",17,},
}
;
struct TRegistro *p;
main()
{
p = &Tabela[3]; /*p aponta para o registro 3 da tabela */
printf("O nome na posição 3 é %s e idade = %d\n", p->nome,p->idade);
}
Note que o uso de p->nome é uma alternativa ao uso de (*p).nome No primeiro caso pode-se ler: o campo nome do objeto que é apontado por p. Retornando uma estrutura em uma função#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];
}
main()
{
p = RetornarStruct(2); /*p aponta para o registro 3 da tabela */
printf("O nome na posição 2 é %s e idade = %d\n", p->nome,p->idade);
}
Passando uma estrutura como parâmetro#include <stdio.h>
struct TRegistro {
char nome[20];
int idade;
} Tabela[4] = {
{"joao",18,},
{"maria",18,},
{"jose",19,},
{"lara",17,},
};
struct TRegistro *p;
void MudarStruct(struct TRegistro *p1, int indice)
{
Tabela[indice] = *p1;
}
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);
}
Vetor de ponteirosComo visto em aulas anteiriores, variáveis ponteiros possuem como conteúdo um endereço. É perfeitamente possível construir vetores e matrizes de ponteiros. Por exemplo:
#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. Argumentos de linha de comandoUm 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 inidica o nome do programa. Exemplo: Considere o programa abaixo: #include <stdio.h>
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" */
}
EXERCÍCIO 1: 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 EXERCÍCIO 2: Renomeie o executável e veja seja a mensagem de erro mostra o nome correto do programa. |
Alocação Dinâmica de Memória |
---|
Alocação Dinâmica de MemóriaA área de heap e o Layout de memória de um programa CNeste link podemos ter uma ideia da anatomia de um programa na memória do computador. http://shivacherukuri.blogspot.com.br/2011/03/memory-layout-in-cdata-segmentbss-code.html Podemos observar que existe as seguintes áreas:
Quando declaramos uma variável global da forma: int x; a variável x é alocada em uma área chamada BSS (dados não incializados). Note que x possui uma área de memória reservada a ela (4 bytes) e cuja existência é o tempo de vida do programa em execução. Da mesma forma, uma variável global da forma: int y=10; é alocada na área de DATA. A inicialização é definida normalmente na carga do programa. Os valores de inicialização são copiados para a área de DATA na carga do programa, a partir do arquivo executável. Por vezes, o tamanho dos dados não são conhecidos antes da execução do programa. Neste caso, pode ser interessante criá-los dinamicamente e é neste ponto que entra a área de HEAP. Trata-se de uma área de memória, gerenciada a partir de funções da biblioteca do C. As funções mais conhecidas são (http://en.wikipedia.org/wiki/C_dynamic_memory_allocation): http://www.linuxjournal.com/article/4681 http://www.cs.cmu.edu/~guna/15-123S11/Lectures/Lecture08.pdf Exemplo 1: Alocação dinâmica de números inteiros (exercício puramente didático): #include <stlib.h>
main()
{
int *px, *py;
int resultado;
px = (int *) malloc(sizeof(int));
*px = 5;
py = (int *) malloc(sizeof(int));
*px = 2;
resultado = *px + *py;
free (px);
px = NULL;
free (py);
py = NULL;
}
Alocando dinamicamente uma tabela de estruturas#include <stdio.h>
#include <stdlib.h>
void main()
{
struct Tteste{
int x;
} *teste;
if ((teste = (struct TTeste *) malloc (100*sizeof(struct Tteste)))==NULL) {
printf("erro de alocação");
exit(1);
}
teste[10].x= 5;
if ((teste = realloc(teste, 10000*sizeof(struct Tteste)))==NULL) {
printf("erro de alocação");
exit(1);
}
teste[9000].x=20;
free(teste);
}
Exercício: Refazer o exemplo anterior para que a quantidade de memória a ser alocada pela tabela seja passada na linha de comando. Listas LigadasPor vezes não se conhece o tamanho dos dados que se vai manipular e o uso de uma lista pode ser conveniente para armazená-los. Um sistema de estoque de produtos, por exemplo, poderia ser armazenado na forma de uma lista. O exercício a seguir explora esta estrutura. Exercício de lista ligada #include <stdlib.h>
#include <stdio.h>
/*========================*/
/** OPERAÇÔES COM LISTA LIGADA ******/
/*========================*/
/*
tipos e variáveis globais
*/
struct TProduto{
int codigo;
struct TProduto *next;
} *head, *tail;
/*
adiciona item a cabeça da lista
retorna 0 se tudo ok e -1 se erro
*/
int add_nodo_head(int codigo)
{
}
/*
adiciona item ao final lista
retorna 0 se tudo ok e -1 se erro
*/
int add_nodo_tail(int codigo)
{
struct TProduto *p = malloc (sizeof(struct TProduto));
if (!p)
return -1;
p->codigo = codigo;
p->next = NULL;
if (tail==NULL) {
/* lista vazia */
tail = head = p;
}else {
/*lista não vazia */
tail->next = p;
tail = p;
}
return 0;
}
/*
imprimir lista
*/
void print_list()
{
}
main()
{
int i;
head = tail = NULL;
print_list ();
for (i=0;i<5;i++)
add_nodo_tail(i);
print_list ();
}
Lição para casa
Autora: Beatriz da Silveira
No código abaixo foi implementado as funções: add_node_head(), print_list, delete_node(int codigo)
#include <stdlib.h>
#include <stdio.h>
/*========================*/
/** OPERAÇÔES COM LISTA LIGADA ******/
/*========================*/
/*
tipos e variáveis globais
*/
struct TProduto{
int codigo;
struct TProduto *next;
} *head, *tail;
/*
adiciona item a cabeça da lista
retorna 0 se tudo ok e -1 se erro
*/
int add_nodo_head(int codigo)
{
struct TProduto *p = malloc (sizeof(struct TProduto));
if (!p)
return -1;
p->codigo = codigo;
p->next = head;
if (head==NULL) {
/* lista vazia */
head = tail = p;
}else{
head=p;
}
return 0;
}
/*
adiciona item ao final lista
retorna 0 se tudo ok e -1 se erro
*/
int add_nodo_tail(int codigo)
{
struct TProduto *p = malloc (sizeof(struct TProduto));
if (!p)
return -1;
p->codigo = codigo;
p->next = NULL;
if (tail==NULL) {
/* lista vazia */
tail = head = p;
}else {
/*lista não vazia */
for(tail=head; tail->next !=NULL; tail=tail->next);
tail->next = p;
// tail = p;
}
return 0;
}
int delete_node(int codigo){
struct TProduto *anterior=NULL;
struct TProduto *p=NULL;
//Caso o código seja o primeiro da lista entrará no if, caso seja do meio ou do final entrará no else
if(head->codigo==codigo){
head=head->next;
free(p);
}else{
for(p=head;p->codigo!=codigo;p=p->next){
anterior=p;
}
anterior->next=p->next;
free(p);
}
return 0;
}
/*
imprimir lista
*/
void print_list( struct TProduto *inicio)
{
struct TProduto *p;
for (p = inicio; p != NULL; p = p->next)
printf( "Imprimindo estrutura: %d\n", p->codigo);
}
int main()
{
int i;
head = tail = NULL;
// print_list (head);
//Inserindo códigos no final da lista
for (i=0;i<5;i++)
add_nodo_tail(i);
//Inserindo códigos no início da lista
for(i=6;i<9;i++)
add_nodo_head(i);
print_list (head);
printf("-----------------\n");
//Deletando o código de número 8
delete_node(8);
print_list(head);
return 0;
}
|
Operando com Arquivos | |
---|---|
Operando com ArquivosObjetivos
O sistema de arquivos no LinuxO ArquivoUm arquivo é um conjunto de dados que pode ser referenciado por um nome e pode ter outros atributos tais como: permissão para leitura e escrita, data da criação, data da última modificação etc. Note que um arquivo pode conter dados (um relatório, por exemplo), um programa C, um programa executável, música, fotos etc. Seja qual for a natureza dos dados o armazenamento será na forma de bits. Normalmente, arquivos são armazenados em memórias secundárias, tais como CD, hard disk etc, mas eles podem se armazenados na memória principal também (RAM, FLASH). Quanto a forma como os dados são armazenados, podemos dizer que os arquivos são binários ou texto. Qualquer um deles armazena bits mas os bytes de um arquivo texto representam códigos ASCII. Sistema de ArquivosUm sistema tal como o Linux possui milhares de arquivos. Para que arquivos possam ser acessados e armazenados de forma consistente, eles são organizados em um sistema de arquivos. Tipicamente, um sistema de arquivos ocupa uma área de um disco (ou mídia de armazenamento). Nesta área ficam armazenados blocos de armazenamento dos dados dos arquivos e também as estruturas chamadas de inodes. Um inode é um estrutura que possui as propriedades do arquivo e ponteiros para os blocos que contém os dados do arquivo. Tipicamente um sistema de arquivos possui uma lista de inodes que permite "indexar" cada um dos arquivos do sistema de arquivos. Existem vários formatos de sistema de arquivos, dependendo do sistema operacional. No linux os formatos mais conhecidos são: ext2, ext3, ext4 etc. Um sistema de arquivos normalmente possui uma estrutura de dados inicial chamada de superbloco. O superbloco traz informações sobre o tamanho de blocos do sistema, o início da lista de inodes (/), etc.
|
lista de inodes | blocos dos arquivos |
+-------------+-----------------+------------------------+ </syntaxhighlight>
DiretóriosSão arquivos especiais que contém basicamente uma lista contendo nome e inode correspondente dos arquivos que o diretório contém. Em um sistema de arquivos, o diretório / é o diretório raiz do sistema, a partir do qual pode-se encontrar todos os demais arquivos. Referência a um arquivoA localização de um arquivo pode ser realizada pela referência absoluta, ou seja, desde o diretório / do sistema: cat /etc/passwd O comando cat tem por objetivo mostrar no terminal o conteúdo do arquivo passwd. Para que este arquivo seja encontrado na árvore de diretórios, deve-se fornecer a referência absoluta, desde o diretório / Uma alternativa de acesso, é o uso da referência relativa ao diretório de trabalho. O conceito de diretório de trabalho é criado pelo interpretador de comandos (shell). Desta forma pode-se por exemplo fazer o comando: cat passwd O sistema procurará o arquivo passwd dentro do diretório de trabalho, que é armazenado pelo shell. Neste caso, o diretório de trabalho deveria ser /etc cd /etc cat passwd No Linux/Unix tudo é arquivoNo Linux, qualquer referência/acesso ao hardware/dispositivos é realizada na forma de acesso a arquivo. Ver arquivos no diretório de dispositivos: ls -l /dev Como consequência, a partir de um programa em C, é possível abrir e escrever/ler em um dispositivo (desde que se tenha autorização). Acessando arquivos a partir de programas CAcesso a arquivos: funções de baixo e alto nívelEm sistemas do porte do Linux e Windows, por questões de segurança e controle, todo acesso a arquivo é realizado através de código do sistema operacional. Desta forma, um programa que deseja acessar um arquivo deve gerar uma CHAMADA AO SISTEMA. O Linux (assim como outros sistemas) possui uma API (Application Programming Interface) bem definida, na forma de um conjunto de chamadas que permitem realizar uma série de funcionalidades (serviços) para os processos(programas em execução). Um programa em C realiza uma CHAMADA AO SISTEMA com auxílio de funções da biblioteca C (a glib no caso do Linux). Duas categorias de funções para acesso a arquivo são disponibilizadas (ver detalhes aqui):
Acesso a arquivo em MODO TEXTO através de funções de alto nívelO acesso em alto nível é realizado usando uma estrutura do tipo FILE definida no stdio.h. Todo acesso passa inicialmente por abrir o arquivo (função fopen), ler/escrever (várias funções, tipo fread(), fwrite()) e fechar o arquivo (fclose()).
Exemplo 1: Escrevendo e lendo um arquivo texto de forma formatadaNos exemplos que se seguem, serão usadas as funções fopen e fclose, para abrir e fechar arquivo e fprintf() e fscanf() para leitura e escrita. A forma é similar ao printf e scanf(ver http://diuf.unifr.ch/pai/ip/tutorials/c/TC02_scanf.pdf), a não ser pelo fato de que a escrita e leitura é realizada no arquivo indicado por p_arq #include <stdio.h>
void main()
{
FILE *p_arq;
int i;
int res;
if ((p_arq=fopen("IFSC.txt", "w")) == NULL) {
printf("Problemas na abertura do arquivo\n");
return;
}
for (i = 0; i<10;i++) {
/* A funcao fprintf devolve o número de bytes gravados ou EOF se houve erro na gravação */
if((res = fprintf(p_arq,"Linha %d\n",i))==EOF) {
printf("Erro\n");
break;
}
}
fclose(p_arq);
}
Note que se o arquivo IFSC.txt não existir, ele será criado. Para ver o que fois escrito faça: cat IFSC.txt #include <stdio.h>
void main()
{
FILE *p_arq;
int i,j;
int res;
char buff[100];
if ((p_arq=fopen("IFSC.txt", "r")) == NULL) {
printf("Problemas na abertura do arquivo\n");
return;
}
for (i = 0; i<10;i++) {
if((res = fscanf(p_arq,"%s %d",buff,&j))==EOF) {
printf("Fim de leitura\n");
break;
}
printf("%s %d\n",buff,j);
}
fclose(p_arq);
}
Note que o fscanf se comporta de forma similar ao scanf. A função retorna o caracter EOF (end-of-file) quando não existe mais dados a serem lidos.
Exemplo2Neste exemplo usaremos as funções fgetc e fputc para ler e cescrever caracteres ASCII nos arquivos. Seja um programa que conta o número de ocorrências do caracter 'a' em um arquivo e reescreve o arquivo sem os "as": #include <stdio.h>
#include <stdlib.h>
main()
{
FILE *fp_fonte,*fp_destino;
int x,cont=0;
if((fp_fonte=fopen("teste.dat","r")) == NULL) {
puts("Não conseguiu abrir o arquivo\n");
exit(1);
}
if((fp_destino=fopen("dest.dat","w")) == NULL){
puts("Não conseguiu abrir o arquivo\n");
exit(1);
}
/* note que fgetc retorna um inteiro contendo o ASCII lido */
while ((x=fgetc(fp_fonte)) != EOF){
if(x=='a')
cont++;
else
if((x=fputc(x,fp_destino))==EOF) {
puts("Não conseguiu abrir o arquivo\n");
exit(1);
}
}
printf("ocorrências de a = %d\n", cont);
fclose(fp_fonte);
fclose(fp_destino);
}
Note que fputc recebe o caracter como um inteiro mas realiza um cast para unsigned char com fins de escrevê-lo no arquivo. Exemplo 3Neste exemplo vamos explorar o modo de abertura do arquivo para fazer um append (escrever no final do arquivo). #include <time.h>
#include <stdio.h>
int main(void)
{
time_t ltime;
FILE *fp;
int num;
time(<ime);
if ((fp=fopen("DATA.txt", "a")) == NULL) {
printf("Problemas na abertura do arquivo\n");
return;
}
if ((num = fputs( ctime(<ime), fp )) != EOF ) {
fclose(fp);
} else {
printf("Erro na escrita do arquivo!\n");
}
}
Execute o programa da forma (suponha que se chame LOG_tempo: log_tempo cat DATA.txt log_tempo cat DATA.txt log_tempo cat DATA.txt
Acesso a arquivo em MODO BINÁRIO através de funções de alto nívelNeste exemplo vamos escrever e ler uma struct (com dados binários) usando fwrite e fread. Note que os dados são gravados de forma binária.
#include <stdio.h>
#include <stdlib.h>
struct TNum {
float x;
float y;
} Num = { 1.5,
2.6,
};
main()
{
FILE *fp;
int num_itens;
fp = fopen("data.bin", "wb");
num_itens = fwrite((char*)&Num, sizeof(struct TNum), 1, fp);
fclose(fp);
Num.x =0;
Num.y = 0;
fp = fopen("data.bin", "rb");
num_itens = fread((char*)&Num, sizeof(struct TNum), 1, fp);
printf("Valor de x = %f\n", Num.x);
fclose(fp);
}
Referências |
Apresentação do Projeto Final |
---|
Projeto FinalObjetivos
Apresentação do Projeto Final
Avaliação do Trabalho
Estrutura Base do ProjetoPara fims de organização vamos implementar inicialmente a seguinte estrutura: 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();
}
}
}
|
Ideias sobre o trabalho |
---|
Ideias sobre o trabalho#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct TUsuario /* struct TUsuario é o nome do tipo que está sendo criado */
{
char userID[20];
char senha[20];
struct TUsuario *next;
} *head, *tail;
void adicione_usuario_tail(struct TUsuario *p)
{
if (tail==NULL) {
tail = head = p;
}else {
tail->next = p;
tail = p;
}
}
void adicionar_usuario ()
{
struct TUsuario *p;
if ((p=(struct TUsuario *)malloc(sizeof(struct TUsuario)))==NULL) {
printf("Não é possível adicionar usuário ao sistema");
return;
}
printf("Entre com userID\n");
scanf("%s",p->userID);
printf("Entre com senha\n");
scanf("%s",p->senha);
p->next = NULL;
adicione_usuario_tail(p);
}
struct TUsuario *encontrar_usuario_lista(userID)
{
}
struct TUsuario *remover_usuario_lista(struct TUsuario *p)
{
}
void remover_usuario()
{
char userID[20];
struct TUsuario *p;
printf("Entre com userID do usuario a ser removido\n");
scanf("%s", userID);
p = encontrar_usuario_lista(userID);
if (!p)
printf("Usuário não existente\n");
else {
remover_usuario_lista(p);
printf("Usuário removido!\n");
}
}
main()
{
adicionar_usuario();
adicionar_usuario();
remover_usuario();
}
|
-->