quarta-feira, 31 de outubro de 2007

AWK e Arrays Associativos

Um grande problema para quem trabalha com arrays associativos no AWK é
com relação a ordem dos elementos quando esta fazendo uma iteração.

Ex:

$ gawk 'BEGIN{ split("5 4 2 1 3",T) ; for(i in T) print T[i]}'
1
3
5
4
2


Eu inseri, nessa ordem, 5, depois 4, depois 2... porém o acesso aos
elementos de um array em um for do tipo
for( variavel in array)

é imprevisive / incontrolável.

Agora vejamos isto:

$ WHINY_USERS=1 gawk 'BEGIN{ split("5 4 2 1 3",T) ; for(i in T) print T[i]}'
5
4
2
1
3


WOW! Através da variavel de ambiente do unix WHINY_USERS agora eu consigo acessar os elementos na ordem em que eles foram inseridos no array!

E para acessar os valores na ordem crescente:
$ WHINY_USERS=1  gawk 'BEGIN{ split("5 4 2 1 3",T)
asort(T) ; for(i in T) print T[i] }'
1
2
3
4
5


A variavel de ambiente WHINY_USERS não esta documentada no man, muito menos na documentação que consegui a respeito do gawk. Descobri esta dica no comp.lang.awk e, por incrivel que pareça, tive que vasculhar o codigo fonte do gawk (graças a deus podemos fazer isso) para entender melhor o que essa variavel poderia fazer.

Enfim, fica a dica.

terça-feira, 30 de outubro de 2007

Tchelinux 2007 - Chamada de trabalhos

Seja bem-vindo à chamada de trabalhos do 2º Seminário do Software Livre Tchelinux que irá acontecer dia 1º de Dezembro de 2007 na UFRGS em Porto Alegre, RS. Antes de enviar sua proposta de palestra, recomendamos que leia atenciosamente o regulamento abaixo:

Sobre o Temário:

A equipe de avaliação de propostas irá selecionar 10 palestras técnicas sobre Software Livre dentro dos seguintes temas:

Sistemas Operacionais
Desktop baseado em Software Livre
Aplicativos Gráficos
Jogos e Multimídia
Linguagens de programação
Ferramentas para desenvolvimento
Banco de dados
Administração de Sistemas
Redes e Segurança da Informação

Sobre as Apresentações:

- Cada palestrante terá 75 minutos para apresentar seu trabalho
- Os recursos disponíveis serão projetor multimídia e micro-computador rodando Ubuntu Gutsy
- O palestrante deverá permitir que os slides de sua palestra seja publicada no site do grupo
- Não haverá nenhuma remuneração ou reembolso de despesas para palestrantes

http://www.tchelinux.org/papers/

Participem!

quarta-feira, 24 de outubro de 2007

Entendendo Ponteiros na linguagem C

Entender ponteiros (e ponteiros para ponteiros) nem sempre é facil quando estamos vendo C ou C++ pela primeira vez. O conceito é absurdamente simples, assim como os operadores * e &, mas pelo menos para mim demorou um tempão para a ficha cair (e olha que eu utilizava arrays direto e nem me ligava nesse detalhe).

Com auxilio do pre-processador C, vejamos se este exemplo que pode ser elucidativo:

#include "pointer.h" 
int main ()
{
int x = 0; // variavel de exemplo
pointer(int) y; // ponteiro

y = address(x); // y aponta para o endereco de x

x++; // incrementamos o valor de x
value(y)++; // incremento indireto (via ponteiro)

printf("value %d %d\n",x, value(y) );
printf("address %p %p\n",address(x), y );

return 0;
}


Ou seja, a criação de um ponteiro para uma variavel do tipo inteira é através da macro pointer. Outra macro, address, retorna o endereço de uma variavel e, assim, tenho uma referência aquela variavel. Posso então ter acesso ao valor e até mesmo manipular a variavel original.

Vejamos agora o resultado da execução:
$ ./a.out
value 2 2
address 0xbfffeaa4 0xbfffeaa4


Perceba que eu consegui incrementar a variavel duas vezes (através das duas formas disponíveis). Perceba também que o ponteiro y tem como valor o mesmo endereço de memória que a variavel x, razão pela qual consigo alterar o seu valor.

O codigo gerado pelas macros

