Linguagem de
programação I A
Carlos Oberdan Rolim
Ciência da Computação
Sistemas de Informação
Versão: 230414_01
Linguagem C
Cronologia
BCPL
1967 – Martin Richards
B
1970 – Ken Thompson
C
1972 – Dennis Ritchie
Padrão ANSI C – 1983
Homologado – 1989
ISO/IEC – 1990
C99 – 1999
C11/C1X - 2007
Por muitos anos o livro, “The C programming language” de Brian Kernighan e
Dennis Ritche, editado em 1978,
serviu de manual de referência tanto para
programadores como desenvolvedores de compiladores da linguagem C, motivo
pelo qual muitas pessoas, erradamente, atribuem o desenvolvimento da
linguagem a Brian Kernighan.
A Linguagem C
Linguagem de nível médio
Aproxima-se do assembly (manipulação de bits,
Tipos abstratos de dados
Linguagem estruturada
compartimenta o código em subrotinas (procedimentos e funções),
permitindo o uso de variáveis locais;
utiliza estruturas de repetição e controle (suporta diretamente diversos
tipos de laços e testes condicionais), eliminando o uso do goto .
A Linguagem C
Linguagem compilada (normalmente)
Permite compilação separada
em programas com múltiplos arquivos basta recompilar apenas o
arquivo modificado e não todos os arquivos;
A Linguagem C
Linguagem de estilo livre
Formatação livre
Case sensitive
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
#include <stdio.h> int main(){printf("Hello, world!\n"); return 0;}
#include <stdio.h> int Main(){printf("Hello, world!\n"); return 0;}
Portabilidade garantida dentro do padrão ANSI
Linguagem enxuta (apenas 32 palavras reservadas)
Transfere poder e consequentemente responsabilidade ao
programador
Palavras Reservadas
auto
double
int
struct
break
else
long
switch
case
enum
register
typedef
char
extern
return
union
const
float
short
unsigned
continue
for
signed
void
default
goto
sizeof
volatile
do
if
static
while
Um Olá!
Comando para
pré-processador
Definições de bibliotecas
de entrada e saída
#include <stdio.h>
Função main
retorna um
inteiro
Início de
bloco
Final de
bloco
Nome da
função é “main”
int main()
Definição de
uma função
{
printf("Hello, world!\n");
return 0;
Chamada à
}
Termina a função
main e retorna
valor 0
Parâmetro
para printf
função “printf ”
A Linguagem C
Comentários:
/* ….*/
/* Programa 1: Imprime “Hello World!” na tela
Autor: Dennis Ritchie */
/* Bibliotecas de funções chamadas */
#include <stdio.h>
/* Início do programa */
int main()
{
printf("Hello, world!\n");
return 0;
}
/* Programa 2: Imprime “Hello World!” na tela
Autor: Dennis Ritchie */
#include <stdio.h>
// Este comentário não está no padrão ANSI C
int main(){
printf("Hello, world!\n");
return 0;
}
A Linguagem C
/* Programa 3: Calculo da area */
#include <stdio.h>
/* inclusão da biblioteca para: printf, gets, scanf */
#include <math.h>
/* inclusão da biblioteca para: pow */
#define TAM 25
/* definindo constante TAM */
const double MY_PI = 3.1415916; /* definindo constante MY_PI */
float area(int raio); /* protótipo da função área */
int main(){
char buffer[TAM]; int aux; float result; /* declaração de variáveis */
printf(“\nEntre com o nome: “);
gets(buffer);
/* leitura através de gets */
fflush(stdin);
/* limpa buffer de entrada */
printf(“\nEntre com o raio: “);
scanf(“%d”, &aux);
/* leitura através de scanf */
result = area(aux); /* chamada a função área */
return 0;
}
float area(int raio){ /* definição da função área */
float var;
/* declaração de variável local */
var = MY_PI * pow(raio,2); /* chamada a função pow de math.h */
return var;
/* retorna o valor calculado para quem chamou */
}
A Linguagem C
Blocos são delimitados por { e }
Declarações de variáveis somente são válidas no início dos blocos
#include <stdio.h>
int main() {
int var_1, var_2, result_1, result_2;
result_1 = var_1 + var_2;
printf(“soma:%d”, result_1);
result_2 = var_1 - var_2;
printf(“subtracao: %d”, result_2);
return 0;
}
#include <stdio.h>
int main() {
int var_1, var_2, result_1;
result_1 = var_1 + var_2;
printf(“soma:%d”, result_1);
int result_2;
result_2 = var_1 - var_2;
printf(“subtracao: %d”, result_2);
return 0;
}
A Linguagem C
A função main é sempre a primeira a ser executada (sendo
obrigatória)
Pelo padrão ANSI a função main retorna um inteiro a quem a
chama: o sistema operacional no caso.
Quando o programador não especifica o tipo de retorno de uma
função, normalmente o compilador assume como int.
Grande maioria de comandos termina com ; (ponto e virgula)
Tipos de Dados
tipo tamanho representação
faixa
char
1 byte
ASCII
-128 à +127
int
4 bytes
Complemento 2
-2147483648 à +2147483647
float
4 bytes IEEE 754
double 8 bytes
void
IEEE 754
-1 x 10-37 à 1 x 1037
-1 x 10-308 à 1 x 10308
0 bytes
#include <stdio.h>
int main() {
char aux_1 = '0', aux_2 = 65;
printf("\ncaracter aux_1: %c\ninteiro
aux_1: %d", aux_1, aux_1);
printf("\n\ncaracter aux_2: %c\ninteiro
return 0;
}
aux_2: %d", aux_2, aux_2);
Qualificadores de Tipos
É possível aplicar modificadores nos tipos para alterar seu
“comportamento” quanto aos limites de armazenamento
Exemplo:
short, long, long long
signed, unsigned
long double pi = 3.1415916;
long int var = 0;
short aux_1, aux_2 = 65;
unsigned char a;
Tabela de Tipos e Qualificadores
Tipo
Tamanho
Range
char
1 bytes
-128 to 127
unsigned char
1 bytes
0 to 255
short
2 bytes
-32768 to 32767
unsigned short
2 bytes
0 to 65535
int
4 bytes
-2147483648 to 2147483647
unsigned int
4 bytes
0 to 4294967295
long
4 bytes
-2147483648 to 2147483647
unsigned long
4 bytes
0 to 4294967295
float
4 bytes
1.175494e-38 to 3.402823e+38
double
8 bytes
2.225074e-308 to 1.797693e+308
signed long long
8 bytes
-9223372036854775807 to 9223372036854775807
unsigned long long
8 bytes
0 to 18446744073709551615
• Precisão de um float 6 digitos
• Precisão de um double 15 digitos
• int e long mesmo tamanho  motivos históricos
•porém, long não pode ser menor que int
Nomes de Identificadores
Utilizados para nomear variáveis, funções, constantes, rótulos,
estruturas, etc;
Os identificadores em C devem começar com uma letra ou _
(underline);
Os identificadores podem conter letras, números ou _ (underline);
As primeiras 31 letras são significativas
case sensitive;
Palavras reservadas não podem ser identificadores
int _aux, Meu_PI, meu_PI, contador2, contador_laco;
long variavel_com_o_nome_muito_longo;
double estas variaveis sao invalidas;
short 3_nomes, var-aux, laço, meu.PI, continue, símbolo;
Variáveis
Formalmente uma variável é definida como uma tupla
composta de 6 atributos:
<nome, posição na memória, tipo, valor,
tempo de vida, escopo>
- nome: identificador usado para referenciar a variável;
- posição na memória: endereço de memória que o compilador aloca para a
variável;
- tipo: tipo de dado. Define seu tamanho, faixa e codificação;
- valor: valor armazenado na variável em um determinado instante
- tempo de vida: tempo que o endereço de memória permanece vinculado a
variável;
- escopo: espaço/ambiente de referenciamento da variável;
Variáveis
- Representação da memória de forma super simplificada
....
15
16
x
z
10
5
17
Variáveis alocadas em memória
int
x = 10;
char z = 5;
18
19
20
21
....
Variáveis
Variáveis precisam ser declaradas.
(Não existe declaração implícita.)
A cada variável é associado um tipo, que determina os valores
possíveis e as operações que podem ser executadas. Sintaxe:
<tipo> nome [= valor inicial];
Na declaração da variável pode ser definido seu valor inicial.
Variáveis
<tipo> nome [= valor inicial];
char letra = ‘A’;
int x = 1, contador;
float var1, var2 = 12, var3;
int aux;
double pi = 3.1415, raio;
Memória
[ ... ]
letra
x
contador
65
0
0
0
1
?
?
?
[000200]
[000201]
[000202]
[000203]
[000204]
[000205]
[000206]
[000207]
[ ... ]
Variáveis e escopo
Onde são declaradas
Como parâmetros de funções (variável local):
int soma(int valor_1, int valor_2);
No início de um bloco do programa (variável local):
int main( ){
for(x = 0; x < 10; x++){
int aux;
int auxiliar;
float raio;
…
}
…
}
No início de um bloco do programa (variável local) – Padrão C99:
for(int i = 0 ; i < 10; i++){
…
Cuidado!!! O padrão ANSI exige
}
que a variável seja declarada no
inicio do bloco, após os parênteses.
{ int i; for(i=0; i<10; i++){} }
Variáveis e escopo
Onde são declaradas
Fora de qualquer bloco de programa (variável global):
#include <stdio.h>
int valor_1;
int main( ){
…
}
E quando existem duas variáveis com mesmo nome mas escopos
diferentes ? O escopo local tem precedência!!!
#include <stdio.h>
int valor_1 = 0;
int main( ){
int valor_1 = 1;
print(“%d”, valor_1);  imprime 1
…
}
Variáveis e escopo
Exemplo de código com variáveis locais e globais
#include <stdio.h>
int x = 0;
int calcula(){
int x = 1, y = 0;
printf(“x:%d y:%d”, x, y);
 Imprime x:1
y:0
}
int main(){
int y = 1;
printf(“x:%d y:%d”, x, y);
return 0;
}
 Imprime x:0
y:1
Conversões de tipos
C realiza avaliação de expressões em modo misto.
Em outras palavras a linguagem permite que as expressões
contenham operandos de tipos diferentes, realizando de maneira
automática a conversão de tipos.
A conversão realizada em C é sempre uma conversão de
alargamento, ou seja, o tipo menor é convertido para um tipo maior.
Nem todas as conversões automáticas são possíveis, neste caso o
compilador apresenta mensagens de erro descrevendo o problema.
Conversões de tipos
Se as conversões forem possíveis ele as faz, seguindo as
regras abaixo:
Todos os chars e short são convertidos para int. Todos os float são
convertidos para double.
Para pares de operandos de tipos diferentes: se um deles é long
double o outro é convertido para long double; se um deles é double
o outro é convertido para double; se um é long o outro é convertido
para long; se um é unsigned o outro é convertido para unsigned.
Conversões de tipos
Cast
Um cast (modelador) é aplicado a uma expressão. Ele força a mesma a ser
de um tipo especificado. Sua forma geral é:
(tipo)expressão
#include <stdio.h>
int main () {
int num;
float f;
num = 10;
f = (float) num / 7;
printf ("%f", f);
return 0;
}
Exemplos
int n = 10, d = 7;
double x, y, z; /* Vírgula separa declarações de mesmo
tipo */
int i, j, k;
i = 25;
/* Atribuição */
x = d + i;
/* x recebe 32.0*/
k = i / n;
/* k recebe 2.0 (divisão inteira) */
k = x / n;
/* k recebe 3.2 */
x = 25; y = 10; /* x recebe 25.0 y recebe 10.0*/
z = x / y;
/* z recebe 2.5 */
j = z + y;
/* j muda para 12 (conversão) */
“Erros” lógicos de divisão
Veja o programa:
main() {
float ans;
ans=5/10;
printf("%f",ans);
}
Qual a saída ??? Deveria ser: 0.50000 Porém foi 0.000000 (?!?!?!)
Isso deve-se a int/int = int
Ou seja….
Altere o programa para
main() {
float ans;
ans=5 / (float) 10;
printf("%f",ans);
}
int/int = int
int/float = float
float/int = float
float/float = float
Sempre quando dois inteiros forem
divididos será gerado um novo initeiro
Agora a saída foi (int/float) = 0.500000
Constantes
•
Qualquer valor que permanece inalterado ao longo
da execução do programa
tipo
inteiro
inteiro long
inteiro sem sinal
inteiro long sem sinal
inteiro hexadecimal
inteiro octal
double
float
long double
caracter
vetor de caracteres
formato
1345
1345L ou 1345l
1345u
1345ul
0x2A
025
134.5 ou 1e-2
134.5f ou 134.5F ou 3e-2f
134.5lf ou 5e3lf
‘a’, ‘1’
“linguagem C”
\n \t \0 também
são constantes
Podemos forcar constantes a serem interpretadas com certos formatos usando os
modificadores de formato
Constantes
• As constantes caracter participam das operações com seus
valores correspondentes da tabela ASCII.
•
Por exemplo o caracter ‘0’ corresponde ao valor numérico 48
e não 0.
• Assim:
int X;
X = ‘0’ + 5;
/* resultado: 53 */
- - - - - - - - - - - - - - - - - - - - - -
- - - - -
char var;
int unidades = 0;
var = 48 + unidades; /* var recebe o caracter
ASCII correspondente a 48
que é 0 */
Constantes
Constantes podem ser definidas de duas formas:
Utilizando o comando #define do pré-processador.
Utilizando a palavra-chave const na declaração.
#define MY_PI 3.1415
...
area = raio * MY_PI * MY_PI;
const float MY_PI = 3.1415;
...
area = raio * MY_PI * MY_PI;
Constantes
Exemplo de Uso:
Quando temos algum valor que será usado diversas vezes ao
longo do programa e por algum motivo desejamos altera-lo
#include < .... >
#define CONTADOR 10
int main(){
int i;
for(i=0; i < CONTADOR; i++){
......
}
......
for(i=0; i < CONTADOR; i++){
......
}
Note que alterando o valor de
CONTADOR ele seria alterado
nos dois laços
Estruturas de Decisão
Permitir testes para decidir ações alternativas:
if – else
if – else if – else
Switch
(?:) Operador Condicional - ternário
if - else
Comandos podem ser executados condicionalmente utilizando a
construção if - else.
if (condição)
comando;
else
comando;
Condição
Parêntesis são
necessários
if (saldo > 0)
printf("credor");
else
printf("devedor");
Comando a executar
se condição for
verdadeira
Comando a executar
se condição for falsa
if - else
O if pode ocorrer sem o correspondente else, caso em que,
se a condição for falsa, nada será executado.
if (x < 0)
x = -x;
Quando mais de uma instrução deve ser executada dentro do if
ou do else, utilizamos chaves { } para delimitar o bloco.
ATENÇÃO!!!
Muitos acabam esquecendo de
usar os delimitadores de bloco
quando se faz necessário
if (x < 0) {
printf(“O valor de x é negativo: %d”, x);
x = -x;
printf(“Agora é positivo: %d”, x);
}
if – else
O else corresponde sempre ao ultimo if encontrado. Usar chaves
quando desejar outra associação
if (n > 0)
if(a > b)
z = a;
else
z = b;
if (n > 0) {
if(a > b)
z = a;
}
else
z = b;
if – else
Lembre que:
ATENÇÃO!!!
Falso = 0
Verdadeiro = tudo que for diferente de falso ( 1 é verdadeiro, ‘A’ é verdadeiro,
10 é verdadeiro, 2.3 é verdadeiro, m = 15 é verdadeiro e assim por diante...
n = 0;
if ( n ){
n = 0;
/* if (x == 1) */
... */ não irá executar
pois n é falso
*/
}
if ( !n ){
/* if (x == 0) */
... */ irá executar */
}
if – else if - else
Comandos de decisão múltipla.
if (condição)
comando;
else if (condição)
comando;
else if (condição)
comando;
else
comando;
if – else if - else
printf(“Entre com o conceito: “);
scanf(“%c”, &let_nota); fflush(stdin);
if (let_nota == ’A’)
printf("A nota está entre 9,0 e 10,0\n");
else if (let_nota == ’B’)
printf("A nota está entre 8,0 e 9,0\n");
else if (let_nota == ’C’)
printf("A nota está entre 7,0 e 8,0\n");
else if (let_nota == ’D’)
printf("Como você vai explicar essa\n");
else {
printf("Claro que não tive nada a ver com isso.\n");
printf("Deve ter sido culpa do professor.\n");
}
Operador condicional ? : (ternário)
Forma compacta de expressar uma instrução if – else
(condição) ? expressão1 : expressão2;
max =
(num1 > num2) ? num1 : num2;
equivalente:
if (num1 > num2)
max = num1;
else
max = num2;
Exemplo:
ABS = (num < 0) ? - num : num;
Comando Switch
• <variável> deve ser uma variável
switch <variável> {
do tipo int ou char;
case <constante 1> : :
<comandos>;
[break;]
case <constante 2> :
<comandos>;
• “break” serve para terminar a
seqüência de comandos em
[break;]
case <constante 3> :
<comandos>;
forem suprimidos permitem que o
[break;]
“case” a seguir seja executado,
[default :]
<comandos>;
}
execução, por serem opcionais, se
sem haver qualquer quebra na
seqüência do processamento.
switch
printf ("\nEscolha uma opção: ");
scanf ("%d", &opcao);
switch (opcao) {
case 1:
printf ("Opcao 1 foi digitada.\n");
case 2:
printf ("opcao 2 foi digitada\n");
break;
case 3:
printf("opcao 3 foi digitada\n");
break;
case 4:
printf("opcao 4 foi digitada\n");
break;
default:
printf("opcao Inválida\n");
}
Estruturas de Repetição
Permitir repetição da execução do código que se
encontra dentro do bloco:
for
while
do - while
Comando for
Forma geral.
for(inicialização; expressão teste; atualização)
comando;
Interpretação: realize a inicialização e então repita o comando
enquanto a expressão teste for verdadeira, atualizando ao final de
cada interação
Teste para entrar no loop
Inicia definindo valor das
variáveis
1
Atualiza / incrementa o
valor após executar o loop
2
5
4
for(numero = 0; numero < 10;
printf (“ %d”, numero);
3
6
numero +=
2 )
Serão realizados somente
se 2 e 5 forem
verdadeiros
Comando for
Qualquer uma das parte do laço pode ser omitida (ou mesmo
todas elas): for ( ; ; ) – laço infinito
Qualquer uma das partes pode ser composta de mais de uma
expressão separadas por virgula (uso do ponto e virgula) :
for(
x = 0, y = 15
;
y > 0
;
y--, x +=2
....
Cuidado com:
for(x = 0; x < 1000; x++);
ATENÇÃO!!!
Cuidado com ; ao final do for
pois é um laço vazio
Um comando break encerra a execução do laço;
Um comando continue encerra a interação corrente do laço;
)
break - continue
int main(){
int x;
for(x = 10; x > 0; x--){
if(x == 3)
break;
if(x == 7)
continue;
printf("\nValor de X: %d\n", x);
}
printf("\nEncerrou laco com x valendo %d\n", x);
return 0;
}
Comando while
Forma geral.
while(expressão teste)
comando;
Interpretação: enquanto a expressão teste for verdadeira repita o
comando (pré-testado).
#include <stdio.h>
#include <stdio.h>
int main ( ){
int main ( ){
int numero = 0;
char tecla = ‘\0’;
while(numero < 100){
printf(“Número: %d”, numero);
while(tecla != ‘q’)
numero++;
tecla = getch();
}
return 0;
return 0;
}
}
Comando while
Cuidado com:
while( x < 1000);
pois é um laço vazio;
Um comando break encerra a execução do laço;
Um comando continue encerra a interação corrente do laço;
#include <stdio.h>
int main ( ){
int numero = 1;
while(numero < 10){
if(numero > 5){
numero++;
continue;
}
printf(“\nNúmero: %d”, numero);
numero++;
}
printf(“\nNúmero Final: %d”, numero);
return 0;
}
Comando do-while
Forma geral.
do
comando;
while(expressão teste);
Interpretação: repita o comando enquanto a expressão teste for
verdadeira (pós-testado).
Comando do-while
#include <stdio.h>
int main( ) {
char opcao;
do{
printf(“\n\n\t\t\tMenu Principal\n\n\n”);
printf(“\t\t[1] - Instrucoes\n\n”);
printf(“\t\t[2] - Inserir Funcionario\n\n”);
printf(“\t\t[3] - Alterar Funcionario\n\n”);
printf(“\t\t[4] - Excluir Funcionario\n\n”);
printf(“\t\t[5] - Pesquisa\n\n”);
printf(“\t\t[6] - Sair\n\n”);
printf(“\t\t\tOpcao [ ]\b\b”);
do
opcao = getch( );
while(opcao < ’1’ || opcao > ‘6’);
} while(opcao != ‘6’);
return(0);
}
Matrizes e vetores
Vetores e matrizes: Vetores são usados para tratamento de conjuntos de dados
que possuem as mesmas características. Uma das vantagens de usar vetores é
que o conjunto recebe um nome comum e elementos deste conjunto são
referenciados através de índices. Pelo nome vetor estaremos referenciando
estruturas que podem ter mais de uma dimensão, como por exemplo matrizes de
duas dimensões.
A forma geral da declaração de um vetor é:
<tipo> nome [tamanho];
int vet[100];
/* vetor de 100 números inteiros */
float notas[65];
/* vetor de 65 números reais */
char nome[40];
/* vetor de 40 caracteres */
int mat_A[5][5]; /* matriz de 5x5. Total 25 elementos */
----- ---------------------x = 3 * vet[2];
/* x recebe o triplo do valor em vet[2] */
vet[5] = Vet[3] + vet[4];
Matriz multidimensional usa formato Matriz [LINHA] [COLUNA]
Matrizes e vetores
De acordo com a especificação ANSI o tamanho de um vetor deve
ser estaticamente definido, ou seja, deve ser uma constante. Desta
forma, o código abaixo é inválido:
int tam;
/* escalar inteiro */
float notas[tam]; /* vetor de tamanho indefinido */
- - - - - - - - - - - - - - - - - - - - - - - - - - - int tamanho = 10;
...
float vet[tamanho] /* tamanho é uma variável */
Matrizes e vetores
int vet[100];
armazena 100 números inteiros. O primeiro elemento está em vet[0]
e o último em vet[99].
É importante notar que em C não há verificação de limites em
vetores. O exemplo abaixo não apresenta erro de compilação,
apenas de execução:
x = 3 * vet[100]; /* Erro: não existe o elemento vet[100] */
vet[200] = cont;
/* Erro: não existe o elemento vet[200] */
O espaço de memória, em bytes, ocupado por um vetor é igual a:
espaço = tamanho * (número de bytes ocupado por tipo)
Matrizes e vetores
- Internamente na memória, tanto
vetores quanto matrizes utilizam a
memória de forma continua, não
fazendo distinção se uma variável
é um vetor ou uma matriz
Memória
[ ... ]
notas[0]
notas[1]
notas[2]
cont
mat[0][0]
mat[0][1]
mat[1][0]
mat[1][1]
8.5
9.5
7.0
0
1
5
-1
10
[000800]
[000804]
[000808]
[00080B]
[000810]
[000814]
[000818]
[00081B]
[ ... ]
-Dessa forma passaremos a
chamar tanto vetores quanto
matrizes simplesmente por
Arrays
Matrizes e vetores
Inicialização de arrays
Arrays multidimensionais não dimensionadas
São aquelas cujo tamanho não é especificado previamente
Precisa informar uma dimensão a não ser a primeira
Memória
[ ... ]
float notas[3] = {8.5, 9.5} ;
int cont = 0;
int mat[][2] = {{1, 5},{-1, 10}};
E se não fosse Informado o 2 ? Lembrando que precisa ao
menos de uma dimensão a não ser a primeira...
Erro: declaration of `mat' as multidimensional array must
have bounds for all dimensions except the first ( arrays
multidimentsionais devem ter limites definidos exceto para
o primeiro)
notas[0]
notas[1]
notas[2]
cont
mat[0][0]
mat[0][1]
mat[1][0]
mat[1][1]
8.5
9.5
7.0
0
1
5
-1
10
[000800]
[000804]
[000808]
[00080B]
[000810]
[000814]
[000818]
[00081B]
[ ... ]
Matrizes e vetores - Strings
char disc[15]
Memória
disc[0]
disc[1]
disc[2]
disc[3]
disc[4]
disc[5]
disc[6]
disc[7]
disc[8]
disc[9]
disc[10]
disc[11]
disc[12]
disc[13]
disc[14]
l
i
n
g
u
a
g
e
m
I
‘\0’
?
?
?
= “linguagem I”;
[ ... ]
[000600]
[000601]
[000602]
[000603]
[000604]
[000605]
[000606]
[000607]
[000608]
[000609]
[000610]
[000611]
[000612]
[000613]
[000614]
Em C uma string é um vetor
de caracteres terminado
com um caractere nulo,
represen-tado por ‘\0’.
O mesmo é colocado
implicitamente pela
linguagem mas deve-se
reservar espaço pra ele.
Matrizes e vetores - Strings
Arrays multidimensionais não dimensionadas para
armazenar strings
São aquelas cujo tamanho não é especificado previamente
Lembre-se que existirá sempre um espaço a mais para o \0 no
final
char vet1[37]="Estou aprendendo a programar em C!!!";
char vet2[]="Estou aprendendo a programar em C!!!";
char nomes[][20]
=
{ “Fulano de Tal”,
“Beltrano da Tal”,
“Ciclano de Tal”}
3 linhas (implicito)
e 20 colunas
E se não fosse Informado o 20 ? Lembrando que precisa ao menos de uma dimensão...
Erro: declaration of `nomes' as multidimensional array must have bounds for all dimensions
except the first ( arrays multidimentsionais devem ter limites definidos exceto para o primeiro)
Matrizes e vetores - Strings
Para os vetores de caracteres, não podemos fazer
atribuições diretas de constantes string, somente de
constantes caracter.
char disc[15] = “linguagem I”; /* Ok: inicialização */
...
disc[10] = ‘1’; /* atribuição válida, pois ‘1’ é um char */
disc = “Arquitetura”; /* atribuição inválida */
*** [Error] incompatible types in assignment of 'const char [12]' to 'char [15]'
O motivo disso é que “linguagem I” é uma constante...
Matrizes e vetores - Strings
Para atribui uma constante string a um vetor de
caracteres devemos utilizar a função strcpy(destino,
valor) da biblioteca string.h.
char disc[15] = “linguagem I”; /* Ok: inicialização */;
...
strcpy(disc, “Arquitetura”); /* atribuição válida */
Matrizes e vetores - Strings
Cuidado com o scanf() para leitura de strings.
Scanf é “bufferizado” por tal motivo você precisa dar um fflush
no buffer de entrada após seu uso com strings ou o scanf()
seguinte não funcionará corretamente
Mais adiante você irá aprender como contornar essa situação
char a[10];
Insira um
scanf("%s", &a);
printf("%s", a);
scanf("%s", &a); /* “não executa” esse */
printf("%s", a);
fflush(stdin);
Exatamente aqui para limpar o buffer
do primeiro scanf() e executar
corretamente o segundo scanf()
printf(“pulou o segundo scanf");
Se você digitar “oi mundo” no primeiro scanf() a saída será “oi mundopulou o
segundo scanf”  note que o segundo scanf() não foi executado como
esperado
Funções Básicas de E/S
printf: imprime o texto na saída padrão
formalmente:
int printf(char *, ...);
printf(“expressão de controle”, argumentos);
expressão de controle: formada pelo texto a ser impresso juntamente com
os comandos de controle;
argumentos: dados (variáveis e constantes) a serem impressos;
printf(“O caracter %c é o primeiro do alfabeto.”, ‘a’);
printf(“A data de hoje eh: %2d\\%2d\\%4d”, dia, mes, ano);
printf("Raio: %f --> Area: %f\n", r, meu_pi*r*r);
printf
Código
Imprimirá
%c
Um único caracter
%d
Decimal
%i
Decimal
%e
Ponto flutuante em notação científica
%f
Ponto flutuante
%g
mais curto entre %e e %f
%o
Octal
%s
String de caracteres
%u
Decimal sem sinal
%x
Hexadecimal
%%
Um sinal de %
%lf
double
printf
•
É possível controlar a quantidade mínima de símbolos a ser
apresentado no printf:
...
cont = 97;
printf(“Contador = [%4d]”, cont );
 Contador = [97]
printf(“Contador = [%8d]”, cont );
 Contador = [97]
printf(“Contador = [%04d]”, cont );
 Contador = [0097]
printf(“Contador = [%-4d]”, cont );
 Contador = [97]
printf(“Contador = [%8.4d]”, cont );
 Contador = [0097]
printf
•
Pode-se usar o controle do número de símbolos a ser
apresentado da seguinte maneira:
%m.n<formato>
onde m é o número mínimo de símbolos apresentados e n tem
seu comportamento definido conforme o formato.
%f, %lf
fará arredondamento necessário a fim de que
apareçam n dígitos após a vírgula, formatado num
espaço de m caracteres;
%o, %i, %d, %u
preenche com q zeros à esquerda do dado. Onde q
= n – dígitos significativos do número formatados no
espaço de m caracteres
%s
Imprimirá somente os n primeiros
formatados no espaço de m caracteres
%c
Sem efeito
caracteres
printf
•
•
•
Valores em ponto flutuante são arredondados;
Colocando-se 0 ele preenche com zeros a esquerda:
%07d
Colocando-se – ele faz alinhamento a esquerda: %-8f
...
int dist = 97;
float teste = 345.656;
char texto[20] = "testando tamanho";
printf("Resultado: [%10.2f]", teste);
 Resultado: [
printf("Resultado: [%10s]", texto);
 Resultado: [testando tamanho]
printf("Resultado: [%10.5d]", dist);
 Resultado: [
00097]
printf("Resultado: [%10.6s]", texto);
 Resultado: [
testan]
printf("Resultado: [%-10.3s]",texto);
 Resultado: [tes
345.66]
]
Caracteres Especiais
Alguns caracteres especiais:
'\n': mudança de linha.
'\r': volta para começo da linha.
'\b': volta um caracter.
'\\': caracter \
'\"': caracter “
'\t': caracter TAB
Outros caracteres especiais podem ser inseridos com: '\xNN',
onde NN é o código hexadecimal do caracter.
printf(“\nS\xA1mbolo = \t[%c]",65);
Símbolo = [A]
Funções Básicas de E/S
scanf: lê dado na entrada padrão (teclado)
formalmente:
int scanf(char *, ...);
scanf(“expressão de controle”, argumentos);
expressão de controle: determina como os dados serão lidos de acordo
com o especificador de formato;
argumentos: posição de memória onde o(s) valor(es) será(ão)
armazenado(s);
scanf(“%c”, &opcao);
/* lê um char */
scanf(“%f”, &total);
/* lê um float */
scanf(“%d%d%d”, &dia, &mes, &ano); /* lê três inteiros */
scanf(“%lf”, &raio);
/* lê um double */
scanf
formato
Lerá
%c
Um único caracter
%d
Decimal
%i
Decimal
%e
Ponto flutuante em notação científica
%f
Ponto flutuante
%g
mais curto entre %e e %f
%o
Octal
%s
String de caracteres
%u
Decimal sem sinal
%x
Hexadecimal
%p
Ponteiro
Problema com scanf
#include <stdio.h>
int main() {
char Nome[50];
printf("Qual o seu primeiro nome? ");
scanf("%s", &Nome);
printf(“%s”, Nome);
return 0;
}
Se a entrada for “Fulano de tal” a saída será somente “Fulano”
Forma alternativa de uso do scanf
#include <stdio.h>
int main() {
char Nome[50];
printf("Qual o seu nome completo? ");
scanf("%[a-z A-Z]", &Nome);
printf(“%s”, Nome);
return 0;
}
É uma alternativa... (leia g*a*m*b*i*a*r*r*a)
Solução mais correta
#include <stdio.h>
int main() {
char Nome[50];
printf("Qual o seu nome completo? ");
gets(Nome);
return 0;
}
É a solução mais correta para leitura de strings!!!
Em resumo....
Não use scanf para ler strings ou caracteres...
Use uma das alternativas a seguir !!!!
Funções Básicas de E/S
gets

gets(char *);
Le um caracter até que o terminador de linha (‘\n’) seja
encontrado.
Terminador de linha não é armazenado
Exemplo
#include <stdio.h>
int main() {
char string [256];
printf (“Informe seu endereco: ");
gets (string);
printf (“Seu endereco : %s\n",string);
return 0;
}
Funções Básicas de E/S
getchar

getchar(void);
Retorna um único caracter esperando retorno do carro
Definida em stdio.h  PADRÃO ANSI - Use em seus
programas ao invés de system(“pause”)
Exemplo
#include <stdio.h>
int main () {
char c;
puts (“Entre com o texto. Se um ponto ('.') para sair:");
do {
c=getchar();
putchar (c);
} while (c != '.');
return 0;
}
Funções Básicas de E/S
As vezes pode ser necessário limpar o buffer de entrada
antes de usar a função, principalmente após um scanf
usar fflush(stdin)
Exemplo
#include <stdio.h>
int main () {
char valor[10];
printf(“Informe o valor”);
scanf(“%s”, valor);
printf(“%s”, valor); Se não for colocado o getchar
interpreta o “lixo” deixado pelo scanf
no buffer como entrada
fflush(stdin);
getchar(); /* faz parar esperando tecla */
return 0;
}
Funções Básicas de E/S
getch(void) ou getche(void)
Retorna um único caracter sem esperar retorno do carro
Definida em conio.h  não é padrão ansi
Exemplo
#include <stdio.h>
int main () {
char c;
puts (“Entre com o texto. Se um ponto ('.') para sair:");
do {
c=getchar();
putchar (c);
} while (c != '.');
return 0;
}
Funções Básicas de E/S
putchar

putchar(int);
Escreve um caracter na tela
Exemplo
#include <stdio.h>
int main () {
char c;
for (c = 'A' ; c <= 'Z' ; c++) {
putchar (c);
}
return 0;
}
Funções Básicas de E/S
puts

puts(str);
Escreve uma string na tela e avança linha (inclui ‘\n’ no final)
Exemplo
#include <stdio.h>
int main () {
char string [] = "Hello world!";
puts (string);
return 0;
}
Funções Básicas de E/S
getchar()
 Lê um caracter do teclado. Espera retorno do carro
(tecla enter). Padrão ANSI
getche() Lê um caracter COM echo; não espera retorno do
carro; não definido pelo ANSI mas é uma extensão comum
getch() Lê um caracter SEM echo; não espera retorno do carro;
não definido pelo ANSI mas é uma extensão comum
putchar()  Escreve um caracter na tela
gets()  Lê uma string do teclado
puts()  Escreve uma string na tela
Operadores
Operadores determinam as operações básicas que podem ser
executadas nos valores.
Levam em consideração os tipos das variáveis.
Em torno de 40 operadores.
Há diversos tipos de operadores:
Atribuição
Atribuição Reduzida
Aritméticos
Lógicos
Condicionais
Bit a bit
Incremento e Decremento
…
Atribuição
Utiliza o sinal gráfico = para representação.
= significa igual a
X = 80;
a = b = 20;
a = (b = 5) + 3;
3 = a;
/* válido
*/
/* válido
*/
/* Inválido */
Operadores Aritméticos
Realizam as operações aritméticas básicas.
Aplicáveis a qualquer tipo de dado (exceto void).
Principais operadores aritméticos binários:
Soma: +
Subtração: Produto: *
Divisão: /
Resto da divisão inteira: %
Unários
Quando aplicado
a valores inteiros
devolve um
inteiro
Sinal: -
 Operação aritmética de negação e conversão do tipo como o +
Sinal: +
 Retorna um signed int ( se short “promove” pra int que é maior)
Não há operador de potenciação.
Exemplos
int n = 10, d = 7;
double x, y, z; /* Vírgula separa declarações de mesmo tipo */
int i, j, k;
i = 25;
/* Atribuição */
j = d + i;
/* j recebe 32 */
k = i / n;
/* k recebe 2 (divisão inteira) */
i = n % d;
/* i muda para 3 */
x = 25; y = 10; /* converte int -> double */
z = x / y;
/* z recebe 2.5 – x e y são double */
Atribuição Reduzida
Uma operação pode ser combinada com a atribuição em
um mesmo operador:
+=, -=, *=, /=, %=, >>=, <<=, &=, |=, ^=
Assim:
a += b;
/* O mesmo que a = a + b */
c -= b*a;
/* O mesmo que c = c – (b*a) */
d *= a - b; /* O mesmo que d = d * (a - b) */
Incremento e Decremento
C dispõe de operadores de auto-incremento (++) e autodecremento (--).
Podem ser utilizados de maneira pré-fixada ou pós fixada.
Pré-fixa: primeiro incrementa/decrementa depois faz o restante
Pós-fixa: primeiro faz a operação, depois incrementa/decrementa
int n = 0, m
n++;
++m;
n--; --n;
a = n++;
b = ++m;
c = 2* m++;
d = 3* ++n;
d += ++n;
= 0, a, b, c, d;
/* n agora vale 1 */
/* m agora vale 1 */
/* n agora é -1 */
/* a recebeu -1; n vale 0 */
/* b recebeu 2; m vale 2 */
/* c recebeu 4; m vale 3 */
/* d recebeu 3; n vale 1 */
/* d recebeu 5; n vale 2 */
Incremento e Decremento
int main(){
int a = 0, b = 0;
printf("A:%d
B:%d \n", ++a, b++);
printf("A:%d
B:%d\n", a, b);
return 0;
}
Resultado:
A:1 B:0
A:1 B:1
Operadores relacionais
Utilizados para comparar/relacionar dois operandos:
== (igual a)
!= (diferente de)
> (maior que)
< (menor que)
>= (maior ou igual a)
<= (menor ou igual a)
O resultado da avaliação será sempre 0(falso) ou 1(verdadeiro)
Operadores relacionais
if (x >= 0)
printf(“positivo");
else
printf(“negativo");
Cuidado!!!
(x == 0)
if (x = 0)
printf(“zero");
else
printf(“não zero");
Operadores lógicos
Comportam-se como operadores booleanos:
&& (e) – todos os operandos devem ser verdadeiros
para a
saída ser verdadeira
|| (ou) – ao menos um dos operandos deve ser
verdadeiro
para a saída ser verdadeira
! (não) – inverte o operando. Se era falso torna-se
e vice-versa
if (!aux)
printf(“zero");
if (x == 0)
verdadeiro
if (x >= 0 && x < 5)
printf("dentro");
else if (x < 0)
printf("muito pequeno");
else
printf("muito grande");
Operadores lógicos
C realiza avaliação curto-circuito:
Avaliação curto circuito de uma expressão é uma avaliação onde o
resultado da expressão pode ser determinado avaliando-se apenas alguns
de seus operandos, obtendo-se o mesmo valor caso a expressão seja
avaliada por completo.
O propósito de uma avaliação curto circuito é dar eficiência, em tempo de
execução. A execução será mais rápida pois na avaliação da expressão
alguns operandos não serão avaliados.
Cuidado com efeitos colaterais.
aux = 20; val = 40
if (aux > 0 || val > 0)
printf(“curto-curcuito");
Operadores bit a bit
Realizam operações booleanas bit a bit sobre números inteiros:
& (and)
| (or)
^ (xor)
~ (complemento)
>> (deslocamento à direita)  deslocando 1 bit = divisão por 2
<< (deslocamento à esquerda)  deslocando 1 bit = mult. por 2
A operação é realizada sobre o valor expresso em binário;
Operadores bit a bit
Expressão
1|2
0xFF & 0x0F
Em binários
Resultado
00000001 | 00000010
11111111 & 00001111
00000011 = 0X03 = 3
00001111 = 0x0F = 15
0x0D << 2
00001101 << 2
00110100 = 0x34 = 52
0x1C >> 1
00011100 >> 1
00001110 = 0x0E = 14
~0x03
~(00000011)
3^2
00000011 ^ 00000010
11111100 = 0xFC = 252
00000001 = 0X01 = 1
Operador Sizeof
Este operador retorna o tamanho da variável ou tipo que está em
seu operando.
Por exemplo:
float area;
int idades[10];
printf(“Um inteiro ocupa %d bytes de memória”,
sizeof(int));
printf(“Um float ocupa %d bytes de memória”, sizeof
area);
printf(“O vetor \”idades\” ocupa %d bytes de memória”,
sizeof idades);
Operador Sizeof
Para saber o tamanho de um array com sizeof()
Sizeof retorna o tamanho em bytes do array. Divide-se então pelo tamanho em
bytes de um único elemento para se obter o total de elementos
int main
int vetor[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
printf(”Tamanho do array = %d”, sizeof(vetor) / sizeof(vetor[0]) );
}
Saída:
Tamanho do array = 9
Precedência e Associatividade
Diversos operadores podem ser utilizados na mesma
expressão.
A ordem de execução dos operadores pode ser determinada
explicitamente pelo uso de parêntesis.
Quando não são usados parêntesis, o compilador usa regras de
precedência para determinar qual operação executar primeiro.
Se duas operações têm a mesma precedência, executa de
acordo com regra de associatividade (normalmente da
esquerda para a direita).
Precedência e Associatividade
Exemplos
a = b + c; /* Atribuição tem menor precedência que soma */
d = (a + b) * c;
/* Determinada pelos parêntesis */
e = a + b * c;
/* * tem maior precedência que + */
f = a + b – c;
/* (a + b) – c */
g = f/e*g;
/* (f/e)*g */
f = a + b * c – d / e; /* (a + (b*c)) – (d/e) */
a = b = c = d = 0;
/* (a = (b = (c = (d = 0)))) */
Funções Matemáticas – Math.h
Algumas funções matemáticas de math.h:
Trigonométricas: sin, cos, tan, asin, acos, atan, atan2.
Relacionadas a exponencial: exp, pow, sqrt, log, log10,
sinh, cosh, tanh.
Outras: fabs, ceil, floor, fmod.
Math.h
Funções mais comuns
pow( )
Calcula a potência de um número.
Exemplo :
pow(num,pot)
Onde, num é a base e pot é o expoente.
Se num fosse 2 e pot fosse 3 seria : 2 elevado a 3 (2
ao cubo), onde resultaria em 8 (2x2x2 - 2 multiplicado
por ele mesmo 3x).
Exemplo
#include<stdio.h>
#include<math.h>
int main()
{
double Total, j, m;
int n;
printf("Valor do bem:
");
scanf("%lf", &Total);
printf("Taxa de juros anual (em %%): ");
scanf("%lf", &j); j /= 100*12;
printf("Numero de meses:
");
scanf("%d", &n);
m = Total * j / (pow(1+j,n) - 1);
printf("Investimento mensal:
%.2f", m);
return 0;
}
Math.h
Funções mais comuns
fmod( )
Calcula o resto da divisão de números inteiros.
Exemplo :
fmod(5,2)
Resultaria em 1, já que 5 dividido por 2, daria 2 e
sobraria 1.
É o próprio % como usado até agora
Math.h
Funções mais comuns
sqrt( )
Raiz quadrada.
Exemplo :
sqrt(num)
Extrai a raiz quadrada de num.
Se num fosse 25, então o resultado seria 5.
Math.h
Funções mais comuns
fabs( )
Retorna o valor absoluto de um número.
Exemplo :
fabs(-8)
Retornará : 8
Se o número for negativo, retornará o mesmo, mas
positivo.
Math.h
Funções mais comuns
ceil( )
Arredonda um número para cima.
Exemplo :
ceil(2.45)
Retornará : 3
Math.h
Funções mais comuns
floor( )
Arrendondará um número para baixo.
Exemplo :
floor(2.78)
Retornará : 2
Diretivas de Pré-Processamento
A linguagem C oferece mecanismos que permitem manter
definições unificadas que são compartilhadas entre diversos
arquivos.
A base destes mecanismos é o pré-processamento de código, a
primeira fase na compilação do programa.
Essencialmente, o pré-processador é um processador de macros
para uma linguagem de alto nível.
As diretivas do C são identificadas por começarem por #.
Algumas das diretivas definidas pelo padrão ANSI são:
#include
#define
#undef
#if
#ifndef
#ifdef
#endif
#else
#elif
Diretivas de Pré-Processamento
#include
diz ao compilador para incluir, na hora da compilação, um
arquivo especificado. Sua forma geral é:
#include <nome_do_arquivo>
ou
#include “caminho_e_nome_do_arquivo"
A primeira é utilizada para bibliotecas da linguagem e a segunda
para inclusão arquivos de cabeçalho
Diretivas de Pré-Processamento
#define
#define nome_da_macro sequência_de_caracteres
Quando você usa esta diretiva, você está dizendo ao compilador
para que, toda vez que ele encontrar o nome_da_macro no
programa a ser compilado, ele deve substituí-lo pela
sequência_de_caracteres fornecida.
Um outro uso da diretiva #define é o de simplesmente definir uma
macro.
#define nome_da_macro
Neste caso o objetivo estamos definindo uma macro para ser usada
como uma espécie de flag. Isto quer dizer que estamos definindo um
valor como sendo "verdadeiro" para depois podermos testá-lo.
Diretivas de Pré-Processamento
Também é possível definir macros com argumentos.
#define max(A,B) ((A>B) ? (A):(B))
#define min(A,B) ((A<B) ? (A):(B))
...
x = max(i,j);
y = min(t,r);
Embora pareça uma chamada de função, o uso de max (ou min)
simplesmente substitui, em tempo de compilação, o código
especificado.
Cada ocorrência de um parâmetro formal (A ou B, na definição)
será substituído pelo argumento real correspondente.
x = ((i>j) ? (i):(j));
y = ((i<j) ? (i):(j));
Diretivas de Pré-Processamento
Exemplo 1
#define max(A,B) ((A>B) ? (A):(B))
...
x = max(p++,r++);
/* x = ((p++ > r++) ? (p++):(r++)) */
Exemplo 2
#define dobro(X) X*X
...
y = dobro(y+z)
/* y = a+b*a+b */
Espaço em
branco
Quando você utiliza a diretiva #define nunca deve haver
espaços em branco no identificador:
#define PRINT (i) printf(“ %d \n", i)
/* não funcionará corretamente */
Diretivas de Pré-Processamento
Diretivas de compilação condicional: Elas são muito parecidas com
os comandos de execução condicional do C. As duas primeiras
diretivas são as #ifdef e #endif. Suas formas gerais são:
#ifdef nome_da_macro
sequência_de_declarações
#endif
A seqüência de declarações será compilada apenas se o nome da
macro estiver definido.
#define PORT_0 0x378
...
/* Linhas de codigo qualquer... */
...
#ifdef PORT_0
#define PORTA PORT_0
#include "../sys/port.h“
#endif
Diretivas de Pré-Processamento
A diretiva #ifndef funciona ao contrário da diretiva #ifdef. Sua forma
geral é:
#ifndef nome_da_macro
sequência_de_declarações
#endif
A seqüência de declarações será compilada se o nome da macro
não tiver sido definido
#ifndef PORT_0
#include "../sys/port.h“
#endif
Diretivas de Pré-Processamento
As diretiva #if, #else e #elif funcionan respectivamente como o if,
else e else if. Observe o exemplo:
#define SISTEMA DOS
...
/*linhas de codigo..*/
...
#if SISTEMA == DOS
#define CABECALHO "dos_io.h“
#else
#define CABECALHO "unix_io.h“
#endif
#include CABECALHO
Bibliografia
SEBESTA, R. W. Conceitos de Linguagem de
Programação. 4 ed. Porto Alegre: Bookman Companhia
Ed. 2000.
KERNIGHAM, Brian W. & RITCHIE, Dennis M. C: A
Linguagem de Programação. Rio de Janeiro: Ed.
Campus. 1986.
SCHILDT, Herbert. C Completo e Total. 3ª. Ed. São
Paulo: Makron Books. 1996.
Apostilas e sites da Internet