Professional Documents
Culture Documents
Conteúdos
Sistemas de Numeração
Tudo o que se passa dentro do computador é armazenado utilizando números (quer seja
dados, texto, sons ou imagens)
Tudo começou com a invenção do bit. Ora, o bit é apenas uma forma de representar dois
estados: verdadeiro e falso ou ligado ou desligado.
Com um bit podemos representar dois estados (verdadeiro ou ligado, representado por 1) e
(falso ou desligado, representado por 0).
Sistemas de Numeração
Um bit serve perfeitamente para indicar qual o sexo de um determinado indivíduo, pois
(pelo menos até agora) apenas existem o sexo masculino e o feminino:
1 - Masculino
0 - Feminino
Se tentarmos representar o estado civil de uma pessoa um bit já não chega, pois os
possíveis estados são:
00 - Solteiro
01 - Casado
10 - Divorciado
11 - Viúvo
Sistemas de Numeração
Assim, para se representar conjuntos maiores de valores a solução é sempre a mesma: ir
juntando bits até que possamos representar o conjunto pretendido.
A solução encontrada foi definir uma unidade. Essa unidade vai passar a ter 8 bits e passa a
se chamar byte.
Ficamos assim sabendo que o bit que se apresenta na posição índice n estiver com 1, o
número que ele representa é o 2n
Sistemas de Numeração
Que número é 01102 na base 10?
0110(2) = 4 + 2 = 6(10)
Sistemas de Numeração
Facilmente se compreende agora que se um byte é constituído por 8 bits, o menor valor
nele representado será o 0
e o maior será
1111 1111(2) = 1*27 + 1*26 + 1*25 + 1*24 + 1*23 + 1*22 + 1*21 + 1*20
Assim, o maior número representado em um byte será o número 255, existindo assim 256
números passíveis de serem representados.
Sistemas de Numeração
A base que se adapta menos à computação é a base decimal, por isso, e porque não
podemos apenas trabalhar na base 2, pois é complicado representar valores numéricos bit a
bit, foram desenvolvidas bases de trabalho diferentes.
Vamos conferir:
35(8) = 24 + 5 =29(10)
Sistemas de Numeração
Base Hexadecimal
A base hexadecimal é formatada por 16 símbolos. Como a base de trabalho (base 10) é
composta por apenas 10 símbolos (0..9), houve necessidade de adicionar os símbolos A(10),
B(11), C(12), D(13), E(14) e F(15).
Sistemas de Numeração
Tomemos o exemplo do número 29(10).
Vamos conferir:
O valor do próximo bit é > 53, logo esse bit não vai ser utilizado, ficando com 0.
Como 53 > 32, vamos ficar com o bit em 1 e sobram ainda (53-32=21)
Como 21 > 16, vamos ficar com o bit em 1 e sobram ainda (21-16=5)
Sistemas de Numeração
Facilmente se compreende que para conseguir construir o número 5 a partir dos bits
teremos de fazer 4+1, isto é, selecionar os bits associados a esses dois números.
181(10) = 10110101(2)
Sistemas de Numeração
Converter Binário para Octal
Já sabemos, basta multiplicar cada um dos bits pelo valor da base elevada a cada uma das
potências.
Já sabemos, basta multiplicar cada um dos bits pela base 8 elevada a cada uma das
potências.
Já sabemos, basta multiplicar cada um dos bits pela base 16 elevada a cada uma das
potências.
Agora que já sabemos comos os números são representados internamente, podemos utilizar
algumas características de um nível da linguagem mais baixo que permitem a manipulação
de dados ao nível do bit.
& (apenas quando existem bits com 1 em ambas as posições é que o resultado é 1, se não é
sempre 0)
| (basta que exista um bit com 1 para que o bit resultado seja 1. Para ser 0 os dois bits
terão de ser simultaneamente iguais a 0)
Sistemas de Numeração
Exemplos:
Na definição de uma estrutura podemos definir campos formados apenas por um ou alguns
Bits, permitindo assim poupar espaço.
Se, por exemplo, ao armazenar o valor “SIM” ou “NÃO”, “MASCULINO” ou “FEMININO” será
usado 1 byte para cada um dos caracteres armazenados. Para este caso apenas precisamos
de 1 bit, pois existem apenas 2 estados (1 ou 0).
● nome
● idade
● sexo (0: Mulher, 1: Homem)
● Estado civil (0: Solteiro, 1: Casado, 2: Viúvo, 3: Divorciado)
Sistemas de Numeração
struct Pessoa {
char nome[100];
int idade;
unsigned sexo : 1; /* 1 bit */
unsigned est_civil : 2; /* 2 bits */
};
Nota: Você pode usar o unsigned para se certificar que essa variável inteira nunca irá
receber um valor negativo, como para armazenar dados de memória, idade, etc...
Sistemas de Numeração
Ficheiros
● Buffers
● Outras funções de manipulação de
ficheiros
Conteúdos
Ficheiros
Até agora usaram programas que pediam dados ao utilizador e o programa é que
manipulava-os. Uma vez terminado o programa, todos os dados introduzidos ou resultados
eram perdidos.
● Para processar um ficheiro, a primeira operação a ser realizada é ligar uma variável a
esse ficheiro, dar um nome ao ficheiro que pretendemos criar (abertura de ficheiro).
● Desta forma evitamos estar sempre a escrever o nome do ficheiro sempre que
precisamos de o referenciar.
Abertura de um ficheiros
Para podermos utilizar um ficheiro, temos que declarar uma variável do tipo FILE (ou, mais
propriamente, um ponteiro para o tipo FILE)
FILE *ficheiro;
A sintaxe é:
A sintaxe é:
Nome de um ficheiros
Para associar a nossa variável ponteiro para um ficheiro que será lido no computador, é
necessário que seja fornecido a localização desse ficheiro, afinal o C não adivinha isso.
Isto é feito através de uma string passada para a função fopen(), e esta string deve conter o
endereço completo do ficheiro e isso inclui o nome do ficheiro.
Vamos supor que trabalhamos com um ficheiro chamado “arquivo.txt”.
Se queremos usar este ficheiro e ele está na mesma pasta do executável, precisamos
apenas de fornecer o nome completo (com extensão) do ficheiro. Por ex: arquivo.txt
Ficheiros
Modos de abertura
“r” - read - abertura do ficheiro para leitura
FILE *arquivo = fopen("arquivo.txt", "r");
Para além destes 3 modos básicos existe ainda a possibilidade de abrir um ficheiro de forma
a permitir simultaneamente operações de leitura e escrita colocando um sinal de + após o
modo.
“r+” - abertura do ficheiro para leitura e escrita.
FILE *arquivo = fopen("arquivo.txt", "r+")
Se o ficheiro não existir é criado. Se já existir, os novos dados serão colocados por cima dos
dados existentes (apaga os dados anteriores).
Fechar um ficheiro
Fechar um ficheiro, retira a ligação entre a nossa variável e o ficheiro existente no disco.
Antes do ficheiro ser fechado são gravados, fisicamente, todos os dados que possam ainda
existir em buffers associados ao ficheiro.
A sintaxe utilizada é:
int fclose(FILE *arq)
No caso de estarmos a trabalhar com vários ficheiro, podemos fechá-los todos através da
função:
int fcloseall()
Ficheiros
Quando abrimos um ficheiro, o ponteiro que criamos do tipo FILE armazenará o endereço de
um ficheiro.
Porém, nem sempre esta tarefa é possível, gerando um erro. Quando este erro ocorre o
ponteiro irá apontar para NULL, sendo essa prática muito importante para o tratamento de
erros.
Este erro pode ocorrer por vários motivos. O mais óbvio é abrir um ficheiro que não existe.
if(arquivo == NULL)
printf("Nao foi possivel abrir o arquivo!");
Ficheiros
Antes de iniciarmos a escrita nos ficheiros, é necessário explicar alguns detalhes sobre como
os ficheiros são vistos em programação C.
A troca de informações num sistema pode se dar de várias maneiras. Pode ser através da
interação teclado-programa-monitor, onde o utilizador fornece os dados via teclado, o
programa processa essa informação, e exibe algo na ecrã.
Nota: existem várias maneiras de se trocar informações, e constantemente estão a surgir novas. Por exemplo, as tecnologias
WiFi e Bluetooth. Visando facilitar, foram padronizadas como sendo ficheiros.
Ficheiros
Mesmo que apenas tenhamos a interação teclado-programa-monitor, existem alguns
ficheiros abertos, e os mais importantes são:
● stdin - é o ficheiro de entrada padrão. É o teclado.
● stdout - é o ficheiro de saída padrão. É a monitor do computador, através do
terminal de comando.
● stderr - ficheiro padrão de erro, onde podemos direcionar mensagens de erro
para outro local sem ser o da saída padrão, como para um log (espécie de registro
de ações)
Além destes, outros ficheiros como o stdaux (dispositivo auxiliar, geralmente a porta COM1)
e o stdprn(impressora padrão), são abertos automaticamente.
Ficheiros
fputc() - Como escrever um caractere em um ficheiro
Para fazer isso vamos usar a função fputc(), que recebe dois dados: o caractere e o FILE*,
que terá as informações do local onde iremos escrever o dito caractere:
Esta função retorna EOF caso não tenha conseguido escrever no ficheiro, ou retorna um
inteiro que representa o caractere, caso tenha ocorrido.
Ficheiros
Escreva um programa que peça um caractere e guarde esta entrada num ficheiro chamado
"char.txt", localizado na mesma pasta do programa executável.
Ficheiros
Vamos inicialmente definir nosso endereço através de
uma string (char url[]), que é simplesmente
"char.txt", bem como o caractere ch para armazenar o
caractere que vamos escrever.
Para isso, existe a função fprintf, que nos permite escrever strings inteiras em ficheiros.
Ou seja, recebe o local onde deve direcionar a saída (para um ficheiro, apontado pelo
ponteiro arq do tipo FILE), e a string que devemos adicionar ao ficheiro. Esta função retorna
EOF em caso de erro.
Ficheiros
Escreva um programa em C que peça 3 notas de um aluno (Matemática, Física e
Química), e salve esses dados num ficheiro chamado "notas.txt", que deve ter, ao final, a
média das três disciplinas.
Ficheiros Vamos definir a nosso url como "notas.txt" e criar
duas variáveis do tipo float, a "nota" (que vai
armazenar a nota de cada disciplina) e a "media"
(que vai calcular a média das 3 disciplinas).
Quando estamos a ler informações do teclado, usávamos as funções getchar, scanf e gets.
Agora vamos conhecer as funções correspondentes, mas para ler em ficheiros.
A única diferença entre leitura e escrita, é a posição do ficheiro que vamos ler.
Quando estamos a escrever, se usarmos o modo de abertura "w", escrevemos no início do
ficheiro. Se usarmos o "a", escrevemos ao final do ficheiro.
Para a leitura, vamos usar funções que iniciam a leitura sempre no início do ficheiro.
Quando usamos a função fgetc, por exemplo, ele lê o primeiro caractere e automaticamente
já se posiciona no próximo. Ao ler o próximo, o C já se prepara para ler o próximo caractere
do ficheiro, e assim faz sempre isso até encontrar a constante EOF.
Ficheiros
Esta função retorna um inteiro que representa o caractere, e EOF, que vale -1, caso aponte
para o fim do arquivo. E como os caracteres são representados por inteiros que vão de 0 até
255, um caractere no ficheiro nunca terá o valor -1, somente entre 0 e 255.
Ficheiros
Escreva um programa em C que leia de um ficheiro (poema.txt) e liste no ecrã, caractere
por caractere.
Notas: Crie o ficheiro poema.txt e copie um pequeno poema que encontre na internet
Ficheiros
Nota:
e directivas
● Directivas #undef, #if, #ifdef,
#ifndef, #else, #endif e #error
Conteúdos
Pré-processador C/C++ e directivas
Problema: Implemente a função Mult, que devolve o produto de dois valores numéricos.
Estamos diante de um problema complicado, e uma linguagem não pode emperrar neste
tipo de problemas.
Macros
As macros são porções de código que são substituídas, pelo Pré-processador, antes mesmo
do compilador passar pelo código.
É assim possível escrever um código que seja substituído por outro, antes do programa ser
compilado, evitando os problemas apresentados anteriormente.
Pré-processador C/C++ e directivas
Mult(x,y)
Nota: na definição de uma macro, a abertura dos parênteses dos parâmetros terá que ficar
imediatamente após o nome da macro.
Pré-processador C/C++ e directivas
Resultado:
4*5=20
5*6=30
Pré-processador C/C++ e directivas
Como podemos reparar, o programa funciona perfeitamente, pois o seu código é expandido
em:
Pré-processador C/C++ e directivas
Vamos pegar apenas na primeira linha do programa anterior, mas com uma ligeira
alteração:
Estranho, não é?
4*5=8
Pré-processador C/C++ e directivas
O que falta?
Faltam os parênteses.
Pré-processador C/C++ e directivas
1000/Mult(2+3,7+3)
MULT(2+3,7+3) = 5*10 = 50
1000/50 = 20
Resultado:
2000
Pré-processador C/C++ e directivas
printf("%d\n", 1000/(2+3)*(7+3));
Como sabem a multiplicação e a divisão têm o mesmo nível de precedência, pelo que
são realizadas pela ordem em que se encontram:
1000/5 = 200
200*10 = 2000
Ora, note-se que ainda falta um outro nível de parênteses, que deverá ser colocado em
volta de toda a expressão em que a macro será expandida:
Exercício:
A macro irá ter dois parâmetros e terá que devolver um dos valores. Como se pretende
devolver um resultado, vamos utilizar o operador ternário.
#include
#include <stdio.h>
Pré-processador C/C++ e directivas
No exemplo, existe um diretório chamado Lang (languages) onde estão colocadas todas as
linguagens de programação existentes num determinado computador.
Neste exemplo, a linguagem C encontra-se no diretório Tc (Turbo C), que contém
subdiretórios no seu interior, dos quais se destacam: Bin, Include, Lib
Pré-processador C/C++ e directivas
Include: local onde existem os ficheiro com extensão .h (stdio.h, string.h, etc...)
Lib: local onde estão as bibliotecas com o código para criar o executável final da aplicação.
Neste diretório encontram-se os ficheiros .lib que contêm o código executável das funções
printf, scanf, atoi, etc…
O ficheiro stdio.h é um ficheiro de texto que contém os cabeçalhos das funções que
utilizamos para a entrada/saída.
Pré-processador C/C++ e directivas
Compilação condicional
#if … #endif
Compilação condicional
#ifdef #ifndef #undef
No exemplo vamos definir um símbolo DEBUG. Não lhe vamos atribuir nenhum valor.
Se o símbolo estiver definido, é compilado.
Pré-processador C/C++ e directivas