int main () 
{
int x = 0; // variavel de exemplo
int * y; // ponteiro

y = (&(x)); // y aponta para o endereco de x

x++; // incrementamos o valor de x
(*y)++; // incremento indireto (via ponteiro)

printf("value %d %d\n",x, (*y));
printf("address %p %p\n",(&(x)), y);

return 0;
}


Eu recomendo que, uma vez que o conceito tenha ficado claro, que não se use mais este header sob pena de criar arquivos ilegíveis. Por exemplo, tente compilar com a opção de gerar os simbolos para debug (-g) e depois tente debugar esse programa: perceberão que o gdb, por exemplo, não mostra o codigo fonte com tanta clareza.

Para fazer este exemplo, utilizamos este arquivo header:

#define pointer(type)                    type *
#define value(var) (*(var))
#define address(var) (&(var))

domingo, 7 de outubro de 2007

Tropa de Elite 2 - Dia de Treinamento Java

Seguimos com novos exemplos inspirados na triste realidade da polícia carioca.

/*
* O Bope foi criado para atuar quando a policia perde o controle
* E no rio de janeiro isso acontece com bastante frequencia
*/
class Bope{
private String nome;
private int qtdeVitimas = 1; // ja começa bem!

public Bope(String nome){
this.nome = nome;
}
// sobrecarga do método ondeTaOBaiano
public void ondeTaOBaiano(Estudante e){
e.sabeVoarEstudante();
}
public void ondeTaOBaiano(Traficante t){
t.levaSacoNaCabeca();
}
// exemplo de método final!
public final Doze encontreiOBaiano(Baiano b){
return b.naCaraNaoQueEhPraNaoEstragarVelorio();
}
}

public class Treinamento{
public static void main(String [] xxx){
// Apresento o capitão nascimento
Bope instrutor = new Bope("Capitao Nascimento");
try{
// de cada 100 policiais que fazem o curso do Bope,
// so se formam 5, e eu, quando me formei parceiro,
// eramos apenas 3.
Turma.tentaFazerCursoBopeCom(capitao);
} catch (PolicialCorruptoEncontrado pce){

} catch (PolicialFracoEncontrado pfe){

} catch (PolicialSemABandoleiraNessaAlturadoCampeonato e){

}
}
}


SEUS FANFARRÕES!
VCS TEM 10 SEGUNDOS PARA COMPLETAR ESSE CÓDIGO!

- O zero-dois NÃO está escrevendo!
- SEU zero-dois, porque o senhor não escreveu nenhuma linha?
- A-a minha IDE não terminou de carregar, senhor...
- Agora a sua IDE ja carregou, seu zero-dois?
- S-sim senhor...
- Então, seu zero-dois, termine o seu programa, senão todos os seus colegas terão que usar o EDIT do MS-DOS até o fim do curso E A CULPA EH DO ZERO-DOIS!



HOMEM DE PRETO QUAL É A SUA MISSÃO?
É APRENDER JAVA SEM PRECISAR DE CERTIFICAÇÃO!
HOMEM DE PRETO O QUE É QUE VC FAZ?
FAÇO CODIGO FONTE QUE ASSUSTA O SATANÁS!


Estratégia, do inglês, Strategy...

- Senhor, o zero-cinco está dormindo...

quinta-feira, 4 de outubro de 2007

Aprendendo Conceitos antes de Sintaxe

O homem aprende por dois motivos: por gosto ou por necessidade.

Depois de passar um semestre brincando com Pascal na era pré-google ( quando não encontravamos uma pagina através do yahoo ou cadê, tentavamos urls aleatórias como www.pascal.org - que era a pagina da família pascal ), tive uma disciplina cujo professor só sabia Fortran e C.

Através do MOO descobri o curso on-line da UFMG, e pude dar os primeiros passos em C. Entretanto o foco dessa disciplina não era fazer agenda ou video-locadora - eram programas científicos. Linux, gnuplot, maple... foi um mundo muito divertido.

É claro que algumas coisas eu simplesmente não compreendia: os tais dos ponteiros, por exemplo. Era só ver um * que não fosse multiplicação que eu já tinha dor de cabeça. E assim se passaram alguns anos onde eu apenas reproduzia os comandos que tinha aprendido.

Anos depois, conversando com o CaSantos caímos em uma micro-aula de programação. Eis que ele profere sabias palavras: Ao estudar uma linguagem de programação, a primeira coisa que se precisa estudar são os conceitos e, por último, a sua sintaxe.

