Hacks e Extras
Comandos do pré-processador
O pré-processador é a ferramenta que prepara o código para a compilação, por isso existem ele tem seus próprios comandos, e caso você queira curiar a versão preprocessada de um arquivo em C use o comando gcc -E <arquivo> > <saida.c>
Basicamente todos os comandos do pré-processador começam com #
, e um desses comandos é o próprio #include
, que usamos para importar nossas bibliotecas, que além de importar bibliotecas padrões, você pode importar seus próprios arquivos.
#include "minhas_funcoes.c"
#include "/home/robocopgay/biblioteca.c"
Quando você usa as aspas duplas (
"
) você pode passar o caminho para a sua biblioteca (caso ela esteja no mesmo diretório coloque apenas o nome do arquivo)
Outra diretris interessante é o #declare
, que serve para criar constantes e macros:
#define PI 3.14
#define soma (n, n2) n + n2
#define add_item ( array, item )\
array = realloc( sizeof (array) + sizeof (item) );
Note que na ultima linha da ultima macro foi usado o
\
para indicar que a próxima linha pertence a ela.
A vantagem aqui é que se precisa de uma constante, é mais útil usar o #define
que criar uma variável, pois a variável tem que ocupar um espaço na memória, enquanto o pre-processador apenas substitue o lugar onde a macro ou constante é chamada pelo seu conteúdo.
E a diretris #undef
“desdefine” uma macro ou constante
#define max 10
int i = max*3;
#undef max
define max 30
E existe o #if
, #else
, #elif
e o #endif
, usados para condicional
#define MIN_SIZE 2
#if defined(MAX_SIZE) // if -> se
#define tamanho MAX_SIZE
#elif MIN_SIZE > 2 // else if -> senão se
#define tamanho 2
#else // else -> senão
#define tamanho MIN_SIZE+1
#endif // end -> fim
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char ** argv){
printf("%i", tamanho);
return 0;
}
Além desses existem os atalhos específicos para o #if defined(<macro>)
e o #if !defined(<macro>)
:
#define MAX_SIZE 35
#ifdef MAX_SIZE
#define TAMANHO_MAXIMO MAX_SIZE
#endif
#ifndef MIN_SIZE
#define TAMANHO_MINIMO 0
#endif
Outra coisa interessantíssima é criar strings a partir de código, “Ué? não entendi...”, muito simples... Quando usamos o operador #
dentro de uma macro ele transforma o comando em string
#define to_str(texto) #texto
puts( to_str(Hello mundo!!) );
Saída:
Hello mundo!!
Ou se quiser juntar duas informações use o ##
#define to_str(texto) #texto
#define str_function_template(func) str##func
int l = str_function_template(len)("abacate");
printf("\"%s\" tem %i letras.\n", "abacate", l);
Saída:
"abacate" tem 7 letras.
Chegou a hora de praticar de novo!
Desafio 5
Faça uma calculadora onde o usuário digite dois números (reais) e no final ele pergunte qual operação matemática fazer ( +, -, / ou * ) e no fim ele pergunte se a pessoa deseja calcular de novo.
Saída:
Digite 2 números: 2 3
Você quer somar (+), subtrair (-), multiplicar (*) ou dividir (/)?
+
2 + 3 = 5
Deseja calcular de novo? [S/n] n
Resposta
Primeiramente iremos declarar as variáveis necessárias:
int n1, n2; // números que iremos ler
char operacao; // operação
int res; // resposta
E iremos ler os dados necessários:
printf("Digite 2 números: ");
scanf("%i %i", &n1, &n2);
printf("Você quer somar (+), subtrair (-), multiplicar (*) ou dividir (/)? ");
operacao = getchar();
Agora nós vamos efetuar os devidos cálculos:
if (operacao == '+')
res = n1 + n2;
else if (operacao == '-')
res = n1 - n2;
else if (operação == '/')
res = n1 / n2;
else res = n1 * n2;
E exibimos o resultado:
printf("\n%i %c %i = %i\n", n1, operacao, n2, res);
E se você é atento notou que faltou perguntar se a pessoa que calcular de novo, mas antes de fazer esta pergunta nó temos que colocar o código que queremos repetir dentro de uma estrutura de repetição, mas não coloque a parte da declaração de variáveis:
do {
printf("Digite 2 números: ");
scanf("%i %i", &n1, &n2);
printf("Você quer somar (+), subtrair (-), multiplicar (*) ou dividir (/)? ");
operacao = getchar();
if (operacao == '+')
res = n1 + n2;
else if (operacao == '-')
res = n1 - n2;
else if (operação == '/')
res = n1 / n2;
else res = n1 * n2;
printf("\n%i %c %i = %i\n", n1, operacao, n2, res);
printf("Deseja calcular de novo? [S/n] ");
if ( getchar() == 'n' )
break;
} while ( 1 );
Eu escolhi o
do..while
porque o código sempre vai ser executado pelo menos uma vez.
E o código final ficou assim:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int n1, n2; // números que iremos ler
char operacao; // operação
int res; // resposta
do {
// lendo dados
printf("Digite 2 números: ");
scanf("%i %i", &n1, &n2);
printf("Você quer somar (+), subtrair (-), multiplicar (*) ou dividir (/)? ");
scanf("%c %c", &operacao, &operacao);
// processando dados
if (operacao == '+')
res = n1 + n2;
else if (operacao == '-')
res = n1 - n2;
else if (operacao == '/')
res = n1 / n2;
else res = n1 * n2;
// exibindo dados
printf("\n%i %c %i = %i\n", n1, operacao, n2, res);
// reiniciando ou interrompendo programa
printf("Deseja calcular de novo? [S/n] ");
getchar();
if ( getchar() == 'n' )
break;
} while ( 1 );
return 0;
}
Desafio 6
Faça um programa que leia 5 números e retorne a soma entre os 3 menores divididos pelo maior.
Saída:
digite 5 numeros: 10 36 88 89 43
(10+36+43)/89 = 1.0
Resposta
Primeiramente precisamos ler os dados
int n[5];
printf("digite 5 numeros: ");
scanf("%i%i%i%i%i", &n[0], &n[1], &n[2], &n[3], &n[4]);
Agora vamos pegar o maior número digitado (já que é mais simples que pegar os 3 menores).
int maior = 0;
for (int i=0; i<5; i++){
maior = (n[i] > n[maior])?i:maior;
}
Agora a parte mais complidada, existem duas formas de fazer isso, a primeira é comparar manualmente e atribuir a variáveis.
int menor1 = maior, menor2 = maior, menor3 = maior;
maior = n[maior];
temos que dar o
maior
como valor, porque para comparar temos que ter certeza de que pode existir um valor menor, caso atribuamos o0
a variável sempre vai ter o menor valor
for (int i=0; i++; i<5){
if (n[i] < n[menor1])
menor1 = n[i];
maior = n[maior]
}
for (int i=0; i++; i<5){
if (n[i] < n[menor2] && i != menor1)
menor1 = n[i];
}
for (int i=0; i++; i<5){
if (n[i] < n[menor3] && i != menor2 && i != menor1)
menor1 = n[i];
}
Essa forma com certeza funciona, mas existe uma forma mais inteligente de fazer:
maior = n[maior];
int menores [] = {maior, maior, maior};
for (int j=0; j<3; j++){
for (int i=0; i<5; i++){
if (n[i]<menores[j]){
menores[j] = n[i];
n[i] = maior;
}
}
}
E por fim vamos exibir os resultados:
printf("(%i+%i+%i)/%i = %1.1f\n",
menores[0],
menores[1],
menores[2],
maior,
(float)(menores[0]+menores[1]+menores[2])/maior
);
Código final:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// criando e lendo dados
int n[5];
printf("digite 5 numeros: ");
scanf("%i%i%i%i%i", &n[0], &n[1], &n[2], &n[3], &n[4]);
// pegando o maior valor
int maior = 0;
for (int i=0; i<5; i++)
maior = (n[i] > n[maior])?i:maior;
// pegando os menores valores
maior = n[maior];
int menores [] = {maior, maior, maior};
for (int j=0; j<3; j++){
for (int i=0; i<5; i++){
// caso o numero atual for menor que o menor
if (n[i]<menores[j]){
menores[j] = n[i];
/* o numero atual é o menor de todos
* e por isso tem que deixar de ser,
* ou não haverá como pegar o segundo
* menor e muito menos o terceiro já
* que ele seria o menor.
*/
n[i] = maior;
}
}
}
printf("(%i+%i+%i)/%i = %1.1f\n",
menores[0],
menores[1],
menores[2],
maior,
(float)(menores[0]+menores[1]+menores[2])/maior
);
return 0;
}
Desafio 7
Faça um algoritmo que leia números inteiros indefinidamente e só pare quando o valor lido for maior que 1000, nos resultados devem ser informados o maior, o menor, e a media entre eles, além de dizer quais foram repetidos e se repetidos o número de vezes que foi repetido, além de todos os números primos da lista.
digitte números... (para parar digite um numero >= 1000)
9
8
4
2
9
8
11
390
23
42
13
1000