Resultado do concurso do livro uC/OS-III The Real-Time Kernel
- por Sergio Prado
Muito bem pessoal, chegou a hora de conhecer os 3 vencedores da promoção para ganhar o livro de RTOS da Micrium!
Primeiramente, gostaria de agradecer à todos pela participação. Recebi 85 respostas, e deu um pouco de trabalho corrigir tudo! :)
A maioria acertou pelo menos 3 dos 4 desafios, e 38 acertaram tudo. Dentre estas 38 pessoas, fiz o sorteio lá no http://www.random.org/.
Mas antes de dizer quem são os 3 felizardos, que tal darmos uma olhada novamente nos desafios?
DESAFIO 1
O desafio 1 dizia o seguinte:
O código abaixo tem um erro. Qual é este erro?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <stdlib.h> #include <stdio.h> #define SIZE 15 int main() { int *a, i; a = malloc(SIZE*sizeof(int)); for (i = 0; i < SIZE; i++) *(a + i) = i * i; for (i = 0; i < SIZE; i++) printf("%dn", *a++); free(a); return 0; } |
A maioria acertou este desafio. Na linha 10 alocamos uma região de memória e armazenamos o endereço no ponteiro “a”. Na linha 16 este ponteiro é alterado, e quando tentamos desalocá-lo na linha 18 teremos problemas na certa, já que o ponteiro “a” não armazena mais o endereço inicial retornado por malloc(). A solução aqui seria não alterar este ponteiro. O código abaixo resolve o problema:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <stdlib.h> #include <stdio.h> #define SIZE 15 int main() { int *a, i; a = malloc(SIZE*sizeof(int)); for (i = 0; i < SIZE; i++) *(a + i) = i * i; for (i = 0; i < SIZE; i++) printf("%dn", *(a + i)); // CORREÇÃO free(a); return 0; } |
Algumas pessoas apontaram ainda que faltou checar o retorno da função malloc() e fazer o cast para (int *). É verdade! O cast é necessário principalmente se você tentar compilar em C++. Mas não considerei estes fatores para validar a resposta como certa.
DESAFIO 2
O desafio 2 dizia o seguinte:
O código abaixo também tem um erro. Qual?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <stdio.h> int main() { int* ptr1, ptr2; ptr1 = malloc(sizeof(int)); ptr2 = ptr1; *ptr2 = 10; return 0; } |
A maioria também acertou este exercício. Uma coisa que aprendi deste quando comecei a estudar C é que devemos colocar o “*” sempre do lado do nome do ponteiro, e não do lado do tipo. No código acima, ptr2 é um inteiro, e não um ponteiro para inteiro como pretendiamos, causando erro na linha 11. Para corrigir este código, basta declarar ptr2 como ponteiro:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <stdio.h> int main() { int *ptr1, *ptr2; // CORREÇÃO ptr1 = malloc(sizeof(int)); ptr2 = ptr1; *ptr2 = 10; return 0; } |
Assim como no primeiro exercício, algumas pessoas também apontaram a ausência da checagem do retorno da função malloc() e do cast para (int *). Mas também não considerei estes fatores para validar a resposta como certa.
Outros falaram da ausência do free(). Sim, é sempre uma boa prática usar o free(), mas sua ausência nem sempre significa erro. No nosso caso, como a aplicação aloca e depois encerra, não teremos problema com memory leak pela ausência do free().
DESAFIO 3
O desafio 3 dizia o seguinte:
A função abaixo recebe um vetor de números inteiros e tem o objetivo de retornar o menor número inteiro deste vetor. Implemente esta função sem usar nenhum operador de comparação! Ou seja, você não pode usar nenhum destes operadores: “==”, “!=”, “>”, “<”, “>=”, “<=”.
1 2 3 4 |
unsigned int menor(unsigned int buf[], size_t size) { } |
Aqui o bicho pegou! Este é o típico “exercício bombril”, que pode ser resolvido de 1001 maneiras. Recebi implementações de 5 linhas e outras de 50 linhas! :)
Esta é a minha sugestão de implementação:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
unsigned int menor(unsigned int buf[], size_t size) { unsigned int m = 0; int i; while(1) { for (i = size; i; i--) { if (!buf[i - 1]) return m; buf[i - 1]--; } m++; } } |
Eu faço uma varredura do vetor em um loop e decremento, um a um, cada elemento deste vetor. A quantidade de decrementos realizados é armazenada na variável “m”. Quando um dos elementos do vetor atingir o valor 0, significa que descobri qual era o elemento de menor valor dentro do vetor, e retorno este valor, que é exatamente a quantidade de decrementos realizada, armazenada na variável “m”.
Recebi algumas implementações que usavam esta lógica, mas também recebi outras implementações bem interessantes.
Achei bem legal esta implementação do Paulo Daniel:
1 2 3 4 5 6 7 8 |
unsigned int menor(unsigned int buf[], size_t size) { unsigned int min = UINT_MAX; while(size) if(!(buf[--size]/min)) min = buf[size]; return min; } |
Ele conseguiu resolver em 5 linhas, usando apenas uma operação de divisão de inteiros!
Atualização: Como bem observado pelos leitores Fernando Barboza e Уθя¡ςκ, esta implementação tem uma falha, já que existe o risco de divisão por 0 na linha 5. Mas a forma como o problema foi resolvido não deixa de ser bem interessante.
Já o Douglas Drumond preferiu escovar alguns bits e trabalhar com complemento de 2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
unsigned int menor(unsigned int buf[], size_t size) { unsigned int shamt = (sizeof(unsigned int) * 8 - 1); unsigned int mask = 0x01; size_t i = size - 1; unsigned int menor_item = buf[i]; while (i--) { if(((buf[i] - menor_item) >> shamt) && mask) menor_item = buf[i]; } return menor_item; } |
DESAFIO 4
Este desafio dizia o seguinte:
Escreva um programa em C que imprima “Quero o meu livro!”, mas sem usar nenhum ponto-e-vírgula no arquivo “.c”! Obs: o programa deve compilar e funcionar normalmente.
A solução é bem simples:
1 2 3 4 5 6 |
#include <stdio.h> void main() { if (printf("Quero o livro!n")) {} } |
Você pode trocar o “if” pelo “while” também.
Teve gente que queria tanto o livro que colocou em um loop infinito! :)
1 2 3 4 |
void main() { while(printf("Quero o meu livro!n")){} } |
Mas aqui o pessoal resolveu usar a criatividade. Como falei apenas que não podia usar “;” no arquivo “.c”, e não mencionei nada sobre o uso de arquivo “.h”, recebi respostas do tipo:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Author: Celso // imprime.c #include <stdio.h> #include <stdlib.h> #include "imprime.h" void main() { IMPRIME } // imprime.h #define IMPRIME printf("Quero o meu livro!n"); |
Ou então trocando o “;” por um define passado pelo compilador:
1 2 3 4 5 6 7 8 9 10 11 |
/* Author: Fernando Martines * * Compilacao: gcc -DSPECIAL=";" desafio4.c -o desafio4 */ #include <stdio.h> int main() { printf("Quero o meu livro!n") SPECIAL return 0 SPECIAL } |
Bom, gostei muito do resultado destes desafios. Aprendi bastante e espero que vocês tenham aprendido também. Afinal, o que importa é participar. Ganhar é só um detalhe, não é verdade? O quê? Não!? :)
OK, chega de enrolação, estes são os três participantes que acertaram os 4 desafios e foram sorteados para receber o livro:
- Rodrigo (a.k.a. Skhaz)
- Eduardo Vieira
- Rodolfo Pereira Araujo
Para aqueles que não ganharam, não desanimem! Vocês podem baixar gratuitamente o PDF do livro no site da Micrium aqui.
Ou então vocês podem esperar o próximo concurso. Eu havia falado que tinha 3 livros, não é verdade? Então… eu estava escondendo o jogo! :)
Na verdade, alem destes 3, tenho mais 1! E logo mais teremos um novo desafio por aqui. Mas desta vez não será tão fácil assim! :)
Um abraço!
Sergio Prado