PRG1-2014-1-Engenharia Programação 1 - Engenharia
PRG1 - PROGRAMAÇÃO I
DADOS DA DISCIPLINA
CARGA HORÁRIA
TOTAL: 72 HORAS (4 HORAS/SEMANA)
TEÓRICA: 36 HORAS
LABORATÓRIO: 36 HORAS
DIAS COM AULA: 36 (18 semanas)
AVALIAÇÂO
Avaliações Semanais
Toda semana nas quinta feiras (aproximadamente 16 avaliações) - conceito se possível na hora
- meses de avaliação (março a junho)
- a última avaliação do mês terá caráter de recuperação
- não será permitida a consulta na avaliação
PROJETO FINAL
- grupos com 3 alunos;
- avaliação individual.
RECUPERAÇÃO FiNAL
- Ficará para recuperação o aluno que não conseguiu obter o conceito mínimo para passar em pelo menos uma das etapas avaliadas (mês) OU não obteve o sucesso no PROJETO FINAL
- última aula do semestre
- recuperação toda matéria
PRÉ REQUISITOS: LÓGICA
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.
CRONOGRAMA DE AULAS
Aula | Data | Horas | Conteúdo | Recursos | |
---|---|---|---|---|---|
1 | 13/2 | 2 | Aula introdução a lógica de programa. Conceito de algoritmos. Representação de algoritmos. Fluxograma. Variáveis e constantes. Expressões com operadores aritméticos e de atribuição. | ||
2 | 14/2 | 2 | Estruturas de decisão. Expressões com operadores lógicos e relacionais. | ||
3 | 20/2 | 2 | Introdução a programação C. Declaração de variáveis inteiras, reais e char no C. Uso do compilador gcc. Estruturas de decisçao com if e i eles. Expressões com operadores aritméticos, lógicos e relacionais. Operador de atribuição. | ||
4 | 21/2 | 2 | Lógica de programação: estruturas de repetição usando fluxogramas | ||
5 | 27/2 | 2 | Estruturas de repetição com a linguagem C: while, do while, for, goto. Uso do break e do continue. Uso do gdb em linha de comando. | ||
6 | 28/2 | 2 | Exercícios de Fixação | ||
7 | 6/3 | 2 | Estruturas de decisão. Comando switch. Outros comandos. Precedência de operadores no C. | ||
8 | 7/3 | 2 | Exercícios de Fixação. | ||
9 | 13/3 | 2 | Lógica de programação: quebrando problemas em subproblemas. Uso de subrotinas. Funções no C. Passagem de parâmetro e retorno de valor. AVALIAÇÂO 1 | ||
10 | 14/3 | 2 | Conceito de vetores. Vetores no C | ||
11 | 20/3 | 2 | Exercícios de vetores. AVALIAÇÂO 2 | ||
12 | 21/3 | 2 | Strings no C. Processamento de Strings. Exercícios | ||
13 | 27/3 | 2 | Strings no C. Processamento de Strings. AVALIAÇÂO 3 | ||
14 | 28/3 | 2 | Strings no C. Processamento de Strings. Exercícios | ||
15 | 3/4 | 2 | Exercícios de Fixação; AVALIAÇÂO 4 | ||
16 | 4/4 | 2 | RECUPERAÇÃO I | ||
17 | 10/4 | 2 | Operação com Matrizes no C | ||
18 | 11/4 | 2 | Exercícios com matrizes. AVALIAÇÃO 5 | ||
19 | 17/4 | 2 | Estruturas | ||
20 | 24/4 | 2 | Exercícios. AVALIAÇÂO 6 | ||
21 | 25/4 | 2 | Estruturas e vetores (Tabelas com estruturas). Typedef | ||
22 | 8/5 | 2 | Exercícios. AVALIAÇÃO 7 | ||
23 | 9/5 | 2 | RECUPERAÇÃO II | ||
24 | 15/5 | 2 | Tópicos adicionais: diretivas de préprocessamento. Compilação condicional; | ||
25 | 16/5 | 2 | Ponteiros – parte 1 | ||
26 | 22/5 | 2 | Exercícios. AVALIAÇÃO 8 | ||
27 | 23/5 | 2 | Ponteiros – parte 2 | ||
28 | 29/5 | 2 | Exercícios. AVALIAÇÃO 9 | ||
29 | 30/5 | 2 | Uso do make. Apresentação do Projeto Final. | ||
30 | 5/6 | 2 | Operação com arquivos – parte 1 | ||
31 | 6/6 | 2 | Exercícios. AVALIAÇÃO 10 | ||
32 | 12/6 | 2 | Operação com arquivos – parte 2 | ||
33 | 13/6 | 2 | Exercícios. AVALIAÇÂO 11 | ||
34 | 26/6 | 2 | RECUPERAÇÃO III | ||
35 | 27/6 | 2 | Projeto Final – Avaliação | ||
36 | 3/7 | 2 | Aula de Recuperação | ||
37 | 4/7 | 2 | Aula de Recuperação | ||
38 | 10/7 | 2 | Aula de Recuperação | ||
39 | 11/7 | 2 | RECUPERAÇÂO FINAL | ||
40 | / | ||||
TOTAL | 78 |
Resultados parciais
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
AULAS
AULA 1 DIA 13/02/2014 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
AULA 1 DIA 13/03/2014Como fazer um churrascoVamos observar atentamente este vídeo para iniciarmos o nosso curso de programação: EmbedVideo received the bad id "U0xSYIXE9vo#!" for the service "youtube". O que tem o churrasco com a nossa aula?? Trata-se de uma sequência de passos para execução de um objetivo. EXERCÍCIO: Na forma textual, descrever as etapas para fazer um bom churrasco. O que é um algoritmoUm algoritmo pode ser visto como uma sequência de instruções ou operações que resolvem um dado problema. A receita de um bom churrasco corresponde a um algoritmo. Como representar um algoritmo ?Uma forma é representar na forma textual ordenada: 1.Comprar a carne 2.Colocar carvão na churrasqueira 3.Acender o carvão 4.Cortar a carne (picanha) 5.Espetar a carne 6.Salgar a carne 7.Colocar a carne na churrasqueira 8.Aguardar a carne ficar no ponto desejado 9.Bater a carne 10.Servir a carne Outras formas são mais apropriadas para o uso no meio computacional:
A PENSAR: É possível mudar a ordem das instruções? É possível paralelizar algumas instruções?
E para quem são os algoritmos?Uma receita de bolo é apropriada para ser executada por um ser humano. Um procedimento de como trocar um pneu também. Mas muitas vezes queremos que o algoritmo seja executado por uma máquina! O computador é perfeito para isto! Neste curso vamos nos concentrar no desenvolvimento de algoritmos simples, desde a sua concepção até a sua implementação através de uma LINGUAGEM DE PROGRAMAÇÃO - a linguagem C , por exemplo. Um PROGRAMA implementa um algoritmo. É o algoritmo materializado na forma de uma sequência de instruções. Neste sentido, vamos entender minimamente o funcionamento de um computador (próxima aula) A Descrição de Algoritmos usando FluxogramasUm fluxograma é uma linguagem semi-gráfica que pode ser utilizada para descrição de algoritmos. Exemplo: O algoritmo de cálculo da média de dois números: Pontos fortes:
Ponto fraco:
Observe no exemplo anterior que nada é dito sobre as variáveis NUM1, NUM2 e MEDIA. Símbolos de um FluxogramaTeste de MesaConstantes, VariáveisAlgoritmos operam sobre dados. O que podem ser estes dados? Variáveis e Constantes No exemplo anterior podemos identificar três variáveis NUM1, NUM2 e MEDIA Também podemos identificar uma CONSTANTE. O número 2.
Ex: NUM1 = 5.5 /* NUM1 é uma variável real */
Ex: RES = TRUE /* RES é uma variável booleana */
Ex: LETRA = 'A'
Ex: FRASE = "ALO MUNDO" E como estas variáveis armazenam os dados?? Depende da linguagem usada. Vamos passar uma primeira noção do C ExpressõesExpressões sentenças que relacionam variáveis e constantes através de operadores matemáticos e que RESULTAM em um valor. A instrução do algoritmo: MEDIA = (NUM1 + NUM2) / 2 será considerada como uma expressão, que usa os operadores '+', '/' e '=' O operador '=' é um OPERADOR DE ATRIBUIÇÃO e indica que a expressão do lado direito do '=' será atribuída a variável do lado esquerdo. Neste curso, para mantermos coerência com a Linguagem C, consideraremos que a expressão como um todo resulta no valor que é atribuído a variável. Operadores AritméticosOs operadores aritméticos que usaremos neste curso serão os disponíveis no C:
O único operador desconhecido aqui é o resto, cujo significado é o resto entre dois númerosinteiros. Exemplo, se B possui o valor 9, então o resultado da atribuição na expressão: A = B%2 será 1. Representando o algoritmo com pseudo-código
|
AULA 2 DIA 14/02/2014 | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
AULA 2 DIA 14/02/2014ObjetivosO aluno deverá saber utilizar comandos e expressões em pseudo-código e fluxogramas usando:
Expressões com operadores relacionaisNa aula anterior estudamos como construir expressões usando operadores aritméticos e o operador de atribuição. Vamos continuar este tópico aumentando o poder das expressões através dos operadores relacionais e lógicos. Os operadores relacionais permitem realizar comparações entre dois operandos. Os operadores são os seguintes:
Note que com operadores lógicos podemos construir expressões tais como indicado no exemplo abaixo: Exemplo: O algoritmo abaixo lê dois número inteiros para dentro das variáveis A e B e atribue à variável X o resultado da comparação do primeiro com o segundo. Observe que a variável X é do tipo booleano.
|
AULA 3 DIA 22/02/2014 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
AULA 3 DIA 22/02/2014ObjetivosO aluno devera ser capaz de:
Possíveis linguagens de programaçãoNa prática, é inviável desenvolver programas complexos em LINGUAGEM DE MÁQUINA. Em geral, utilizamos linguagens de ALTO NÍVEL que podem, de alguma forma, serem traduzidas (compiladas) para a linguagem de baixo nível ou interpretadas em tempo de execução. Exemplo:
Neste curso utilizaremos a linguagem C. Por que? É uma linguagem muito usada na implementação de produtos eletrônicos, incluindo àqueles voltados as Telecomunicações. Introdução a linguagem C
EmbedVideo received the bad id "rGCbvqz6Kt4#!" for the service "youtube".
Visão geral do processo de compilação com gcc
Compilando um programa CNeste curso usaremos o compilador da coleção gcc do projeto GNU. O manual completo do gcc pode ser encontrado aqui. O processo de desenvolvimento do programa envolve:
mkdir ExerciciosC cd Exercicios Exemplo: salve o programa abaixo como teste.c
#include <stdio.h>
main()
{
printf("Alo Mundo\n");
}
gcc teste.c -o teste
./teste Nota: o atributo -o permite que se forneça um nome para o executável diferente de a.out É possível somente compilar (gerar código objeto): gcc -c teste.c Observe os subprodutos listando com detalhes: ls -l Estrutura do Programa em CUm programa em C pode ser visto como um conjunto de uma ou mais funções:
#include <stdio.h>
main()
{
printf("Alo Mundo\n");
}
No programa acima temos uma única função: a função main() Uma função é um pedaço de código delimitado por chaves e com um nome. Todo programa C bem comportado deve ter um função main. A primeira instrução desta função é o ponto de entrada do código do usuário. A primeira instrução do programa acima é uma chamada a uma função da biblioteca: o printf(). Esta função permite mostrar dados no terminal. Não é possível colocar instruções fora de funções! Vamos ver algumas variações do Alo Mundo: #include <stdio.h>
main()
{
printf("Alo Mundo 1\n");
printf("Alo Mundo 2\n");
printf("Alo Mundo 3\n");
printf("Alo Mundo 4\n");
printf("Alo Mundo 5\n");
}
e #include <stdio.h>
main()
{
printf("Alo Mundo 1");
printf("Alo Mundo 2\n");
printf("Alo Mundo 3\n\n");
printf("Alo Mundo 4\n");
printf("Alo Mundo 5\n");
}
Observe nestes exemplos a ordem de execução das instruções e o uso do caracter de nova linha. Declarando variáveis inteiras e reais locaisNo "c" temos que declarar as variáveis que serão utilizadas no programa. Se estas variáveis forem declaradas DENTRO da função elas serão "vistas" somente localmente (escopo local). Este conceito será estendido para blocos de códigos posteriormente.
#include <stdio.h>
main()
{
/* aqui começam as declarações de variáveis */
int x; /* declaração de uma variável inteira */
float y; /* declaração de uma variável real */
/* aqui começam as instruções do programa principal */
x=5; /* atribuindo o valor 5 (constante) a variável x */
y=6.5;
}
No exemplo anterior criamos duas variáveis : x e y. Lembrando que variáveis podem ser vistas como um lugar que pode armazenar um valor. Para simplificar ainda mais, podemos imaginar a variável como uma CAIXA onde podemos armazenar um valor. A CAIXA possui um nome e um tipo. O nome IDENTIFICA a CAIXA enquanto o tipo da variável determina a natureza dos valores que podemos armazenar na CAIXA: +-----+ | 5 | x +-----+ A variável x é do tipo int e, portanto, está apta a armazenar valores inteiros. Já a variável y é do tipo float e está apta a receber valores reais. +-----+ | 6.5 | y +-----+ Observe que as instruções de atribuição acima envolvem constantes também. Funções de entrada e saída de dadosNo "c" não existe instrução especialmente para leitura ou saída de dados. Este procedimento é realizado através de funções da biblioteca. Na sequência são mostradas duas funções "clássicas" de entrada e saída de dados: o printf() - já apresentado - e o scanf(). Esta última função permite entrada de dados.
#include <stdio.h>
main()
{
int x; /* declaração de uma variável inteira */
float y; /* declaração de uma variável real */
printf ("Entre com o valor de x ");
scanf("%d",&x);
printf ("Entre com o valor de y ");
scanf("%f",&y);
printf ("O valor de x é %d\n",x);
printf ("O valor de y é %f\n",y);
}
Uma variação do uso do printf neste exemplo é: #include <stdio.h>
main()
{
int x; /* declaração de uma variável inteira */
float y; /* declaração de uma variável real */
printf ("Entre com o valor de x ");
scanf("%d",&x);
printf ("Entre com o valor de y ");
scanf("%f",&y);
printf ("O valor de x é %d e o valor de y é %f\n",x, y);
}
Construindo expressões no COperador de AtribuiçãoO operador de atribuição = é amplamente usado para atribuir valores para variáveis. Veja o exemplo abaixo. Dois números do tipo float são lidos para as variáveis x e y e a média é calculada e colocada na variável média. #include <stdio.h>
main()
{
float x,y;
float media;
printf("Entre com x\n");
scanf("%f", &x);
printf("Entre com y\n");
scanf("%f", &y);
media = (x+y)/2;
printf("Valor de media = %f\n",media);
}
Um diferencial do C com relação a outras linguagens é que a atribuição pode ser realizada várias vezes dentro de uma mesma instrução. Veja o exemplo: #include <stdio.h>
main()
{
int x,y,w;
x=1;
w=y=x+1;
printf("x=%d y=%d w=%d\n", x,y,w);
w=2*(y=x+1);
printf("x=%d y=%d w=%d\n", x,y,w);
}
NOTE que o código: w=2*y=x+1; produz um erro de compilação: erro: lvalue required as left operand of assignment Ver conceito de lvalue e rvalue aqui. O problema é que A ESQUERDA do sinal de atribuição sempre deve existir uma referência a uma área de memória (normalmente uma variável). A semântica da atribuição é copiar o valor computado a direita PARA a área referenciada a esquerda. Operadores aritméticosOs operadores aritméticos básicos são àqueles apresentados na aula anterior.
Exercícios
|
AULA 4 DIA 21/02/2014 | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Objetivos
Operadores Relacionais e LógicosOs operadores relacionais e lógicos são os mesmos vistos na aula anterior.
Ver Operadores Relacionais e Lógicos Comandos de decisão if() e if() else
#include <stdio.h>
main()
{
int x; /* declaração de uma variável inteira */
int y; /* declaração de uma variável inteira */
printf ("Entre com o valor de x ");
scanf("%d",&x);
printf ("Entre com o valor de y ");
scanf("%d",&y);
if (y>x)
printf("MSG1:y é maior que x\n");
if (y>x)
printf("MSG2:y é maior que x\n");
else
printf("MSG3:y é igual ou menor que x\n");
}
Outro exemplo, usando blocos:
#include <stdio.h>
main()
{
int x,y,z; /* declaração de uma variável inteira */
printf ("Entre com o valor de x ");
scanf("%d",&x);
printf ("Entre com o valor de y ");
scanf("%d",&y);
if (y>x) {
printf("MSG1: y é maior que x\n");
z = y-x;
printf("MSG2: Neste caso z = %d\n", z);
} else {
printf("MSG3: y é igual ou menor que x\n");
z = x-y;
printf("MSG4: Neste caso z = %d\n", z);
}
}
No C, qualquer expressão que resulta em 0 é considerada FALSA e qualquer expressão com valor diferente de 0 é VERDADEIRA. Exemplo: if (2)
printf("expressão sempre VERDADEIRA");
if ('2')
printf("expressão sempre VERDADEIRA");
if (1-1)
printf("expressão sempre FALSA");
if (x=1) /* um erro comum - sinal de atribuição no lugar de == */
printf("expressão sempre VERDADEIRA");
Tipo CharUma variável do tipo caracter é tratada como um número inteiro e declarada com o tipo char, que na prática é um número inteiro de byte. Exemplo #include <stdio.h>
main ()
{
char x='A',y=65,w=0x41,z;
scanf("%c",&z);
printf("Caracter lido = %c\n",z);
printf("Caracter lido = %d\n",z);
printf("Caracter lido = %x\n",z);
if (z==x)
printf("Iguais 1\n");
if (z==y)
printf("Iguais 2\n");
if (z==w)
printf("Iguais 3\n");
}
IndentaçãoExercícios
|
AULA 5 DIA 27/02/2014 |
---|
AULA 6 DIA 29/08/2013ObjetivosO aluno deverá ser capaz de colocar estruturas de repetição especificadas em fluxogramas ou pseudo-código na forma de estruturas em linguagem C. 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. O comando while():teste da repetição no começoO comando while permite implementar loops com controle no início: #include <stdio.h>
main()
{
int contador;
contador=0;
while (contador<5) {
printf("valor do contador = %d\n", contador);
contador=contador+1;
}
}
Variação do exemplo anterior: #include <stdio.h>
main()
{
int contador;
contador=0;
while (contador<5) {
printf("valor da expressão = contador < 5 é %d\n", contador<5);
printf("valor do contador = %d\n", contador);
contador=contador+1;
}
printf("NO FINAL a expressão contador < 5 é %d\n", contador<5);
}
A estrutura do comando, informalmente, é: while (expressão) instrução_simples; ou while (expressão) { lista_de_instruções } Vamos ver a correspondência do comando while com um fluxograma: NOTE que no exemplo anterior o contador inicialmente DEVE conter um valor válido. Comando do while: controle do loop no finalO 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. #include <stdio.h>
main()
{
int contador;
contador=0;
do {
printf("valor do contador = %d\n", contador);
contador=contador+1;
} while (contador<5);
}
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. #include <stdio.h>
main()
{
int i;
for (i=0;i<10;i=i+1)
printf("i =%d\n",i);
}
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 } Aninhamento de loops#include <stdio.h>
main()
{
int i,j;
for (i=0;i<3;i++) {
for (j=0;j<4;j++) {
printf("valor de j = %d\n", j);
}
printf("valor de i = %d\n", i);
}
}
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 */
}
}
aaaaaaaaaa a a aaaaaaaaaa |
AULA 6 DIA 28/02/2014 |
---|
Exercícios 1.Usando o comando for aninhado, construa um programa que implemente a figura abaixo. A margem esquerda (margem de espaços), o caracter do desenho, o número de linhas vazadas e o tamanho horizontal da figura deve ser lido pelo teclado. aaaaaaaaaa a a aaaaaaaaaa #include <stdio.h>
main()
{
int i, j,num_linhas, num_colunas, margem;
printf("Entre com linhas\n");
scanf ("%d",&num_linhas);
printf("Entre com colunas\n");
scanf ("%d",&num_colunas);
printf("Entre com margem\n");
scanf ("%d",&margem);
/* subproblema 1 */
for (i=0;i<margem;i=i+1)
printf(" ");
for (i=0;i<num_colunas;i=i+1)
printf("A");
printf("\n");
/*subproblema 3 */
for(j=0;j<num_linhas-2;j++) {
/*subproblema 2 */
for (i=0;i<margem;i=i+1)
printf(" ");
printf("A");
for(i=0;i<num_colunas-2;i=i+1)
printf(" ");
printf("A");
printf("\n");
}
/* subproblema 1 */
for (i=0;i<margem;i=i+1)
printf(" ");
for (i=0;i<num_colunas;i=i+1)
printf("A");
printf("\n");
}
2.Construa um programa para desenhar a seguinte figura de forma parametrizável: AAAAAAAAAAAAAAAA AAAAAAAAAAAAAA AAAAAAAAAAAA AAAAAAAAAA AAAAAAAA AAAAAA AAAA AA BB BBBBB BBBBBBBB BBBBBBBBBBB BBBBBBBBBBBBBB BBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBB 3.#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;
}
srand ( time(NULL) ); iSecret = rand() % 10 + 1; 4.Sobre o exercício 3, implemente uma versão usando o comando while(). 5.Elabore um programa que lê um número inteiro e imprime todos os números pares entre 1 e este número.
|
AULA 7 DIA 6/03/2014 |
---|
AULA 7 DIA 6/03/2014Objetivos
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;
("valor de i = %d\n", i);
}
}
Uso do continue para prosseguir no início do loop#include <stdio.h>
main()
{
int i,j;
for (i=0;i<3;i++) {
if (i==1) {
continue;
}
printf("valor de j = %d\n", j);
for (j=0;j<4;j++) {
if (j==1) {
continue;
}
printf("valor de j = %d\n", j);
}
}
}
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
Usando funções da biblioteca matemáticaPara usar as funções matemáticas da biblioteca padrão, fazer os seguintes passos:
#include <stdio.h>
#include <math.h>
main()
{
float x,y; /* declaração de duas variáveis reais */
printf ("Entre com o valor de x ");
scanf("%f",&x);
y = sqrtf(x);
printf ("Raiz de x = %lf", y);
}
NOTA: a maior parte de parâmetros e valores de retorno das funções matemáticas são reais de dupla precisão (double).
gcc ex1.c -o ex1 -lm EXERCÍCIOS
|
AULA 8 DIA 7/03/2014 |
---|
AULA 8 DIA 7/03/2014Exercícios
|
AULA 9 DIA 13/03/2014 |
---|
AULA 9 DIA 13/03/2014ObjetivosO aluno deverá ser capaz de:
Quebrando um problema em subproblemas: SUBPROGRAMASPROBLEMA: Aprimorar o exemplo do controle de acesso para que, no caso de 3 tentativas de acesso seguidas, com senha errada, o sistema seja bloqueado.
Note que a variável CONT_ACESSO é iniciada com zero e incrementada a cada erro no fornecimento da senha. A atribuição CONT_ACESSO = CONT_+ACESSO + 1 deve ser interpretada da forma: acesse o valor de CONT_ACESSO e some 1 a este valor. Coloque o resultado novamente em CONT_ACESSO (o conteúdo anterior é sobrescrito!) Neste procedimento pode ser observado que:
Em síntese, existem subproblemas adicionais a serem resolvidos. Como podemos resolvê-los sem deixar um fluxograma complexo? Usaremos a caixa de processos pré-definidos que usaremos para invocar funções que resolvem determinado subproblema. Inicialmente, vamos construir três subprogramas:
OBS: Note que foi usada uma variável auxiliar AUX que permite ajustar o valor de número de acessos a ser mostrado no display. Note também que na caixa DISPLAY foi usado uma string a ser impressa e a variável AUX cujo conteúdo deve ser impresso. Ambos separados por vírgula. PARÂMETROS E RETORNO DE VALORES EM SUBPROGRAMASPara tornar ainda mais interessante o uso de subprogramas, vamos ver o conceito de passagem de parâmetros e retorno de valores. Quando chamamos (invocamos) um subprograma podemos passar valores (dados de entrada) para este subprograma. Estes valores são passados através de variáveis especiais que chamamos de parâmetros. Parâmetros podem ser passados por valor e por referência. Por valor é quando os dados a serem passados na invocação do subprograma são copiados para uma variável do subprograma. Os parâmetros são passados por referência quando o que é passado para o subprograma é simplesmente o endereço da variável repassada na invocação do subprograma. Não existe uma forma explícita de definir os parâmetros em um fluxograma. Deve-se realizar um comentário antes ou ao lado do mesmo especificando o tipo e como será tratado o parâmetro. EXEMPLO: Seja elaborar um fluxograma correspondente a uma subprograma que deve calcular o fatorial de um número inteiro passado como parâmetro. O subprograma deve retornar o valor calculado. A função fatorial é definida por: Neste fluxograma, o subprograma denominado CalcFatorial recebe um valor no parâmetro N (implicitamente inteiro) e retorna o valor calculado do fatorial. O fluxograma principal invoca duas vezes o subrograma. O retorno é armazenado nas variáveis NUM1 e NUm3. Quando um subprograma retorna um valor, ele é chamado de função. Para manter coerência com o C chamaremos qualquer subrprograma de função (independente de retornar valor).
Exemplo de Função usando pseudo-códigoSeja uma função que retorna a média de 5 números reais passados como parâmetros:
|
AULA 10 DIA 20/03/2014 |
---|
AULA 10 DIA 20/03/2014Objetivos
Exercícios sobre funções
|
AULA 11 DIA 27/03/2014 |
---|
AULA 13 DIA 27/03/2014Objetivos
Comando switchO comando switch permite controlar o fluxo de um programa de forma condicional. O comando testa uma expressão que deve resultar em um número inteiro. Uma sequência de cláusulas case permite executar uma sequência de instruções conforme o valor da expressão. Note que esta sequência de instruções pode ser interrompida por um break. #include <stdio.h>
int x=1;
main ()
{
int opcao;
printf("Entre com uma opção (número inteiro)\n");
scanf ("%d",&opcao);
switch(opcao) {
case 1:
printf("opcao 1\n");
break; /* o break força o encerramento da instrução*/
case 2:
printf("opcao 2\n");
x++; /* instrução demonstrativa apenas */
printf("Note que pode existir ums lista de instruções\n");
break;
case 3:
printf("opcao 3\n"); /* note o efeito de não ter o break */
case 4:
printf("opcao 4\n");
break;
case 5:
printf("opcao 5\n");
break;
default:
printf("opcao default\n");
break; /* a opção default é opcional */
}
Exercício 1 Implementar um programa de calculadora onde são fornecidos via scanf dois operandos reais e uma operação que pode ser uma das 4 operações. Com auxílio de um switch deve ser computado e mostrado o resultado da operação. Solução: #include <stdio.h>
main ()
{
float operando1, operando2, res;
char operador;
printf("Entre com operando 1\n");
scanf ("%f",&operando1);
printf("Entre com operando 1\n");
scanf ("%f",&operando2);
printf("Entre com operador\n");
scanf (" %c",&operador);
switch(operador) {
case '+':
res = operando1 + operando2;
printf("Valor da soma = %f\n", res);
break;
case '-':
res = operando1 - operando2;
printf("Valor da diferença = %f\n", res);
break;
case '*':
res = operando1 * operando2;
printf("Valor da diferença = %f\n", res);
break;
case '/':
if (operando2 != 0) {
res = operando1 / operando2;
printf("Valor da diferença = %f\n", res);
} else
printf("Divisão por zero não permitida!\n");
break;
default:
printf("Operação inválida!\n");
break;
}
}
Exercício 2 Elaborar uma função que recebe como parâmetro um número inteiro de 1 a 7. A função deve imprimir Domingo se o número é 1, Segunda se 2 etc. A função deve retornar -1 caso o parâmetro esteja fora da faixa e 0 caso contrário. Solução:/* contribuição do aluno Iago */
#include <stdio.h>
int operar(int x)
{
switch(x) {
case 1:
printf("Domingo\n");
break;
case 2:
printf("Segunda\n");
break;
case 3:
printf("Terça\n");
break;
case 4:
printf("Quarta\n");
break;
case 5:
printf("Quinta\n");
break;
case 6:
printf("Sexta\n");
break;
case 7:
printf("Sábado\n");
break;
default:
printf("-1\n");
return -1;
}
return 0;
}
main()
{
int num;
printf("Entre com um número:\n");
scanf("%d",&num);
num=operar(num);
printf("%d\n",num);
}
Exercício 3 Um funcionário irá receber um aumento de acordo com o seu plano de trabalho, de acordo com a tabela abaixo [3]: Plano Aumento A 10% B 15% C 20% Faça um programa que leia o plano de trabalho e o salário atual de um funcionário e calcula e imprime o seu novo salário. Use o comando switch. Exercício 4 Faça um programa que leia um número entre 0 e 10, e escreva este número por extenso. Use o comando switch. |
AULA 12 DIA 28/03/2013 |
---|
AULA 12 DIA 28/03/2013ObjetivosO aluno deverá:
ARRAYS UNIDIMENSIONAIS (VETORES)Um vetor pode ser visto como uma variável que pode ser indexada e onde em cada posição existe um elemento do vetor. Os elementos do vetor possuem um tipo único. Uma boa analogia é comparar o vetor com uma tabela de tamanho fixo onde em cada linha pode ser armazenado um elemento. PROBLEMA: Ler 10 números inteiros para um vetor de inteiros. Computar um segundo vetor que é o resultado da multiplicação por um escalar inteiro 5. DADO DE ENTRADA: Os 10 números armazenados em VET1 DADO DE SAÍDA: VET2, o vetor resultado da multiplicação de VET1 por 5.
Exercício 1: Implementar um algoritmo para ler 10 números inteiros para um vetor e imprimir o número de números acima da média. OBS: Definir um contador, iniciado em zero. Calcular a media e fazer um loop sobre o vetor testando cada item para verificar se é maior que a média. Definindo e usando vetores no CUm vetor pode ser facilmente definido no C da forma: TipoVetor NomeDoVetor[dimensao]; O algoritmo do fluxograma implementado anteriormente ficaria da seguinte forma em C: #include <stdio.h>
main()
{
int vet1[5],vet2[5];
int i;
for(i=0;i<5;i++) {
printf("Entre com vet[%d] => ",i);
scanf("%d",&vet1[i]);
vet2[i]=vet1[i]*5;
}
/* para conferir- vamos imprimir o conteúdo de vet2 */
for(i=0;i<5;i++)
printf("vet2[%d] => %d\n",i,vet2[i]);
}
Vamos a um exemplo que mostra as possibilidades de acesso a um vetor: 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]);
i=2;
x[i*2]=i*1.5; /* usando uma expressão como índice */
while (i<8) { /* usando loop para acessar o vetor */
x[i]=0.0;
i++;
}
}
NOTA: vetores na Linguagem C começam SEMPRE na posição 0 Iniciando vetores em CPode-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]);
}
Passando vetores como parâmetrosVetores não são copiados na passagem por parâmetro. Eles são passados sempre como referência. Veja o exemplo a seguir: #include <stdio.h>
void ler_vet(int aux[5])
{
int i;
for (i=0;i<5;i++) {
printf("aux[%d] <== ",i);
scanf("%dd",&aux[i]);
}
}
main()
{
int vet[5], i;
ler_vet(vet);
for (i=0;i<5;i++)
printf("vet[%d]=%d\n",i,vet[i]);
}
Note como é realizada a declaração de parâmetros que são vetores. Observe no exemplo, que o vetor aux é na realidade o próprio vetor vet. Inicialmente dados são lidos para aux e depois vet é impresso. Não é obrigatório definir o tamanho do vetor na declaração de parâmetros. Na realidade o C não verifica o acesso indevido a um elemento fora do tamanho do vetor. Exercícios
#include <stdio.h>
main()
{
float x[10];
float soma = 0, media;
int i, cont;
/* leitura do vetor */
i=0;
while (i<10) {
printf("Entre com x[%d] -> ", i);
scanf("%f",&x[i]);
soma = soma + x[i];
i++;
}
/* calculo da media */
media = soma /10;
/* computação de números acima da média */
cont = 0;
i=0;
while (i<10) {
if (x[i] > media)
cont++;
i++;
}
printf ("Número de números acima da média = %d\n", cont);
}
Exemplo: Para os vetores x[]={1,1,3,4,5} e y[]={1,2,3,3,5} temos três elementos iguais (nas posições 0, 2 e 4). |
AULA 14 DIA 3/04/2014 |
---|
AULA 14 DIA 3/04/2014Objetivos
Implementar uma função C que recebe como parâmetros um vetor de inteiros e o tamanho do vetor. A função deve retornar a média dos números ímpares contidos neste vetor. Fazer uma função main demonstrando o uso da função. Exercício 2: Elaborar um programa C que lê duas resistências em ohms, e uma tensão aplicada sobre eles. O programa apresenta um menu da forma: 1.Calcular potência dissipada no resistor equivalente série. 2.Calcular a potência dissipada no resistor equivalente paralelo. 3.Encerrar programa. Usar um comando switch e um comando do while para controle de execução.
Exercício 1A: Elaborar uma função que recebe como parâmetro um vetor de floats e o tamanho deste vetor. A função deve retornar a média de todos os números contidos no vetor que estão dentro da faixa 50.0 e 125.5 (inclusive). Construir uma função main para demonstrar o funcionamento. Exercício 1B: Elaborar uma função que recebe como parâmetro um vetor de floats e o tamanho deste vetor. A função deve retornar a média de todos os números contidos no vetor que estão dentro da faixa 50.0 e 125.5 (inclusive). Construir uma função main para demonstrar o funcionamento. Exercício 2: Elaborar um programa que lê três números inteiros e então apresenta um menu de opções: 1.Calcular a soma dos fatoriais dos números. 2.Ordenar os números de forma decrescente. 3.Sair Usar os comandos switch e do while. Se a opção é não sair então o programa deve voltar a ler os números.
|
AULA 15 DIA 4/04/2014 | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
AULA 15 DIA 4/04/2014Objetivos
Tipo CharEm aulas anteriores vimos que um caracter pode ser representado por uma sequência de bits. Utilizando um código é possível definir o significado da sequência. Um código amplamente usado é o ASCII. Com 8 bits (7 no Ascii original) tem-se então a possibilidade de representar qualquer letra, número, ou símbolo (vírgula, ponto-e-vírgula etc). Note que um número representado em ASCII NÂO serve para realizar operações aritméticas. Trata-se de representação textual, por exemplo, um dígito de um número telefone. Em síntese, uma variável do tipo caracter é tratada como um número inteiro e declarada com o tipo char, que na prática é um número inteiro de byte. Exemplo #include <stdio.h>
main ()
{
char x='A',y=65,w=0x41,z; /* três formas de representar a mesma coisa */
scanf("%c",&z);
printf("Caracter lido = %c\n",z);
printf("Caracter lido = %d\n",z);
printf("Caracter lido = %x\n",z);
if (z==x)
printf("Iguais 1\n");
if (z==y)
printf("Iguais 2\n");
if (z==w)
printf("Iguais 3\n");
}
Armazenamento de cadeias de caracteres em vetoresUma cadeia de caracteres ou string nada mais é que uma sequência de caracteres ASCII. Para mantermos coerência com a linguagem C, vamos assumir que uma string bem comportada termina com um zero (0, não o caracter '0' que é o número 48 decimal em ASCII). Em inglês chama-se "string NULL terminated". Exemplo: A string "IFSC" armazenada em um vetor CADEIA, na memória de um computador, teria a seguinte implementação: Estamos assumindo que cada caracter é armazenado em um byte. Uma string terminada em 0 facilita o seu processamento pois pode-se facilmente detectar o seu final. Note que no exemplo acima, a string está armazenada em um vetor CADEIA cujo tamanho excede ao da string. Os bytes que se seguem ao zero podem ser considerados lixo. Processando cadeias de caracteresSabendo como uma string é armazenada na memória de um computador torna-se fácil processá-la. Por exemplo, vamos ver um algoritmo para contar o número de caracteres de uma string lida pelo teclado para dentro de um vetor CADEIA. EXERCÍCIO 1: Colocar o procedimento acima na forma de um subprograma (função) que recebe como parâmetro o vetor e retorna um número inteiro correspondente ao tamanho da cadeia. EXERCÍCIO 2: Elaborar um fluxograma para computador o número de ocorrências do caracter 'b' em uma string lida pelo teclado. Apresentá-lo na forma de um subprograma que retorna o número de ocorrências. EXERCÍCIO 3: Estude a tabela ASCII e elabore um fluxograma para capitalizar todos os caracteres minusculos de uma string lida pelo teclado. Apresentá-lo como subprograma. Vetor de CharNo C é 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);
}
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;
}
Processamento de stringsNas aulas anteriores vimos como definir e usar 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. Computando o tamanho de uma stringA função abaixo permite computar o tamanho de uma string. 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 stringsDa mesma forma que o exmplo anterior, implementar uma função similar a função strcat que permite concatenar duas strings passadas como parâmetro. #include <stdio.h>
void str_cat(char auxs1[], char auxs2[])
{
int i=0;
/*localizar o final da string de destino*/
while(auxs1[i]!=0)
i++;
/* usando a função de cópia já implementada temos */
str_cpy(&auxs1[i], auxs2);
}
main()
{
char str1[100]="IFSC em ", str2[100]="Sao Jose", x[]="teste";
str_cat(str1, str2);
printf("\nString copiada = %s\n", str1);
}
AVALIAÇÂO 5
#include <stdio.h>
#define NUM_FORN 3
#define NUM_PECAS 5
struct tipo_endereco{
char rua[30];
int numero;
char cidade[30];
};
struct tipo_fornecedor{
char fornID[10];
struct tipo_endereco endereco;
};
struct tipo_peca{
char pecaID[10];
int num_estoque;
float preco;
char fornID[10];
};
struct tipo_fornecedor fornecedores[NUM_FORN] = {
{"alfa",{"Rua Joao da Silva",1,"Florianopolis"}},
{"beta",{"Rua Jose Cabral",10,"Sao José"}},
{"gama",{"Rua Manuel da Silva",30,"Palhoça"}},
};
struct tipo_peca estoque_pecas[NUM_PECAS]={
{"A100",34,2.50,"alfa"},
{"B100",64,5.50,"alfa"},
{"A200",100,6.50,"beta"},
{"B200",21,8.50,"alfa"},
{"B300",82,10.00,"gama"},
};
/* a função retorna o número de peças em estoque relativas a um dado fornecedor */
/* a função retorna 0 se não existe peças do fornecedor */
int total_pecas_por_fornecedor (char fornID[])
{
}
/* a função dá baixa no estoque de uma quantidade de uma dada peca*/
/* a função retorna -1 se ID inválido */
int baixa_em_estoque(char pecaID[], int num_pecas)
{
}
/* a função retorna o indice (indexador na tabela de fornecedores) do fornecedor da peça, dado o ID da peça */
/* retorna -1 caso contrário pecaID inexistente */
int fornecedor_peca(char pecaID[])
{
}
/* imprime a estrutura de endereco passada como parâmetro */
void imprime_endereco(struct tipo_endereco endereco)
{
}
/* esta função imprime todos os dados de uma peça e o endereço e ID do fornecedor*/
/* ela deve usar a função imprime_endereco() */
/* retorna 0 ou -1 conforme a peça exista ou não */
int imprime_dados_peca(char pecaID[])
{
}
/* testar as funções acima aqui */
main()
{
}
|
AULA 21 DIA 16/5/2014 |
---|
AULA 21 DIA 16/5/2014ObjetivosReferências
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++;
}
}
OBSERVE que p++ incrementa em 4 unidades. 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 1: Implementar a função str_cat que concatena duas strings usando ponteiros.
|
Aula dia 22/05/2014 |
---|
Viagem para Porto Alegre |
Aula dia 23/05/2014 |
---|
Viagem para Porto Alegre Exercícios Adicionais ponteiros 1.Implementar um programa para ler dados para dentro das variáveis x e y e somar o conteúdo das mesmas colocando o resultado em x SEM referenciar estas variáveis no scanf ou na expressão de soma. #include <stdio.h>
main()
{
float x,y;
}
2.Implementar uma função que compara duas strings passadas como parâmetro. A função retorna 0 se as strings forem iguais e 1 se diferentes. Usar ponteiros. 3.Implementar uma função que recebe como parâmetro o endereço de duas variáveis float que contêm a parte real e imaginária de um número complexo no formato polar (ângulo em radianos). A função deve converter do formato polar retangular colocando a coordenada x no primeira variável cujo endereço foi fornecido como parâmetro e a coordenada y na segunda variável. void converte_polar_retang(float *parte1, float parte2)
{
}
main()
{
float num1=1.5, num2=10.6;
/*chamar a função aqui */
/* imprimir os valores de num1 e num2 aqui */
}
4.Implemantar uma funçao que recebe como parâmetro o endereço de duas variáveis do tipo char e após a chamada da função os valores das variáveis devem estar maiúsculos(caso elas contenham letras minúsculas). main()
{
char alfa='a', beta='b';
capitaliza(&alfa, &beta);
/* aqui os valores de alfa e beta deverão ser A e B */
}
5.Implementar uma função que recebe uma string contendo uma cadeia de caracteres com dígitos numéricos e retorna o valor inteiro da string. Usar ponteiros. int a_toi(char *p)
{
}
main()
{
char *p="123";
int x;
x = a_toi(p);
/* neste ponto x deve conter 123 */
}
|
AULA 24 DIA 29/05/2014
Objetivos
- vetor de ponteiros;
- argc e argv
- ponteiros para qualquer coisa
- ponteiros para estruturas
Vetor de ponteiros
Como 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 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 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 2: 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 3: Renomeie o executável e veja seja a mensagem de erro mostra o nome correto do programa.
Ponteiros para qualquer coisa
Podemos criar ponteiros para apontar para qualquer objeto na memória. Por exemplo, podemos apontar para variáveis do tipo float, double etc.
main()
{
float a, *p;
p=&a;
*p= 5.5;
}
Exercício 4
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
OBS: usar a função atof para converter string em float.
Apontando para estruturas
Ponteiros 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
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];
}
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);
}
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.
Múltiplas indireções
#include <stdio.h>
void main()
{
int a, *b, **c, ***d;
a = 3;
b = &a;
c = &b;
d = &c;
printf("Valor de a = %d\n",***d);
}
Soluções |
---|
Exercício 1 Implementação feita pela monitora de programação
#include <stdio.h>
main () {
char opcao;
int opr1;
int opr2;
int result;
printf("Entre com a operação desejada\n");
opcao=getchar();
printf("Entre com o operando\n");
scanf("%d",&opr1);
printf("Entre com outro operando\n");
scanf("%d",&opr2);
switch(opcao) {
case '+':
result=opr1+opr2;
printf("Soma: %d\n",result);
break; /* o break força o encerramento da instrução*/
case '-':
result=opr1-opr2;
printf("Subtração: %d\n",result);
break;
case '*':
result=opr1*opr2;
printf("Multiplicação: %d\n",result);
break;
case '/':
result=opr1/opr2;
printf("Divisão: %d\n",result);
break;
default:
printf("Nenhuma das operações é válida!\n");
break;
}
}
|
Soluções |
---|
Exercício 1 Implementação feita pela monitora de programação
#include <stdio.h>
void str_cpy(char *pdest, char *pfonte)
{
while (*pfonte!=0) {
*pdest++ = *pfonte++;
}
*pdest = 0;
}
void str_cat(char *destino, char *origem){
while(*destino!=0){
destino++;
}
while(*origem!=0){
*destino++=*origem++;
}
*destino=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);
str_cat(destino, "alunos");
printf("string destino = %s\n", destino);
printf("tamanho de dest = %d\n", str_len(destino));
}
EXERCÍCIO 2 Código implementado pela monitora de programação
#include <stdio.h>
main(int argc, char *argv[])
{
int comp;
if((argc-1)>2){
printf("cmpcadeia: dois parametros devem ser passados\n");
}else{
comp=strcmp(argv[1],argv[2]);
if(comp==0){
printf("palavras iguais\n");
}else{
printf("palavras diferentes\n");
}
}
}
|
Conteúdo extendido |
---|
ExercíciosExercício 1 Implementar uma função que recebe dois números complexos no formato retangular e retorna a soma dos mesmos no formato polar. Os parâmetros são passados por referência (usar ponteiro). Demonstre o funcionamento no programa main. struct TComplexoRet {
float x;
float y;
};
struct TComplexoPolar {
float mod;
float ang;
};
struct TComplexoPolar conv_polar(struct TComplexoRet *p1, struct TComplexoRet *p2)
{
}
obs: é possível retornar um ponteiro para uma estrutura?? Exercício 2 Implemente uma função usando ponteiros que recebe duas strings como parâmetro e retorna o número de vezes que a segunda string está contida na primeira. Use a função da biblioteca strcmp() como apoio.
#include <string.h>
int conta_sub_strings(char *p1, char *p2)
{
}
Exercício 3 Seja um vetor de inteiros x definido globalmente. Implemente uma função para ler dados para este vetor, dado o endereço inicial do mesmo e o tamanho. Imprima na função main o vetor. Usar ponteiros no acesso ao vetor. int x[10];
void ler_vetor(int *p, int tamanho)
{
}
Exercício 4 Implemente uma função que recebe uma string como parâmetro. Esta string contém um número inteiro. A função deve retornar um inteiro no formato int. Obs: é uma reimplementação do atoi da biblioteca. |
AULA 26 DIA 5/6/2014 |
---|
AULA 26 DIA 5/6/2014Objetivos
A á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));
*py = 2;
resultado = *px + *py;
free (px);
px = NULL;
free (py);
py = NULL;
}
Alocando uma estrutura#include <stdio.h>
#include <stdlib.h>
void main()
{
struct TTeste{
int x;
int y;
};
struct TTeste *teste;
teste = (struct TTeste *) malloc (sizeof(struct TTeste));
if (teste==NULL) {
printf("erro de alocação");
exit(1);
}
teste->x=10;
free(teste);
teste=NULL;
}
Usando o typedef para ajudar na definição e declaração de estruturas#include <stdio.h>
#include <stdlib.h>
void main()
{
typedef struct {
int x;
int y;
} TTeste;
TTeste *teste;
teste = (TTeste *) malloc (sizeof(TTeste));
if (teste==NULL) {
printf("erro de alocação");
exit(1);
}
teste->x=10;
free(teste);
teste=NULL;
}
Alocando dinamicamente uma tabela de estruturas#include <stdio.h>
#include <stdlib.h>
void main()
{
struct TTeste{
int x;
int y;
} *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. |
AULA 27 DIA 6/6/2014 |
---|
AULA 27 DIA 6/6/2014Listas 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
|
AULA 28 DIA 13/6/2014 |
---|
AULA 27 DIA 13/6/2014Exercícios Exercício 1 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. #include <stdio.h>
#define TAM 10
struct tLivro {
char *titulo;
char *autor;
char *isbn;
float *preco;
int estoque;
};
typedef struct tLivro TLivro;
TLivro Livros[10]; /* iniciar a tabela com NULL */
TLivro *retornar_entrada_livre()
{
}
int adicionar_livro()
{
char aux_isbn[20];
TLivro *p;
/* Ler ISBN */
if(verificar_livro_existe(aux_isbn)==1)
return 0;
if((p=retornar_entrada_livre())==NULL)
return -1;
/* Ler os dados do livro pelo teclado e colocar na estrutura
apontada por p*/
}
/* retorna 0 se removido com sucesso e -1 caso contrário */
int remover_livro(char *isbn)
{
}
void imprimir_dados_livro(char *isbn)
{
}
main()
{
/* testar as funções aqui */
}
Exercício 2 Refazer o exercício anterior usando filas. |
Mais exercícios |
---|
Exercício 1 Seja a seguinte estrutura: struct tipo_carro {
char *marca;
char *modelo;
int potencia;
};
typedef tipo_carro tcarro;
/* cria dinamicamente uma estrutura,
preenche os dados dos campos
e retorna um ponteiro para a estrutura criada
Retorna NULL caso não consiga alocar área
*/
tcarro *ler_carro()
{
}
/*
recebe dois ponteiros para estruturas do tipo carro e
retorna -1 caso pelo menos um dos ponteiros seja NULL,
retorna 0 se os modelos forem iguais
e retorna 1 se os modelos forem diferentes */
int compara_modeloa(tcarro *p1, tcarro *p2)
{
}
/* libera a área da estrutura passada como parâmetro */
void deleta_estrutura(tcarro *p)
{
}
main()
{
/*testar as funções aqui */
/* criar dois carros */
/* comparar o modelo dos dois carros. Testar o retorno */
/* liberar a área das estruturas */
}
|
AULA X DIA 26/06/2014 | |
---|---|
AULA XX DIA 26/06/2014Objetivos
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 é referenciado 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.
#include <stdio.h>
void main()
{
FILE *p_arq;
int i,j,res;
float MatA[5][5], MatB[5][5], MatR[5][5];
/* Ler a matriz MatA do arquivo */
if ((p_arq=fopen("MatA.dat", "r")) == NULL) {
printf("Problemas na abertura do arquivo\n");
return;
}
for (i =0;i<5;i++) {
for (j=0;j<5;j++) {
if((res = fscanf(p_arq,"%f",&MatA[i][j]))==EOF){
printf("Fim de leitura\n");
break;
}
printf("%f ",MatA[i][j]);
}
printf("\n");
}
fclose(p_arq);
/* Ler a matriz MatB do arquivo */
printf("\n\n");
/* Ler a matriz MatB do arquivo */
if ((p_arq=fopen("MatB.dat", "r")) == NULL) {
printf("Problemas na abertura do arquivo\n");
return;
}
for (i =0;i<5;i++) {
for (j=0;j<5;j++) {
if((res = fscanf(p_arq,"%f",&MatB[i][j]))==EOF){
printf("Fim de leitura\n");
break;
}
printf("%f ",MatB[i][j]);
}
printf("\n");
}
fclose(p_arq);
/* Calcular a soma das matrizes e colocar resultado em MatR */
for (i =0;i<5;i++) {
for (j=0;j<5;j++) {
MatR[i][j]=MatA[i][j]+MatB[i][j];
}
}
printf("Resultado da Adição\n");
for (i =0;i<5;i++) {
for (j=0;j<5;j++) {
printf("%f ", MatR[i][j]);
}
printf("\n");
}
/* Armazenar MatR em arquivo */
if ((p_arq=fopen("MatR.dat", "w")) == NULL) {
printf("Problemas na abertura do arquivo\n");
return;
}
for (i =0;i<5;i++) {
for (j=0;j<5;j++) {
if((res = fprintf(p_arq,"%f ",MatR[i][j]))==EOF) {
printf("erro\n");
break;
}
}
fprintf(p_arq,"\n");
}
fclose(p_arq);
}
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
Ainda funções de acesso a arquivosA localização corrente do acesso a um arquivo pode ser modificada antes de uma leitura ou escrita. Tipicamente, quando se abre uma arquivo para leitura/escrita, o "cursor" de acesso é 0, ou seja início do arquivo. Se o arquivo for aberto em modo append, o "cursor" é posicionado no final. A cada acesso (leitura ou esrita), este cursor é incrementado conforme o número de dados lidos ou escritos. É possível entretanto modificar a posição deste cursor, tipicamente com as funções fseek() e rewind(). (ver http://www.gnu.org/software/libc/manual/html_node/File-Positioning.html#File-Positioning) Considere o programa abaixo que escreve um vetor de 100 inteiros em um arquivo. #include <stdio.h>
int x[100];
void main()
{
FILE *fp;
fp = fopen("teste.dat","w");
x[0]=32;
x[90]=11;
fwrite(x, sizeof(int),100,fp);
fclose(fp);
}
Note que o vetor, sendo uma variável global não inicialiazada, será zerado pelo procedimento de startup do programa. Entretanto, a posição 90 recebe um valor (11). Agora observe o programa seguinte que lê especificamente a posição 90 e na sequência restabelece o cursor no início. Note que o fread lê somente um inteiro na posição corrente do arquivo. A posição corrente foi determinada por fseek e depois retornada para o início com rewind.
#include <stdio.h>
int y;
void main()
{
FILE *fp;
fp = fopen("teste.dat","r");
fseek(fp, 90*sizeof(int), SEEK_CUR);
fread(&y, sizeof(int),1,fp);
printf("y=%d\n", y);
rewind(fp);
fread(&y, sizeof(int),1,fp);
printf("y=%d\n", y);
fclose(fp);
}
Execício Considero o programa abaixo. Ele deve acessar uma tabela que se encontra em um arquivo binário. Cada item da tabela se apresenta conforme o registro TRegistro. Implemente a função LerTab e crie um programa para escrever uma tabela iniciada com um tabela de 5 registros a fim de testar a função implementada. #include <stdio.h>
struct TRegistro {
char nome[30];
int idade;
} Registro, *pAux;
struct Tregistro *LerTab()
{
}
void main()
{
pAux=LerTab(3);
if (pAux!=0) {
printf("Nome lido %s\n", pAux->nome);
}
}
|