Home Anotações sobre C
Post
Cancelar

Anotações sobre C

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

TipoIntervaloBits (padrão ANSI)
char / signed char-127 a 1278
unsigned char0 a 2558
int / signed int / short int / signed short int-32.767 a 32.76716
unsigned int0 a 65.53516
long int / signed long int-2.147.483.647 a 2.147.483.64732
unsigned long int0 a 4.294.967.29532
float6 casas decimais32
double10 casas decimais64
long double10 casas decimais80

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

OperadorOperação 
+soma 
++soma 1x++ 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 1X– 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

OperadorOperaçã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ímboloDescrição
%cCaractere
%d, %iNúmero inteiro (com sinal)
%uNúmero inteiro (sem sinal)
%e, %ENotação científica
%fPonto flutuante
%lfPonto flutuante longo
%oOctal
%sString
%x, %XHexadecimal
%pPonteiro
%%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ímboloDescrição
%aDia da semana abreviado
%ADia da semana
%bMês abreviado
%BMês
%cData e hora completa
%dDia do mês (1-31)
%HHora (24)
%lHora (12)
%jDia do ano (1-366)
%mMês (1-12)
%MMinuto (0-59)
%pAM, PM
%SSegundos (0-59)
%UNúmero da semana (a partir de domingo)
%wDia da semana (0-6) (a partir de domingo)
%WNúmero da semana (a partir de segunda)
%xData completa
%XHorário completo
%yAno (yy)
%YAno (yyyy)
%ZFuso 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

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ódigoDescrição
aBeep (som)
bBackspace (BS)
fAlimentação de formulário (FF)
nNova linha (LF)
rRetorno (CR)
tTabulação horizontal
vTabulação vertical
Aspas simples
Aspas duplas
0Nulo
\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

Esta postagem está licenciada sob CC BY 4.0 pelo autor.