Aprenda C

  • Página Inicial
  • Contato!
  • Tudo sobre C Parte 1!
  • Tudo sobre C Parte 2!
  • Tudo sobre C Parte 3!
  • Tudo sobre C Parte 4!
  • Tudo sobre C Parte 5!
  • Tudo sobre C Parte 6!
  • Tudo sobre C Parte 7!
  • Tudo sobre C Parte 8!
  • Tudo sobre C Parte 9!
  • Tudo sobre C Parte 7

    Funções Recursivas

    Existem determinadas situações que uma função necessita chamar ela mesma novamente. É uma coisa que deve ser feita com cuidado na programação, mas que também é muito útil em determinadas situações.

    Veja no exemplo uma função recursiva que faz a somatória dos antecessores de um número, inteiro positivo, informado pelo usuário, ou seja, se o usuário digitar 5, o programa deverá retornar o resultado da soma 5 + 4 + 3 + 2 + 1 + 0. A função deverá somar até o valor zero, portanto esse será o critério de parada:

    
    int somar(int valor);
    
    int main() {
        setlocale(LC_ALL, "portuguese");
        
        int num, resultado;
    
        printf("Digite um número inteiro positivo: ");
        scanf("%d", &num);
    
        resultado = somar(num); // Primeira chamada da função
    
        printf("\nResultado: %d.\n", resultado);
    
        return 0;
    }
    
    int somar(int valor) {
        if(valor == 0) {
            return valor;
        }
        else {
            return valor + somar(valor - 1);
        }
    }
    
    

    Invertendo Valores de Variáveis

    Em alguns casos, principalmente em jogos, é necessário inverter a direção ou valores de variáveis. Para tanto, existem os valores de inversão de variáveis. No caso, seria deixar o valor negativo se for positivo e vice-versa.

    Veja um exemplo simples disso:

    
    int num = 10;
    
    printf("%d\n", num);
        
    num = num * -1;
        
    printf("%d\n", num);
    
    

    Você também pode colocar o sinal negativo diretamente ao lado da variável à ser exibida, assim:

    
    int num = 10;
        
    printf("%d\n", -num);
    
    

    PS: Esse negativo não muda o valor da variável, só na exibição nesse printf ele faz a inversão.

    Para gravar o novo valor da variável, faça uma nova atribuição.

    Veja um exemplo:

    
    int num = 10;
    
    printf("%d\n", num); // Valor original.
    
    num = -num;
    
    printf("%d\n", -num); // Retornará positivo, - com - retorna + e a variável foi alterada antes.
    
    printf("%d\n", num); // Retornará negativo, já que a variável foi alterada.
    
    

    PS: Só pra lembrar, + com + retornará positivo, e - com - retorna positivo. Apenas quando usarmos + e - que retornará negativo. Regra simples de matemática, iguais retornam positivo e diferentes retornam negativo.

    Estrutura - Definição e Atribuição

    As estruturas são uma espécie de agrupamento de diversas variáveis distintas sob um nome comum. É um tipo de dados que o próprio programador define para usar no seu programa, existem outros tipos de dados que o usuário pode definir, mas aqui só falaremos de estruturas. As estruturas são usadas para criar um tipo de dado específico, composto ou complexo para usar no programa.

    Para utilizarmos uma estrutura, usamos a palavra-chave struct, dessa forma.

    
    #include <stdio.h>
    #include <stdlib.h>
    
    int main() {
        struct endereco {
            char rua[50];
            char numero[5];
            char cep[8];
            char bairro[30];
        };
    
        return 0;
    }
    
    

    No caso acima, as variáveis são chamadas de membros de estrutura. Podemos ter vários tipos de dados numa mesma estrutura.

    Veja outro exemplo, com vários tipos de dados:

    
    #include <stdio.h>
    #include <stdlib.h>
    
    int main() {
        struct livro {
            char nome[30];
            char autor[50];
            int paginas;
            float preco;
        };
    
        return 0;
    }
    
    

    Podemos usar o struct fora do método main, e chamando o mesmo dentro do main:

    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <locale.h>
    
    struct livro {
        char nome[30];
        char autor[50];
        int paginas;
        float preco;
    };
    
    struct livro liv1; // O primeiro nome é o "tipo" e o segundo nome é a a variável.
    
    int main() {
        setlocale(LC_ALL, "portuguese");
    
        printf("Cadastrando livro!\n");
        printf("\nDigite o nome do livro: ");
        fgets(liv1.nome, 30, stdin);
        printf("Digite o nome do autor: ");
        fgets(liv1.autor, 50, stdin);
        printf("Digite o número de páginas do livro: ");
        scanf("%d", &liv1.paginas);
        printf("Digite o preço do livro: ");
        scanf("%f", &liv1.preco);
    
    
        // Isso é pra remover a quebra de linha:
        size_t len;
        len = strlen(liv1.nome); // Inclua string.h
    
        if(liv1.nome[len - 1] == '\n') liv1.nome[--len] = 0;
    
        len = strlen(liv1.autor);
    
        if(liv1.autor[len - 1] == '\n') liv1.autor[--len] = 0;
    
        printf("\nO livro %s possuí %d páginas e custa R$%4.2f.\n", liv1.nome, liv1.paginas, liv1.preco);
    
        return 0;
    }
    
    

    PS: Note que usamos o fgets para pegar dados de livro, mas só funciona pra char, mas nada impede de usarmos também scanf para isso, desde que indiquemos corretamente.

    Podemos declarar o nome da variável diretamente no struct também, é recomendado quando usaremos apenas uma variável com esse struct, veja um exemplo:

    
    struct livro {
        char nome[30];
        char autor[50];
        int paginas;
        float preco;
    } liv1;
    
    

    PS: Pode colocar mais de uma variável declarada dessa forma, separando por vírgulas.

    Também podemos atribuir os dados de uma estrutura para outra, dessa forma:

    
    liv2 = liv1;
    
    

    PS: Não são permitidos métodos em estruturas em C.

    Caso as estruturas sejam ponteiros, use a seta (->) ao invés do ponto. Compare os dois exemplos abaixo.

    Exemplo sem ponteiros:

    
    #include <stdio.h>
    #include <stdlib.h>
    #include <locale.h>
    
    struct livro {
        char *nome; // Como atribuímos diretamente, não podemos usar arrays e sim ponteiros pra char
        char *autor; // Idem
        int paginas;
        float preco;
    } liv1; // Atribuição direta a uma variável
    
    int main() {
        setlocale(LC_ALL, "portuguese");
        struct livro liv2; // Nova variável de estrutura
    
        liv2.nome = "Tudo sobre Linguagem C";
        liv2.autor = "Fulano da Silva";
        liv2.paginas = 400;
        liv2.preco = 49.99;
    
        printf("O livro %s possuí %d páginas e custa R$%4.2f.", liv2.nome, liv2.paginas, liv2.preco);
    
        return 0;
    }
    
    

    Exemplo com ponteiros:

    
    #include <stdio.h>
    #include <stdlib.h>
    #include <locale.h>
    
    struct livro {
        char *nome; // Como atribuímos diretamente, não podemos usar arrays e sim ponteiros pra char
        char *autor; // Idem
        int paginas;
        float preco;
    } liv1; // Atribuição direta a uma variável
    
    int main() {
        setlocale(LC_ALL, "portuguese");
        struct livro *liv2 = &liv1; // Atribuindo ponteiro a endereço da outra variável
    
        liv2->nome = "Tudo sobre Linguagem C";
        liv2->autor = "Fulano da Silva";
        liv2->paginas = 400;
        liv2->preco = 49.99;
    
        printf("O livro %s possuí %d páginas e custa R$%4.2f.", liv2->nome, liv2->paginas, liv2->preco);
    
        free(liv2); // Excluindo ponteiro pra liberar memória
    
        return 0;
    }
    
    

    Unions

    As unions se declaram de forma parecida com as structs, mas ela ocupa menos espaço na memória.

    Veja um exemplo de uso:

    
    union exemplo {
        int inteiro;
        char caractere;
    };
    
    

    As variáveis do unions ocupam o mesmo endereço de memória.

    Vamos comparar uma union e uma struct:

    
    union estrutura01 {
        int inteiro;
        char caractere;
        float decimal;
    };
    
    struct estrutura02 {
        int inteiro2;
        char caractere2;
        float decimal2;
    };
    
    

    E na função principal, faça isso:

    
    printf("União: %d\n", sizeof(union estrutura01));
    printf("Estrutura: %d\n", sizeof(struct estrutura02));
    
    

    Dessa forma vemos a comparação entre o tamanho da union e da struct.

    PS: As unions podem ser utilizadas dentro de structs ou de outras unions também.

    Typedef em C

    Como fizemos com as enuns, podemos criar nossos "tipos" próprio com qualquer tipo primitivo, struct, union, etc.

    Veja um exemplo de uso logo abaixo:

    
    typedef int inteiro;
    typedef float flutuante;
    typedef char caractere;
    typedef char* texto;
    
    int main() {
        setlocale(LC_ALL, "portuguese");
    
        inteiro num = 50;
        flutuante real = 9.85;
        caractere letra = 'A';
        texto frase = "Introdução à Typedef em C";
    
        printf("%d\n", num);
        printf("%.2f\n", real);
        printf("%c\n", letra);
        printf("%s\n", frase);
    
        return 0;
    }
    
    

    Passando Estruturas para Funções

    Podemos também passar estruturas para funções, veja um exemplo abaixo:

    
    struct estrutura {
        int a, b;
        char c;
    };
    
    void imprimir(struct estrutura param);
    
    int main() {
        setlocale(LC_ALL, "portuguese");
    
        struct estrutura arg;
    
        arg.a = 1200;
        arg.b = 500;
        arg.c = 'A';
    
        imprimir(arg);
    
        return 0;
    }
    
    void imprimir(struct estrutura param) {
        printf("%d\n", param.a);
        printf("%d\n", param.b);
        printf("%c\n", param.c);
    }
    
    

    Dessa forma podemos usar métodos para manipular as estruturas.

    Lendo Arquivos em C

    Para lermos arquivos em C, podemos fazer assim:

    
    void lerArquivo();
    
    int main() {
        setlocale(LC_ALL, "portuguese");
    
        lerArquivo();
    
        return 0;
    }
    
    void lerArquivo() {
        FILE *arquivo;
        unsigned char byte;
    
        arquivo = fopen("C:\\Meus Projetos\\C\\NovosConteudos\\teste.txt", "r"); // Para leitura é r
        
        while(fread(&byte, sizeof(byte), 1, arquivo)) {
            printf("%c", byte);
        }
    
        printf("\n");
        fclose(arquivo);
    }
    
    

    PS: A função acima pode ser melhorada usando parâmetros na função lerArquivo e usando o chdir para procurar um arquivo.

    Escrevendo em Arquivos em C

    De forma parecida com a de leitura, para escrever podemos fazer assim:

    
    void escArquivo();
    
    int main() {
        setlocale(LC_ALL, "portuguese");
    
        escArquivo();
    
        return 0;
    }
    
    void escArquivo() {
        FILE *arquivo;
        char *frase;
        frase = (char*)malloc(sizeof(char));
    
        printf("Digite a frase que deseja salvar no arquivo: ");
        fgets(frase, sizeof(frase), stdin);
    
        arquivo = fopen("C:\\Meus Projetos\\C\\NovosConteudos\\teste2.txt", "w"); // Para escrita é w, para adição é a
    
        // Isso é pra remover a quebra de linha:
        size_t len;
        len = strlen(frase); // Inclua string.h
    
        if(frase[len - 1] == '\n') frase[--len] = 0;
    
        fwrite(frase, 1, strlen(frase), arquivo);
    
        fclose(arquivo);
    }
    
    

    Se o arquivo não existir, ele será criado.

    PS: Essa função também pode ser melhorada.