Baseado no curso da Softblue
Introdução
O que é o C?
– Linguagem de programação
– Criada por Dennis Ritchie (meados de 1970)
– Padronizada pelo ANSI em 1983 (portabilidade)
– Atualmente a mais utilizada no mundo
– Diferença do C para o C++(novos recursos - orientação a objetos)
- Linguagem de programação C
– Nível médio
– Estruturada
– Compilada
– Portável
Próxima do baixo nível
- Vantagens
– Linguagem com comandos e tipos de dados simples
– Acesso livre à memória
– Velocidade
- Codificar
– Arquivos com extensão .c
– Não utilizar processadores de texto (Word)
- Compilar
– Processo de transformar código-fonte em
código-objeto (de máquina)
- Linkeditar
– Unificação de programas e bibliotecas diversas
Distribuir
Desvantagens
– Não possui classes e objetos
– Não possui um gerenciador de memória
– Outros (multi-thread, web)
Arquitetura da memória
- 4 regiões de memória
– Código do programa (instruções compiladas)
– Variáveis globais
– Pilha (ordem das chamadas e retornos)
– Heap (memória livre)
Tipos de dados e operadores
Tipos de dados
Tipo | Intervalo | Bits (padrão ANSI) |
---|---|---|
char / signed char | -127 a 127 | 8 |
unsigned char | 0 a 255 | 8 |
int / signed int / short int / signed short int | -32.767 a 32.767 | 16 |
unsigned int | 0 a 65.535 | 16 |
long int / signed long int | -2.147.483.647 a 2.147.483.647 | 32 |
unsigned long int | 0 a 4.294.967.295 | 32 |
float | 6 casas decimais | 32 |
double | 10 casas decimais | 64 |
long double | 10 casas decimais | 80 |
Modificador short/long
apenas com int e double
Modificador signed/unsigned
Variáveis
Espaços de memória alocados para armazenar valores.
Nomenclatura: não utilizar caracteres especiais, nem espaços em branco ou pontuações. Pode utilizar números, mas não no início. Case sensitive.
Escopo local - criadas dentro do bloco de código e excluídas ao final do bloco. As variáveis devem sempre ser criadas no início do bloco (C++ é mais flexível).
Variáveis globais - ocupam memória durante toda a execução. Declaradas no início do arquivo, fora de qualquer bloco de código.
1
2
3
4
Operador de atribuição =
Atribuição múltipla: x = y = z = 3
Hexadecimais: int x = 0x145; // número 325 em decimal
Octais: int y = 0505; // número 325 em decimal
Modificadores de armazenamento
extern - resolve o conflito de variáveis e constantes globais entre diferentes programas em C. Defina a variável no primeiro programa, sem extern, e nos demais com extern.
static - variáveis que mantém seus valores entre diferentes chamadas de uma mesma função.
register - armazena a variável no mecanismo de acesso mais rápido disponível (no registrador do processador, e não na memória, por exemplo).
Constantes
const - valores constantes que não podem ser alterados durante a execução. Não podem ser inicializadas em separado.
volatile - Constantes que podem sofrer alterações por vias externas ao seu programa.
Enumerações
Grupos de valores que uma variável pode ter. Para limitar o valor de uma variável em um subconjunto conhecido de valores.
Sintaxe: enum nome {valores,}
Operadores Matemáticos
Operador | Operação | |
---|---|---|
+ | soma | |
++ | soma 1 | x++ utiliza o valor atual de x na expressão e depois incrementa-o, enquanto ++x primeiro incrementa x e depois utiliza o valor atualizado na expressão |
- | subtração | |
– | subtrai 1 | X– utiliza o valor atual de x na expressão e depois decrementa-o, enquanto –x primeiro decrementa x e depois utiliza o valor atualizado na expressão |
* | multiplicação | |
/ | divisão | |
% | resto da divisão inteira |
Podem ser associados ao sinal de atribuição (+=, por exemplo).
Operações matemáticas entre diferentes tipos de dados podem ocasionar imprecisão. Conversão automática de tipos de dados. Promoção de tipo.
Conversão implícita (cast):
1
2
3
int x = 10;
int y = 3;
(double) x / y;
Operadores bit a bit
Operações de baixo nível. Representados pelos tipos int e char.
Operadores bit a bit
Operador | Operação | |
---|---|---|
& | AND (“e” lógico) | |
OR (“ou” lógico) | ||
^ | XOR (“ou” exclusivo) | |
~ | Complemento de um | |
» | Deslocamento para a direita | |
« | Deslocamento para a esquerda |
Diretivas (#)
Instruções pré-processadas pelo compilador.
Tempo de compilação vs Uso de variáveis.
Cada uso de uma diretiva deve ser realizado em uma linha própria.
1
2
3
4
5
6
7
8
9
10
11
#define - permite atrelar um valor por meio de um identificador #define PI 3.14 . Pode ser utilizada para definir uma breve função.
#undef - remove a definição de uma chave.
#if - condição em tempo de compilação, inicia um bloco de código sem necessidade de chaves.
#else - encerra o bloco anterior e inicia o negativo.
#elif - encerra o bloco anterior e abre outro condicional.
#endif - Encerra o bloco como um todo.
1
2
3
4
5
6
7
#if PI > 5
//se verdadeiro
#elif PI < 5
//se verdadeiro
#else
//se falso
#endif //encerra o bloco if
1
2
3
4
5
6
7
8
9
#ifdef - verifica se uma chave foi definida. Termina com #endif. Permite o use de #else.
#ifndef - verifica se uma chave não foi definida. Termina com #endif. Permite o use de #else.
#line - Gerencia o número da linha. Identificadores __line__ e __file__
#error - interrompe a compilação.
#include - orienta o compilador para ler outro arquivo. Comando de importação de bibliotecas.
Operadores Relacionais
1
2
3
4
5
6
7
8
9
10
11
== mesmo valor mesmo que tipos diferentes
!= diferentes em valor
< menor que
> maior que
<= menor igual
>= maior igual
Operadores Lógicos
1
2
3
4
5
6
7
8
9
10
11
! negação
& e
| ou
&& e verificando a primeira condição e já resultando falso se for o caso
|| ou verificando a primeira condição e já resultando verdadeiro se for o caso
Precedência: aritméticos>relacionais>!>&&>||
Controle de fluxo e repetição
Comandos de decisão
Qualquer valor diferente de false e de 0 é considerado verdadeiro (true). Quando um comando if não apresenta suas chaves para definição de suas ações, apenas um comando é atrelado a ele.
1
2
3
if(condição) {}
else if(condição) {}
else{}
short if
1
condição ? verdadeiro : falso;
valor apenas int
1
2
3
4
5
switch(valor){
case 0: ...
break;
default:
}
Comandos de repetição - laços - iterações
1
2
3
for(inicialização; condição; incremento) {}
while(condição) {}
do {} while(condição)
Comandos de controle
break interrompe repetição
continue interrompe a execução atual da repetição mas permite a continuação do laço
return encerra a execução da função, pode retornar valores à chamada da função
exit encerra a aplicação retornando se o encerramento foi intencional (exit 0) ou por erro (exit 1). Disponibilizado pela biblioteca stdlib.h
Exemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "stdio.h"
int main()
{
char *c;
int x = 5, y = 0;
// Comandos IF, ELSE IF e ELSE
x = 1;
if(x >= 5)
{
printf("x vale 5 ou mais n");
}
else if(x >= 3)
{
printf("x vale 3 ou mais n");
}
else
{
printf("x nao vale mais que 3");
}
x = -50;
y = x >= 0 ? 1 : -1;
printf("n y vale %d n", y);
// Comandos SWITCH, CASE, BREAK e DEFAULT
x = 3;
switch(x)
{
case 1:
printf("n x vale 1 n");
break;
case 2:
printf("n x vale 2 n");
break;
case 3:
printf("n x vale 3 n");
break;
default:
printf("n x nao foi identificado n");
break;
}
// Comandos FOR, BREAK e CONTINUE
printf("n");
for(x=0; x<10; x++)
{
if(x == 8)
{
break;
}
if(x == 3)
{
continue;
}
printf("%d ", x);
}
printf("n");
x = 5;
if(x == 10)
{
x = 15;
x++;
}
printf("n %d n", x);
// Comando WHILE
printf("n Comando While n");
x = 0;
while(x < 10)
{
printf("%d ", x);
x = x + 1;
}
printf("n");
// Comando DO WHILE
printf("n Comando Do While n");
x = 0;
do
{
printf("%d ", x);
x = x + 1;
} while(x < 10);
printf("n");
x = 2;
y = 11;
if(y == 11 && x++ == 5)
{
printf("n Sucesso n");
}
else
{
printf("n Falha n");
}
printf("X vale neste momento: %d n", x);
scanf("%c", &c);
return 0;
}
Leitura e exibição de valores
1
2
3
#stdio.h
printf("string de formatação", variáveis);
//caracteres especiais não são suportados
Caracteres de formatação
Símbolo | Descrição |
---|---|
%c | Caractere |
%d, %i | Número inteiro (com sinal) |
%u | Número inteiro (sem sinal) |
%e, %E | Notação científica |
%f | Ponto flutuante |
%lf | Ponto flutuante longo |
%o | Octal |
%s | String |
%x, %X | Hexadecimal |
%p | Ponteiro |
%% | Símbolo de percentual |
sprintf(variável destino, “caractere de formatação”, variável origem); idêntico ao printf, mas não exibe na tela, e sim aloca em uma variável de texto. Utilizada para converter números em texto.
Formatando valores numéricos: %a.b símbolo do tipo de dado a: quantidade de que casas serão exibidas; b: quantidade máxima de caracteres ou de casas de ponto flutuante.
Lendo informações:
1
2
3
4
#stdio.h
scanf("caractere de formatação de string", &endereços de memória-variável);
//não suporta espaço em branco entre palavras
//caracteres especiais não são suportados
Gerando números randômicos:
1
2
3
4
5
6
7
8
9
10
#stdlib.h
rand();
//retorna um flutuante randômico entre 0 e 1
//baseado em uma semente
srand(semente);
//define uma nova semente para a função rand
//o tempo atual pode ser utilizando como semente
#time.h
time();
//retorna a quantidade de segundos desde 00:00 de 01/01/1970
Manipulando datas:
1
2
3
4
5
6
#time.h
//tipo de dado time_t instante (data e hora) quantidade de segundos desde 00:00 de 01/01/1970
//estrutura struct tm organiza o time_t
time(); //retorna o time_t atual
localtime(); //time com fuso local
strftime(); //formata data e hora
Caracteres de formatação de data e hora com strftime
Símbolo | Descrição |
---|---|
%a | Dia da semana abreviado |
%A | Dia da semana |
%b | Mês abreviado |
%B | Mês |
%c | Data e hora completa |
%d | Dia do mês (1-31) |
%H | Hora (24) |
%l | Hora (12) |
%j | Dia do ano (1-366) |
%m | Mês (1-12) |
%M | Minuto (0-59) |
%p | AM, PM |
%S | Segundos (0-59) |
%U | Número da semana (a partir de domingo) |
%w | Dia da semana (0-6) (a partir de domingo) |
%W | Número da semana (a partir de segunda) |
%x | Data completa |
%X | Horário completo |
%y | Ano (yy) |
%Y | Ano (yyyy) |
%Z | Fuso horário |
Exemplos:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include "stdio.h"
#include "time.h"
int main()
{
char *c;
int varInt = 70;
double varDouble = 150.15;
float varFloat;
char varChar;
int y = 50, z = 100;
char buffer[100];
// Manipulando datas
time_t agora;
struct tm *tm_agora;
char texto[100];
// Caracteres de formatacao
printf("n Valor de varInt (inteiro): %d", varInt);
printf("n Valor de varInt (hexadecimal): %x", varInt);
printf("n Valor de varInt (octal): %o", varInt);
printf("n Valor de varInt (flutuante): %f", varInt);
printf("n Valor de varInt (caractere): %c", varInt);
printf("n Valor de varDouble (flutuante): %f", varDouble);
printf("n A soma de %d com %d resulta em %d", y, z, y+z);
printf("n %5.5f", 123.456789);
printf("n %15.5f", 123.456789);
printf("n %15.2f", 123.456789);
printf("n %3.5d", 123);
printf("n %3.3d", 123);
printf("n %10.3d", 123);
printf("n %10.5d", 123);
printf("n %20.25s", "Minha string");
printf("n %5.10s", "Minha string");
// Capturando valores
printf("n Insira um valor inteiro: ");
scanf("%d", &varInt);
scanf("%c", &c);
printf("n O valor digitado foi: %d", varInt);
printf("n Insira um valor float: ");
scanf("%f", &varFloat);
scanf("%c", &c);
printf("n O valor digitado foi: %f", varFloat);
printf("n Insira um valor double: ");
scanf("%lf", &varDouble);
scanf("%c", &c);
printf("n O valor digitado foi: %f", varDouble);
printf("n Insira um valor char: ");
scanf("%c", &varChar);
scanf("%c", &c);
printf("n O valor digitado foi: %c", varChar);
// Manipulando datas
agora = time(NULL);
tm_agora = localtime(&agora);
strftime(texto, sizeof(texto), "%d/%m/%y", tm_agora);
printf("n A data de hoje e: %s", texto);
sprintf(buffer, "A data de hoje e: %s", texto);
printf("n A variavel buffer contem: %s", buffer);
scanf("%c", &c);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "stdio.h"
#include "stdlib.h"
#include "time.h"
int main()
{
char *c;
int numeroSecreto, tentativa;
// Randomiza o numero a ser adivinhado
srand(time(NULL));
numeroSecreto = rand() % 20 + 1;
do
{
// Captura as tentativas do usuario
printf("n Adivinhe o numero (entre 1 e 20): ");
scanf("%d", &tentativa);
scanf("%c", &c); // Limpa o buffer
// Avalia se o usuario digitou algo menor ou maior
if(numeroSecreto < tentativa)
{
printf("n O numero e menor.");
}
else if(numeroSecreto > tentativa)
{
printf("n O numero e maior.");
}
} while(numeroSecreto != tentativa);
printf("n Acertou, o numero era: %d", numeroSecreto);
printf("n Pressione <ENTER> para sair...");
scanf("%c", &c);
return 0;
}
Ponteiros
Operadores
“E” comercial (&) – Permite acessar o endereço de memória de seu operando
Asterisco (*) – Permite acessar o valor armazenado em um endereço de memória fornecido
Ponteiro - Apontadores de endereços de memória. Um endereço de memória z armazena/aponta para outro endereço de memória x.
1
2
Printf("%d", z); //imprime o endereço de memória que foi atribuído
Printf("%d", *z); //imprime o valor que está armazenado no endereço de memória ao qual aponta z
Ponteiros em funções:
- Facilitam a atualização de variáveis enviadas para funções externas
Pois em C a passagem de parâmetros ocorre por cópia, por padrão, e não por referência.
- scanf usa ponteiro para atualizar as variáveis
A função scanf precisa receber o endereço de memória da variável que receberá o valor lido no formato inteiro (%d). Se ela receber um ponteiro como parâmetro, o código executa sem a necessidade de utilizar o &.
Apontamento múltiplo:
- Ponteiro que aponta para outro ponteiro
*** quantidade de asteriscos determina a multiplicidade do apontamento
Características de ponteiros
- Iniciam com valores sujos
– Podem apontar para áreas inválidas
- Utilização de valor nulo na inicialização
– int *p = NULL;
- Podem ser comparados em expressões condicionais
– Comparações numéricas
– Apontam para mesma área (==)
- Uma string (vetor de char) por si só já é um endereço de memória
Aritmética de ponteiros
Operações de adição e subtração
Ocorrem deslocando os endereços dos ponteiros para o próximo ou anterior de mesma base (tipo de dado)
A criação de matrizes na memória garante que os espaços alocados sejam vizinhos, o que permite as operações com ponteiros de maneira satisfatória.
Alocação dinâmica de memória
Biblioteca stdlib.h
Instrução malloc
– void* malloc(bytes)
Esse comando pode retornar um ponteiro nulo, então é importante criar um if para verificar se a alocação foi criada com sucesso antes de utilizar o ponteiro.
1
2
3
4
5
6
#include stdlib.h
char *minhaStr;
minhaStr = malloc(100);
if (!minhaStr) {
printf("Erro");
}
- Instrução free – free(void*)
// é importante liberar a memória para evitar leaks e travamento do sistema
Exemplo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include "stdio.h"
#include "stdlib.h"
void somaUmNormal(int i)
{
i = i + 1;
}
void somaUmPonteiro(int *i)
{
*i = *i + 1;
}
int main()
{
char *c;
int a, b;
int *pi = NULL;
int **ppi = NULL;
int *matrizInteiro;
int matrizSemPonteiro[5] = {2, 4, 6, 8, 10};
// Uso tradicional
a = 5;
b = a;
printf("n a = %d, b = %d", a, b);
a = 5;
b = a;
a = 8;
printf("n a = %d, b = %d", a, b);
a = b = 5;
a = 8;
printf("n a = %d, b = %d", a, b);
printf("n a = %d (%d), b = %d (%d)", a, &a, b, &b);
// Ponteiro
a = 5;
pi = &a;
a = 8;
printf("n a = %d, pi = %d", a, pi);
printf("n a = %d, pi = %d", a, *pi);
// Ponteiro para ponteiro
a = 5;
pi = &a;
ppi = π
printf("n a = %d, pi = %d, ppi = %d", a, *pi, ppi);
printf("n a = %d, pi = %d, ppi = %d", a, *pi, *ppi);
printf("n a = %d, pi = %d, ppi = %d", a, *pi, **ppi);
// Passagem por valor
a = 5;
somaUmNormal(a);
printf("n Soma normal: a = %d", a);
// Passagem por referencia
a = 5;
somaUmPonteiro(&a);
printf("n Soma normal: a = %d", a);
// Alocacao dinamica de memoria
matrizInteiro = (int *) malloc(5 * sizeof(int));
if(!matrizInteiro)
{
printf("Erro");
}
matrizInteiro[0] = 5;
matrizInteiro[1] = 10;
printf("n Posicao [0] = %d, posicao [1] = %d", matrizInteiro[0], matrizInteiro[1]);
// Liberacao de memoria alocada dinamicamente
free(matrizInteiro);
// Aritmetica de ponteiro
pi = &matrizSemPonteiro[0];
printf("n pi vale agora: %d", *pi);
pi++;
printf("n pi vale agora: %d", *pi);
pi = pi + 2;
printf("n pi vale agora: %d", *pi);
pi--;
printf("n pi vale agora: %d", *pi);
scanf("%c", &c);
return 0;
}
Matrizes
Também conhecidos como arrays, vetores
Conjunto de informações do mesmo tipo
Variável com mais de uma posição (slot)
Índice numérico sempre no zero
Matrizes unidimensionais (uma dimensão)
Sintaxe: tipo nome[tamanho];
Int numeros[7] = {33, 34, 35, 36, 37, 44}
Tamanhos de matriz
- Instrução sizeof() //nome da variável ou tipo de dado
– Obtém o tamanho em bytes
– Sabendo o tamanho total, e o tamanho do tipo de dado, pode-se calcular sua quantidade de posições
Matrizes multidimensionais
Matrizes com mais de uma dimensão
Matrizes dentro de matrizes (unidimensionais)
Todas as dimensões do mesmo tipo
Dimensões de tamanhos diferentes
Sintaxe: – tipo nome[tamanho][tamanho];
– tipo nome[tamanho][tamanho][tamanho];
Alocação dinâmica de memória
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "stdio.h"
#include "stdlib.h"
int main( )
{
int *matriz, x;
matriz = (int *) malloc(5 * sizeof(int)); //casting para ponteiro, pois o retorno padrão de malloc é void *
matriz[0] = 10;
matriz[1] = 15;
matriz[2] = 20;
matriz[3] = 25;
matriz[4] = 30;
for(x=0; x<5; x++)
{
printf("%d ", matriz[x]);
}
// 10 15 20 25 30
free(matriz);
return 0;
}
Exemplos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include "stdio.h"
#include "stdlib.h"
int main()
{
char *c;
// Declaracoes variadas
int x, y, z;
int matrizA[5] = {2, 2, 3, 3, 4};
int matrizB[5];
int *matrizC = NULL;
int *matrizD[5];
int matrizBD[2][3] = { {1, 2, 3}, {4, 5, 6} };
int matrizTD[2][2][2];
// Inserindo valores em uma matriz
matrizB[0] = 1;
matrizB[1] = 3;
matrizB[2] = 5;
matrizB[3] = 7;
matrizB[4] = 9;
// Exibindo valores
for(x=0; x<5; x++)
{
printf("n matrizA[%d] = %d, matrizB[%d] = %d", x, matrizA[x], x, matrizB[x]);
}
for(x=0; x < sizeof(matrizA) / sizeof(int); x++)
{
printf("n matrizA[%d] = %d, matrizB[%d] = %d", x, matrizA[x], x, matrizB[x]);
}
// Alocando dinamicamente uma matriz de 5 posicoes
matrizC = (int *) malloc(5 * sizeof(int));
matrizC[0] = 10;
matrizC[1] = 20;
matrizC[2] = 30;
matrizC[3] = 40;
matrizC[4] = 50;
for(x=0; x<5; x++)
{
printf("n matrizC[%d] = %d", x, matrizC[x]);
}
// Liberando da memoria uma matriz alocada dinamicamente
free(matrizC);
// Matriz de ponteiros
matrizD[0] = &matrizA[0];
matrizD[1] = &matrizA[1];
matrizD[2] = &matrizB[0];
matrizD[3] = &matrizB[1];
y = 3;
matrizD[4] = &y;
for(x=0; x<5; x++)
{
printf("n matrizD[%d] = %d", x, *matrizD[x]);
}
// Matriz bidimensional
matrizBD[0][0] = 55;
matrizBD[1][2] = 111;
for(x=0; x<2; x++)
{
for(y=0; y<3; y++)
{
printf("n matrizBD[%d][%d] = %d", x, y, matrizBD[x][y]);
}
}
// Matriz tridimensional
matrizTD[0][0][0] = 1;
matrizTD[0][0][1] = 2;
matrizTD[0][1][0] = 3;
matrizTD[0][1][1] = 4;
matrizTD[1][0][0] = 5;
matrizTD[1][0][1] = 6;
matrizTD[1][1][0] = 7;
matrizTD[1][1][1] = 8;
for(x=0; x<2; x++)
{
for(y=0; y<2; y++)
{
for(z=0; z<2; z++)
{
printf("n matrizTD[%d][%d][%d] = %d", x, y, z, matrizTD[x][y][z]);
}
}
}
scanf("%c", &c);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include "stdio.h"
#include "stdlib.h"
int main()
{
char *c;
// Ponteiro para matriz de uma dimensao
int *matrizUnidimensional;
// Ponteiro para ponteiro (matriz de duas posicoes)
int **matrizBidimensional;
int x, y;
// Alocacao de uma dimensao
matrizUnidimensional = (int *) malloc(5 * sizeof(int));
matrizUnidimensional[0] = 15;
matrizUnidimensional[1] = 25;
matrizUnidimensional[2] = 35;
matrizUnidimensional[3] = 45;
matrizUnidimensional[4] = 55;
for(x=0; x<5; x++)
{
printf("n Matriz unidimensional [%d] = %d", x, matrizUnidimensional[x]);
}
// Liberacao de uma dimensao
free(matrizUnidimensional);
// Alocacao de duas dimensoes (passo 1/2: dimensao 1)
matrizBidimensional = (int **) malloc(5 * sizeof(int *));
// Alocacao de duas dimensoes (passo 2/2: dimensao 2 para cada item da dimensao 1)
matrizBidimensional[0] = (int *) malloc(2 * sizeof(int));
matrizBidimensional[1] = (int *) malloc(2 * sizeof(int));
matrizBidimensional[2] = (int *) malloc(2 * sizeof(int));
matrizBidimensional[3] = (int *) malloc(2 * sizeof(int));
matrizBidimensional[4] = (int *) malloc(2 * sizeof(int));
matrizBidimensional[0][0] = 1;
matrizBidimensional[0][1] = 2;
matrizBidimensional[1][0] = 3;
matrizBidimensional[1][1] = 4;
matrizBidimensional[2][0] = 5;
matrizBidimensional[2][1] = 6;
matrizBidimensional[3][0] = 7;
matrizBidimensional[3][1] = 8;
matrizBidimensional[4][0] = 9;
matrizBidimensional[4][1] = 10;
for(x=0; x<5; x++)
{
for(y=0; y<2; y++)
{
printf("n Matriz bidimensional [%d][%d]: %d", x, y, matrizBidimensional[x][y]);
}
}
// Liberando matriz de duas dimensoes: primeiro libera todas as posicoes da segunda dimensao
for(x=0; x<5; x++)
{
free(matrizBidimensional[x]);
}
// Por ultimo, libera a primeira dimensao
free(matrizBidimensional);
scanf("%c", &c);
return 0;
}
Strings
Conjunto de caracteres (char)
Armazenados em formato de matrizes unidimensionais (arrays, vetores)
Toda string encerra com um valor nulo (0) em seu final, incluído automaticamente pelo compilador
Seu tamanho deve ser declarado levando em conta o caractere de encerramento
Declarando Strings
Especificando o tamanho
Não especificando o tamanho
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
char minhaStr[4] = "ola";
printf("%s", minhaStr); // ola
char minhaStr[3] = "ola";
printf("%s", minhaStr); // olaa#(##
char minhaStr[4] = {'o', 'l', 'a', '0'};
printf("%s", minhaStr); // ola
char minhaStr[] = "ola";
printf("%s", minhaStr); // ola
char minhaStr[]; // Erro
minhaStr = "ola";
printf("%s", minhaStr);
char *minhaStr;
minhaStr = "ola";
printf("%s", minhaStr); // ola
Interagindo com o usuário
Biblioteca stdio.h
Capturando valores
– gets
– gets vs. scanf
Gets realiza tratamento de nova linha (remove n), mas é perigoso de ser utilizado, pois permite que uma string de muitas posições seja forçada em uma variável menor. Deve ser evitado. Utilizar fgets(variável destino, limite de posições, local de origem da leitura/ stdin). Requer atenção com a limpeza do buffer de entrada.
· Limpeza do buffer
Strtok(variável destino, caractere a ser apagado);
strtok (x, “/n”); //caractere de escape que pode ficar no buffer
Tratar exceções no tamanho da entrada - limpar o buffer
1
2
3
if (strlen(x) == 6-1) { //tamanho da variável -1
while ((ch = getchar()) != 'n' && ch != EOF); //End Of File
}
if (strlen(x) == 6-1) { //tamanho da variável -1 while ((ch = getchar()) != ‘n’ && ch != EOF); //End Of File }
- Imprimindo valores
– puts
Exibe string na tela, preparado para concatenar strings com quebras de linha
– puts vs. printf
Printf não quebra linhas automaticamente.
-sprintf associa e concatena mensagens a uma variável, sem imprimir.
sprintf(variável de destino, “mensagem impressa %s”, variavel substituida no texto);
puts(variável de destino);
Matriz de strings
Matriz dentro de matriz
Matriz bidimensional
Funções interessantes
- Biblioteca string.h
Em algumas funções não é necessário utilizar o caractere & para indicar endereço de ponteiros, pois em C a passagem de parâmetros nesses casos já é feita por referência.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//– strcpy: Copia uma string em outra; Altera o valor de uma string.
(char *) strcpy(char *destino, char *origem ou nova string);
//– strcat: Concatena duas strings; Concatena a segunda string na primeira.
(char *) strcat(char *destino, const char *conteudo);
//– strlen: Retorna o tamanho da string, sem considerar o caractere de finalização.
(int) strlen(char *string);
//– strcmp: Compara se duas strings são iguais; Operador == não funciona.
(short) strcmp(char *string1, char *string2);
//– strchr: Retorna o ponteiro para a primeira ocorrência de um caractere; substring
(char *) strchr(char *string, char caractere);
//– strrchr: Retorna o ponteiro para a última ocorrência de um caractere; substring
(char *) strrchr(char *string, char caractere);
//– strstr: Retorna o ponteiro para a primeira ocorrência de uma string
(char *) strstr(char *string, char *substring);
Tabela ASCII
- Utilizando caracteres ASCII
1
2
char caractereAscii = 65;
printf("%c", caractereAscii); // A
Códigos de escape
- Caracteres especiais utilizados em strings
Ocupam apenas um slot na string
Código | Descrição |
---|---|
a | Beep (som) |
b | Backspace (BS) |
f | Alimentação de formulário (FF) |
n | Nova linha (LF) |
r | Retorno (CR) |
t | Tabulação horizontal |
v | Tabulação vertical |
’ | Aspas simples |
” | Aspas duplas |
0 | Nulo |
\ | Barra invertida |
Conversão entre textos e números
- Funções para conversão
– Biblioteca stdlib.h
– atoi: string para inteiro
– atof: string para ponto flutuante
Funções
- O que são
– Blocos de códigos independentes
– Permitem organizar e centralizar rotinas
- Sintaxe
– Cabeçalho
1
tipo_de_retorno nome(parâmetros);
– Definição
1
2
3
tipo_de_retorno nome(parâmetros) {
// Bloco de código
}
- Escopo local
– Variáveis locais são excluídas no final do bloco
– Sem acesso a variáveis locais de outras funções
– Acesso livre a variáveis globais
– Variáveis do tipo static são compartilhadas entre diferentes chamadas da mesma função
Parâmetros e retorno
- Parâmetros
– Variáveis locais
– Excluídas no final do bloco
- Retorno
– Tipos de retornos
Tipos de dados disponíveis no C
Ponteiro
Nada (void)
– Instrução return
Chamadas
- Por valor
– Uma cópia do valor é criada na memória
– Alterações são perdidas no final do bloco
- Por referência
– Utilização de ponteiros
– Uma cópia do endereço de memória é criado
– Alterações são realizadas no mesmo endereço de memória informado, sendo mantidas
– Exemplo: scanf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Por valor
void soma(int p1)
{
p1 = p1 + p1;
}
// Por referência
void somaPonteiro(int *p1)
{
*p1 = *p1 + *p1;
}
int x = 4;
soma(x);
printf("%d", x); // 4
somaPonteiro(&x);
printf("%d", x); // 8
O método main
- Parâmetros
– argc: número de parâmetros, tipo int
– argv: parâmetros, array de string
– Parâmetro ZERO é sempre o nome/caminho do programa
· A definição de outros parâmetros na chamada do programa pode ser utilizada
· Como esses parâmetros são opcionais, é importante tratar as exceções.
– Padrão ANSI
- Retorno
– Pelo padrão ANSI deve retornar int
1
2
3
4
5
int main (int argc, char *argv[])
{
// Código
return 0;
}
Interagindo com arrays / matrizes
- Passando como parâmetro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void imprima(int *matriz)
{
int x;
for(x=0; x<4; x++)
{
printf("%d ", matriz[x]);
}
}
void imprima(int matriz[4])
{
int x;
for(x=0; x<4; x++)
{
printf("%d ", matriz[x]);
}
}
void imprima(int matriz[])
{
int x;
for(x=0; x<4; x++)
{
printf("%d ", matriz[x]);
}
}
Retornando um array / matriz
- Envia-se um parâmetro adicional
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void imprima(int *matriz)
{
int x;
for(x=0; x<4; x++)
{
printf("%d ", matriz[x]);
}
}
void inverte(int *original, int *invertido)
{
int x;
for(x=0; x<4; x++)
{
invertido[4-1-x] = original[x];
}
}
Parâmetro desconhecido
Quando o parâmetro pode ser de diferentes tipos de dados dependendo da ocasião
Parâmetro do tipo void*
Pode ser utilizado como parâmetro da função e como seu retorno
1
2
3
4
5
6
7
void grave(void* buffer)
{
FILE* arquivo;
arquivo = fopen("dados.txt", "wb");
fwrite(&buffer, sizeof(buffer), 1, arquivo);
fclose(arquivo);
}
Parâmetros variáveis
Funções com número e tipos de parâmetros indefinidos
Exemplo: printf(“%d %d %d”, 35, 42, 66);
Instrução reticências (…)
Pelo menos um parâmetro deve ser fixo
Biblioteca stdarg.h
– va_list: matriz de argumentos
– va_start(matriz, primeiro parâmetro): inicializa a matriz
– va_arg(matriz, tipo de dado): acessa a matriz
– va_end(matriz): encerra o uso
Ponteiro para função
- Cada função possui seu ponto de entrada
-Utilizado para facilitar alternância entre bibliotecas de SO diferentes - basta alterar o ponteiro que aponta para a função, sem a necessidade de alterar todas as ocorrências da função no código.
– Endereço de memória no código-objeto
- Sabendo o ponto de entrada, pode-se apontar para ele
1
2
3
4
5
int (*pf) (const char *);
puts("texto");
pf = puts;
pf("texto");
00003443("texto");
Recursão
Função que invoca ela mesma
Looping infinito
Exemplo: cálculo de fatorial de um número
1
2
3
4
5
6
7
8
9
10
11
12
13
int fatorial(int n)
{
if(n != 1)
{
return n * fatorial(n-1);
}
else
{
return 1;
}
}
int x = fatorial(4);
printf("%d", x); // 24
Exemplo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "stdio.h"
#include "stdarg.h"
int somaValores(int valorA, int valorB)
{
int resultado;
resultado = valorA + valorB;
return resultado;
// return valorA + valorB;
}
void strBomdia(char *str, char *nome)
{
sprintf(str, "Bom dia sr(a) %s", nome);
}
//void imprime(int *matriz)
//void imprime(int matriz[50])
void imprime(int matriz[], int tamanho)
{
int x;
printf("n ");
for(x=0; x<tamanho; x++)
{
printf("%d ", matriz[x]);
}
}
int somaParametrosVariaveis(int p1, ...)
{
int total = 0;
int contadorDeParametros = 0;
va_list args;
int temp;
va_start(args, numeroDeParametros);
while (contadorDeParametros++ < numeroDeParametros)
{
temp = va_arg(args, int);
total += temp;
}
return total;
}
int somaRecursao(int v)
{
if(v == 1)
{
return 1;
}
else
{
return v + somaRecursao(v-1);
}
}
int main(int argc, char *argv[])
{
char *c;
int i;
char buffer[50];
int valores[10] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int (*ponteiroFuncao) (int a, ...);
// Funcao simples
i = somaValores(20, 30);
printf("n Resultado: %d", i);
// Funcao por referencia
strBomdia(buffer, "Andre");
printf("n %s", buffer);
// Argumentos do metodo main
for(i=0; i<argc; i++)
{
printf("n Parametro %d: %s", i, argv[i]);
}
if(argc > 1)
{
strBomdia(buffer, argv[1]);
printf("n %s", buffer);
}
// Funcoes com matrizes
imprime(valores, 10);
// Parametros variaveis
i = somaParametrosVariaveis(3, 3, 4, 5);
printf("n A soma e: %d", i);
i = somaParametrosVariaveis(4, 3, 4, 5, 6);
printf("n A soma e: %d", i);
i = somaParametrosVariaveis(5, 3, 4, 5, 6, 7);
printf("n A soma e: %d", i);
// Ponteiro de funcao
ponteiroFuncao = somaParametrosVariaveis;
i = ponteiroFuncao(3, 4, 2, 3);
printf("n A soma e: %d", i);
// Recursividade
i = somaRecursao(5);
printf("n A soma recursao de 5 e: %d", i);
scanf("%c", &c);
return 0;
}
Estruturas e uniões
Estrutura (struct)
Conjunto de variáveis, de mesmos ou diferentes tipos
Dados variados, porém relacionados entre si com um mesmo propósito
Estrutura vs. OO
Não comportam métodos
- Instrução struct
1
2
3
4
5
6
Sintaxe
struct nome {
tipo nome;
...
tipo nome;
} [variáveis];
1
2
3
4
5
6
//Exemplo
struct pessoa {
char nome[30];
unsigned int idade;
double peso;
} p1;
- Tipo de dado: struct nome_struct
struct pessoa p2, p3;
- Acesso (.)
p1.idade = 30;
Matrizes de estruturas
- struct com [ ]
1
2
3
4
5
6
7
8
struct pessoa {
char nome[30];
unsigned int idade;
double peso;
} turma[5];
strcpy(turma[0].nome, "Andre");
turma[0].idade = 30;
turma[0].peso = 68.5;
Estruturas em funções
Utilizar como um tipo de dado simples
Declarar o parâmetro da função como o tipo de dado:
struct nome_struct nome_parâmetro
Ponteiros de estruturas
- Similar aos demais usos de ponteiro
struct pessoa p1;
struct pessoa *p2;
p2 = &p1;
- Acesso via operador seta (->)
printf(“Nome: %s”, p2->nome);
Estruturas dentro de estruturas
Estrutura comporta qualquer tipo de dado
Se uma estrutura é um tipo de dado, então comporta uma estrutura
Comporta ponteiros, matrizes
1
2
3
4
5
6
7
8
struct geral {
int x;
int *y;
int z[15];
struct pessoa p1;
struct pessoa galera[30];
struct pessoa *p2;
};
Uniões
Instrução union
Compartilhamento de memória entre variáveis
Tipos definidos pelo usuário
Instrução typedef
Permite criar apelidos para tipos de dados
Arquivos
Arquivos e streams
- O que são streams?
– Sequência de informações
– YouTube: streaming de áudio e vídeo
– Streams binárias
- Bytes
– Streams de texto
Caracteres
O que são arquivos?
– Destino das streams
– Exemplos: arquivo, navegador, impressora
– Palavra chave FILE
Mecanismo de ponteiro
Posicionamento de ponteiro
Instrução fseek: posiciona o ponteiro
– Biblioteca stdio.h
– SEEK_SET: início do arquivo
– SEEK_CUR: posição atual
– SEEK_END: final do arquivo
– EOF: atingiu o final do arquivo (End Of File)
Modos de interação
- Modos para arquivos texto
1
2
3
4
5
6
r Somente para leitura, colocando o ponteiro no começo do arquivo.
r+ Leitura e escrita, colocando o ponteiro no começo do arquivo.
w Somente para escrita, colocando o ponteiro no começo do arquivo, criando o arquivo caso ele não exista.
w+ Leitura e escrita, colocando o ponteiro no começo do arquivo, criando o arquivo caso ele não exista.
a Somente para escrita, colocando o ponteiro do arquivo no final deste, criando o arquivo caso ele não exista.
a+ Leitura e escrita, colocando o ponteiro do arquivo no final deste, criando o arquivo caso o mesmo não exista.
- Modos para arquivos binários
1
2
3
4
5
6
rb Somente para leitura, colocando o ponteiro no começo do arquivo.
r+b Leitura e escrita, colocando o ponteiro no começo do arquivo.
wb Somente para escrita, colocando o ponteiro no começo do arquivo, criando o arquivo caso ele não exista.
w+b Leitura e escrita, colocando o ponteiro no começo do arquivo, criando o arquivo caso ele não exista.
ab Somente para escrita, colocando o ponteiro do arquivo no final deste, criando o arquivo caso ele não exista.
a+b Leitura e escrita, colocando o ponteiro do arquivo no final deste, criando o arquivo caso o mesmo não exista.
Permissão de acesso
- Exemplos de problemas comuns
– Criar arquivo sem acesso de gravação
– Realizar leitura sem acesso no arquivo
– Realizar leitura sem acesso no diretório
- Permissões de acesso
– Acesso r/w nos diretórios em questão
– Acesso r/w nos arquivos em questão
– Geralmente problemas são falta de permissões
Principais comandos
Biblioteca stdio.h
Abertura e fechamento
– fopen(nome_arquivo, modo_abertura)
– fclose(FILE*)
- Escrita e leitura de caracteres
– fputc(caractere, FILE*)
– fgetc(FILE*)
- Escrita e leitura de strings
– fputs(string, FILE*)
– fgets(string, tamanho, FILE*)
- Escrita e leitura maiores que um byte
– fwrite(buffer, bytes, contador, FILE)
– fread(buffer, bytes, contador, FILE)
- Buffer
– Região temporária de dados
– Geralmente de tamanho pequeno
– Geralmente uma matriz unidimensional
– Exemplo: char meuBuffer[10]
- Verificação se chegou ao final do arquivo
– feof(FILE*)
- Verificação de erro
– ferror(FILE*)
- Descarregamento do stream no arquivo
– fflush(FILE*)
- Retroceder o indicador de posição ao início
– rewind(FILE*)
- Deletar o arquivo
– remove(nome do arquivo)
Ordenações e buscas
Ordenações
- Quando utilizar
– Buscas com frequência
Produzem melhores resultados se utilizados com mecanismos de buscas inteligentes
Tipos de ordenações
– Bubble sort
– Shell sort
– Quick sort
Ordenações mais conhecidas
- Bubble sort
– Ordenação como bolhas de sabão
– Não eficiente: trocas em excesso
- Shell sort
– Ordenação em nível: 3 em 3, 2 em 2, 1 em 1
– Eficiente: relativamente rápida e otimizada
- Quick sort
– Ordenação em blocos
– Eficiente: considerada a melhor ordenação
Buscas
Utilizadas em parceria com ordenação
Diferentes tipos de busca
– Busca sequencial
Posição por posição (força bruta)
Similar a busca sequencial em dados não ordenados
– Busca binária
Divide ao meio e decide para que lado prosseguir
Dados devem estar ordenados
Número de operações diminui
Estruturas de dados
- Principais estruturas de dados
– Organizados em arrays
Fila
Fila circular
Pilha
– Organizados por ponteiros
Lista encadeada
Lista duplamente encadeada
Árvore binária
Fila
Primeiro que entra é o primeiro a ser atendido
FIFO: First In First Out
Operações
– Enqueue: insere um elemento na fila
– Dequeue: remove um elemento da fila
- Exemplo: fila de banco, fila de pagar conta
Fila circular
Mesma lógica da fila tradicional (FIFO)
Reaproveitamento de posições
Utilização:
– Fila tradicional: filas de tamanho previsto
– Fica circular: filas de tamanho imprevisível
Pilha
Último que entra é o primeiro a ser atendido
LIFO: Last In First Out
Operações
– Push: insere um elemento
– Pop: remove um elemento
- Exemplo: pilha de chamadas de métodos
Lista encadeada
Acesso randômico na memória
Não destrói os elementos removidos
Cada elemento aponta para um próximo
Lista duplamente encadeada
Similar a uma lista encadeada tradicional
Adiciona um ponteiro para o anterior
Árvore binária
Cada elemento aponta para dois outros, que não podem apontar para ele novamente
Cada elemento é um nó
– Raíz
– Nó terminal