Toda a vez que eu entrava em uma lista de discussão ou forum e via as perguntas dos novatos eu lembrava dessa frase. Coisas como dizer que os arquivos .h do C são bibliotecas, colocar system("pause") pro programa não "fechar do nada" e por ai vai. O tipo da coisa que, quem conhece o conceito, não perguntaria.

Por que razão não se ensina os conceitos de uma linguagem logo no começo? Eu só posso pensar que é para os alunos aprenderem de forma intuitiva no começo e resgatar isso mais tarde (talvez em uma cadeira de compiladores, sei lá), mas será que isso acontece?

Geralmente o trabalho de fim de semestre dessas cadeiras é um CRUD em C com listagem (ou relatório) de alguma coisa ordenada de uma ou mais formas. Cadastrar alunos ou contas bancárias, salvando em arquivo.

Pois bem, se é uma disciplina introdutória, por que raios alguem iria pedir um CRUD?? Meu deus, os alunos mal sabem como compilar o programa, tampouco debuga-lo - No maximo enchem de printf("passei por aqui") - e pedem um programa com 'menu interativo'! Ai o camarada perde metade do tempo fazendo 'menuzinho' com asteriscos ou outro caracter e não consegue implementar a lógica. Quando implementa é aquela maçaroca. O que isso ensina?

Eu daria uma sugestão: quer ensinar C ou Java ou Snobol 4, ensine. Mas não peça um programa CRUD cheio de frescura - peça uma biblioteca. De um arquivo header ou uma interface java e diga: implementem essas funções/metodos ai. Eu vou testar o meu programa com essa biblioteca e espero que tudo funcione.

videolocadora.h

int cadastra_video(char *nome, int preco, int categoria);
int cadastra_cliente(char *nome, char *cpf, char *endereco);
int aluga_video(...);


Enfim, não consigo pensar num exemplo melhor. A ideia é introduzir um desenvolvimento em camadas, deixando o aluno pensar em como ele vai gravar, ler e ordenar os dados sem frescuras de tela, ensinando a fazer testes e também a debugar a aplicação.

Quer ensinar a fazer telinha? Ensina em outra disciplina, nesse caso ensinando técnicas de design apropriadas. Começando pela linha de comando do unix: como pode um aluno se formar sem nunca ter criado o seu próprio grep? Criar interfaces com o usuário não é algo facil, requer muito estudo, principalmente de usabilidade.

Alias fazer "telinhas" geralmente supõe colocar um programa em um estado. Quem aprende o conceito de maquina de estados no momento que esta fazendo esse cadastro? Posso apostar que esse pessoal não sabe o que é stateless e statefull e o professor nem pensa q isso seja importante (aqui eu lembro da agenda de telefones que eu fiz em pascal).

Fica aqui a minha sugestão. Espero que faça sentido :)

segunda-feira, 1 de outubro de 2007

Convertendo Números

Um dos meus primeiros desafios na área de programação foi fazer um conversor de números decimais para romanos. Eu estava aprendendo Turbo Pascal e usava um potente 286 com 1MB de memória - sem HD.

Fiz a maior sequencia de ifs da minha vida. Hoje estava relembrando e resolvi fazer uma versão SED.

/[0-9]*[5-9]...$/q
s/1...$/M&/;s/2...$/MM&/;s/3...$/MMM&/;s/4...$/MMMM&/
s/6..$/DC&/;s/7..$/DCC&/;s/8..$/DCCC&/;s/9..$/CM&/
s/1..$/C&/;s/2..$/CC&/;s/3..$/CCC&/;s/4..$/CD&/;s/5..$/D&/
s/6.$/LX&/;s/7.$/LXX&/;s/8.$/LXXX&/;s/9.$/XC&/
s/1.$/X&/;s/2.$/XX&/;s/3.$/XXX&/;s/4.$/XL&/;s/5.$/L&/
s/1$/I/;s/2$/II/;s/3$/III/;s/4$/IV/;s/5$/V/
s/6$/VI/;s/7$/VII/;s/8$/VIII/;s/9$/IX/
s/[0-9]//g


Tendo um número por linha ja basta.

$ echo '3999' | sed -f other.sed
MMMCMXCIX


O sed é realmente fantástico! Pena que acima de 5 mil tem que colocar uma barra em cima dos números.