30 de mar. de 2011

Cansado...

Não sei se vou conseguir.

Tenho andado extremamente ocupado com muita coisa. Além das cadeiras que estou fazendo, estou fazendo aula de LIBRAS, participo de dois corais na igreja, devo começar a fazer aulas de Alemão (no caso, voltar: eu já fazia antes, mas elas ainda não começaram esse semestre) e "trabalho" (como o leitor já deve saber, eu realmente não gosto dessa palavra) num projeto de pesquisa em computação gráfica.

Além disso, mantenho esse humilde blog, tentando blogar numa média (que ultimamente nem tem sido muito respeitada) de uma postagem por dia. Para não ficar sedentário, queria começar a fazer aulas de karate toushenkai numa academia que tem aqui em Guaíba (o cara que "ensina" - não sei a palavra certa pra isso - é um dos fodões da confederação gaúcha de karate toushenkai, pelo que sei), e para completar tenho lido O Senhor dos Anéis (não acabo NUNCA esse livro!) e o Learn You a Haskell For Great Good, do qual eu comentei no meu último post.

Assim, acho que tenho desculpa para repetir: estou cansado.

Não tenho conseguido dormir direito, mas também porque eu tenho sido relapso quanto a isso. Até agora tenho conseguido manter - a muito custo - todos os temas das aulas bem encaminhadinhos, ignorando a cadeira de Engenharia de Software (essa eu vou deixar pra estudar mesmo só perto da prova) e meio que relaxando um pouco na cadeira de Otimização Combinatória (mas não ignorando, porque além de ter prova semana que vem, a matéria é legal e difícil e eu já vi que não dá pra deixar pra estudar na última hora). Mesmo assim, não creio que essa estabilidade vá durar por muito tempo: só pra exemplificar, como eu disse, tenho prova semana que vem.

Uma forma de manter a minha vida funcionando um pouco melhor, pela experiência que tenho tido, é me abstendo das relações sociais. Eu poderia simplesmente ignorar todas as coisas a que me convidam e ignorar a existência da minha família por um tempo, além de os compromissos de igreja, ficando completamente livre para os estudos. Essa opção funcionaria maravilhosamente bem, dada a disposição que tenho tido em estudar ultimamente. Mesmo assim, não sei o quanto tempo ela permaneceria funcional, já que é bem fácil que eu perca o ânimo quando tenho mais tempo livre.

Outra opção talvez seria eu tentar me organizar e me esquecer das bobagens que eu faço durante os dias, como escrever nesse blog (me desculpe leitor, não se ofenda: apesar de o blog ser bobagem, o leitor é muito importante =D). De qualquer forma, acho que não quero isso: eu já nem to mais jogando, e, assim, se parar TUDO, não vou agüentar muito tempo sem alguma coisa pra "espraiar".

Enfim... o objetivo desse post era só compartilhar do meu cansaço. Eu já deveria estar dormindo, mas, enfim, to aqui, né?

R$

------------------
UPDATE: Eu esqueci de falar que além de tudo estou aprendendo a tocar flauta transversal "autodidaticamente" e que com isso às vezes perco parte do meu tempo tocando algumas músicas do livrinho "Solfeo de los Solfeos" - que a gente usava no tempo em que estudávamos na OSPA (digo "a gente" por estar me referindo a mim e ao mano ao mesmo tempo) - que, para todos os efeitos, foi o melhorzinho que eu consegui pegar para tocar (tem músicas fáceis e boas pra pegar a digitação e a embocadura =D). De qualquer forma, lembro: a flauta doce permanece com o seu mesmo espaço na minha vida, recebendo atenção especialmente quando quero tocar alguma coisa e não estou com saco de aceitar que isso possa ser difícil de alguma maneira.

29 de mar. de 2011

Sobre programação e linguagens funcionais

(Para o leitor que está procurando leitura sobre Haskell: Learn you a Haskell for Great Good. Fikdik).

Estou aprendendo Haskell.


Haskell é uma linguagem funcional bastante eficiente e absurdamente bonita. Normalmente, em outro momento, por ser linguagem funcional, eu simplesmente ignoraria a sua existência, já que não creio que seja algo que eu deva usar com muita frequência na minha vida no futuro. Mas... err... não é outro momento.

Estou fazendo uma cadeira chamada Modelos de Linguagens de Programação onde sou obrigado a "me confrontar" com outros paradigmas de programação, como, por exemplo, o funcional. Além dele, pelo que vi, teremos o lógico e, obviamente, o imperativo. A cadeira é legal, e tem tudo para ser uma cadeira interessante, apesar de normalmente as aulas do professor não serem das mais divertidas (mas ele se esforça, e é o que conta =D). Mesmo assim, o assunto me chama muito a atenção, afinal, vim para a computação porque gostava dessa idéia mágica de fazer os computadores fazerem aquilo que quero que eles façam.

O que é divertido que é no fim da cadeira o professor pede que escrevamos dois programas equivalentes utilizando paradigmas diferentes. Ele disse que não sabia se seria assim nesse semestre, mas já defini as linguagens que vou usar (se for assim): Lua para o paradigma imperativo (infelizmente, acho que não poderei usar muito as belezas funcionais da linguagem) e Haskell para o paradigma funcional.

Enfim... o professor colocou no moodle um link para um tutorial que estou lendo sobre Haskell que achei significativamente bom: o Learn you a Haskell for Great Good. É ótimo, apesar de, às vezes, muito lento. Mesmo assim, estou satisfeitíssimo: acho que até o fim de semana já estarei mais ou menos dominando boa parte da linguagem =D

Enfim... é isso. Talvez eu tente falar alguma coisa sobre Haskell num futuro próximo =D

R$

26 de mar. de 2011

Ponteiros em C - Tutorial

Há muito tempo venho pensando em escrever sobre ponteiros. Assim como eu, creio que muitos estudantes iniciantes tiveram sérios problemas para entender esse assunto que, no fim das contas, depois de aprendido, é até que bem fácil. Já vi até bastantes livros sobre o assunto e tutoriais na internet e tudo é muito parecido, sinceramente: falam sobre uma variável de ponteiro, e aí falam sobre o endereço de memória e sobre o que tá guardado no endereço de memória, e sobre aquele asteriscozinho, e depois sobre passar por valor e por referência e blá blá blá . Quando tive as aulas disso no meu primeiro semestre simplesmente ignorei a existência deles, crente de que não me seriam úteis. Estava enganado e, no fim das contas, tive de aprender a coisa na marra.

É do meu interesse que esse post se torne algo como um bom lugar onde as pessoas possam procurar sobre como usar ponteiros em C. Assim, faço questão de pedir que o leitor comente, ao término - ou não necessariamente ao término - da leitura, sobre o que achou, me indicando erros (para que eu possa corrigir) e me sugerindo alguma coisa que ache relevante ao trabalho.

Introdução

Como o assunto é complicado, pretendo ser o que já ouvi muitos chamarem de prolixo. Devo falar, falar e falar, tentando, assim, ser bem claro em minhas definições. Na primeira parte, utilizarei uma analogia para definir bem o conceito em si, não me apegando necessariamente à linguagem C. Mesmo assim, conhecimento prévio das outras estruturas da linguagem é muitíssimo bem vindo, já que não será nem um pouco abordado aqui. No segundo capítulo, elucidarei alguns assuntos que considero de suma importância antes de começar a falar de ponteiros. Assim, discorrerei um pouco sobre os vários usos do operador * na linguagem C e farei algumas considerações sobre ponteiros do C e as referências existentes em C++. Em geral, os usuários da linguagem C já devem estar acostumados com os assuntos tratados na segunda parte; mesmo assim, ainda considero interessante a sua leitura, para que entendam a maneira como pretendo prosseguir pensando ao abordar os temas posteriores.

Na terceira parte, deverei discorrer realmente sobre o uso dos ponteiros em C, destacando suas utilidades, dando exemplos e, principalmente, salientando as várias possibilidades de usos do operador *. Minha sugestão é que o leitor leia esse e os subsequentes capítulos testando trechos de código próprios, além daqueles que estarão disponíveis no próprio post. Por fim, no quarto e último capítulo, sugerirei alguns lugares onde o leitor poderá procurar por mais informações, além de fazer algumas considerações finais.

Capítulo 1

O conceito de ponteiro é nem um pouco intuitivo. Poderíamos dizer que "um ponteiro é uma variável que aponta para um endereço de memória", ou seja, que guarda um endereço de memória (frequentemente, de outra variável). Mesmo assim, concordemos que essa definição, apesar de bonita, só serve pra inglês ver. Assim, tive a idéia (eu duvido que alguém ainda não tenha pensado nisso, mas depois de uma boa procura no google concluí que, se alguém pôs em prática, ainda não ficou conhecido) de usar uma analogia mais intuitiva sobre o mundo real e "o mundo dos ponteiros".

Começaremos a nossa analogia conhecendo a Joana e o Mário. Naturalmente, a Joana é mais baixinha que o Mário, já que normalmente as mulheres são mais baixinhas (estou errado?).
Figura 1.1
Continuando a nossa história, esses nossos dois novos amigos, no mundo real, assumem uma outra forma: eles são endereços de memória. Como tais, eles só podem carregar uma informação de cada vez junto com eles.

No nossa história, o Mário está com o número de telefone da Joana, a saber, 2345678. Já a Joana, está com o número da casa da mãe do Mário: 41.

Figura 1.2
Ao longo da nossa história, isso vai ficar mais claro, mas vale lembrar (como o leitor até mesmo já deve ter percebido) que as coisas no mundo dos ponteiros funcionam de um modo diferente daquele percebido por nós no mundo real. Assim, um exemplo bem característico é o fato de que pessoas no mundo dos ponteiros nunca vivem juntas, ou seja: em cada casa, só cabe uma pessoa. Além disso, às pessoas às vezes são atribuídos chapéus, arbitrariamente, os quais elas são obrigadas a ficar usando durante um tempo indeterminado. Outra coisa[!!!]: nem todo mundo tem casa! Aliás, pouquíssimas pessoas têm. E às vezes essas casas passam de mão em mão, rapidamente.

Voltando a falar de ponteiros e fazendo um paralelo do seu mundo para o nosso, temos agora informações suficientes para definir o que eles são. Sem muita enrolação, os ponteiros são as casas. Elas guardam exatamente uma pessoa (um endereço de memória), tendo ela um chapéu ou não.

Quando um programador, no mundo real, declara uma variável qualquer (um int, por exemplo), ele aloca alguns endereços de memória para uso no seu programa. Isso significa, no mundo dos ponteiros, que agora aquelas pessoas têm chapéu, até que o programa acabe ou que a variável seja, de alguma forma, desalocada.

Acalme-se, jovem programador: ainda temos muito texto pela frente. O importante agora é só saber exatamente aquilo que eu disse: ponteiros são casas, ou seja, variáveis que guardam endereços de memória. A figura 1.3 faz um resumo da nossa analogia:
Figura 1.3

 Capítulo 2

Aqui eu faço uma pausa: esqueçamos nossa história por um tempo. Antes de continuar explicando sobre ponteiros precisamos de um certo embasamento. Assim, divido o capítulo em duas partes: uma sobre referências em C++ e outra em que combinarei com o leitor alguns padrões de notação (e, sim, essa última é, acho, a parte mais importante do capítulo).

2.1 Sobre referências em C++
A linguagem C, na minha opinião, é "completa" no que trata de ponteiros. Com ela, podemos - o leitor não precisa entender do que estou falando nesse primeiro momento - referenciar (usando o &) e desreferenciar (usando o *). Com o "advento" do C++, inventaram as "referências" (não confundir com o "referenciar" e o "desreferenciar" da frase anterior), que tem uma semântica parecida com a dos ponteiros, mas que não é completa por si só, precisando ainda dos ponteiros para se basear. Além disso, as ditas referências "mudam" a semântica do operador "&", diminuindo a sua ortogonalidade.

Assim, me abstenho de fazer qualquer consideração sobre o que são e como funcionam as referências nos capítulos seguintes, me limitando a dizer que elas simplesmente não existem na linguagem C. Dessa forma, pessoas com dúvidas sobre protótipos de funções (i.e., a declaração da função) utilizando, em qualquer parte, um &, devem procurar outro tutorial na internet sobre o assunto.


2.2 O operador *
Muitas vezes, o grande motivo pelo qual o programador iniciante se confunde com ponteiros não tem nada a ver com o ponteiro em si, mas com o operador *. No início do capítulo 3, eu ensinarei como o são declarados ponteiros em C. Aqui, farei um pequeno resumo.

Para declarar um ponteiro, basta seguir o padrão "<tipo>* <nome da variável>;". Isso também serve para, ao escrever uma nova função, especificar que você quer que haja um parâmetro que seja um ponteiro. O código a seguir exemplifica o que quero dizer:


Sabendo que o * é um operador (unário, diga-se de passagem), ele não é influenciado por espaços (bem como qualquer operador). Um exemplo disso seria o operador de soma: tanto faz escrever 2+3, 2+ 3 ou 2 + 3, ou qualquer combinação diferente (inclusive com um número maior de espaços). Assim, frequentemente vemos pessoas jogando o operador * para todos os lados, o que normalmente confunde o programador inexperiente:


Nos trechos acima, parece trivial enxergar que o tipo daquelas variáveis é ponteiro. Mas e quando temos uma função que recebe um ponteiro e manipula esse ponteiro dentro de si? Mais adiante veremos um exemplo, mas antes preciso discutir sobre a utilidade de um irmão gêmeo do operador *, o operador de desreferência. No capítulo 3, o veremos com mais detalhes, mas aqui faço um resumo sobre ele.

Agora que você já sabe para que servem os ponteiros (fazer referência a endereços de memória) e já viu qe eles têm um tipo (ou seja, referenciam endereços de memória alocados com o propósito de guardar uma informação daquele tipo), você já deve ter percebido que eles não seriam muito úteis se não tivéssemos um mecanismo para acessar aqueles endereços, certo? O C disponibiliza, para tanto, o operador * (sim, ele mesmo, mas usado num outro contexto). O exemplo abaixo deve deixar claro como usá-lo (ao menos tenta).


Você saberia me dizer o que cada uma das funções acima faz (por favor, sem ler os comentários)? Creio que alguns leitores desavisados me diriam que a primeira e a última função fazem exatamente a mesma coisa, o que não é verdade. Mesmo assim, creio que a ambiguidade deixa de existir quando o * fica perto do tipo, como na terceira função. Dessa forma, para que não haja esse tipo de problema, usarei o asterisco, daqui para a frente, sempre perto do tipo.

Vale reforçar aqui o seguinte: uma vez usado o asterisco, ele se torna parte do tipo. Dessa forma, faz sentido dizer que o tipo de uma variável é, por exemplo, um ponteiro de inteiro (int*). Isso é importante para a continuação do texto.


Capítulo 3

Voltando à nossa história (do Mário e da Joana), vamos definir ponteiros, sua sintaxe e seus vários usos. Como já vimos antes, no capítulo 1, ponteiros são as casas dos endereços de memória, ou, melhor, são as casas das pessoas no mundo dos ponteiros.

Como também já visto, casas são um bem extremamente difícil de se adquirir no mundo dos ponteiros, além de frequentemente passarem de mão em mão rapidamente (ponteiros, nos programas, estão frequentemente trocando o endereço para o qual estão apontando).

3.1 Declarando ponteiros
Para criar uma casa no mundo dos ponteiros (ponteiro em C), deve-se utilizar a seguinte sintaxe:
<tipo>* <nome_da_nova_variável>;

Essa sintaxe também serve para indicar que uma função pretende receber como parâmetro um ponteiro. O seguinte trecho de código (também utilizado no capítulo 2) exemplifica o caso:


Em C, quando uma variável é criada, ela não é inicializada com nenhum valor. No caso de ponteiros, é como se, ao terminar de construir uma casa, um endereço de memória vileiro já fosse lá e invadisse, tomando-a para si. Assim, a forma de expulsar o morador indesejável do lugar é atribuindo um endereço de memória "nulo" pra ela. Em C, a constante "NULL" (que é o mesmo que escrever o valor 0, mas aconselho fortemente que se use NULL em vez de 0) serve como tal endereço, e, no mundo dos ponteiros, ele definitivamente é o cara mais rico do mundo.

Como eu disse, o mundo dos ponteiros têm uma série de especificidades, muitas das quais ainda não foram numeradas (e que, ao longo do tempo, serão reveladas). Uma delas é o fato de que cada pessoa tem um número, relativo ao seu endereço de memória. Dessa forma, poderíamos dizer que o NULL é o 0, por exemplo. Da mesma forma, o Mário poderia ser, por exemplo, o 40.000, e a mãe do Mário, como já visto (veja a figura 1.2), seria o 41.

Como ponteiros são variáveis como qualquer outra, a atribuição é feita do mesmo jeito, através do sinal de "=". Além disso, ponteiros são números, como qualquer inteiro, o que implica que também podemos manipulá-los como manipularíamos inteiros, através de somas, multiplicações ou substrações, por exemplo (isso seria o mesmo que ficar mudando arbitrariamente o dono da casa).

O seguinte trecho de código mostra um exemplo desse tipo de manipulação. Eu crio um array de 20 inteiros e um ponteiro. Mando o ponteiro apontar para o primeiro endereço de memória desse array e percorro o array, sem fazer nada (acalme-se, jovem programador, logo faremos alguma coisa). Caso o leitor não entenda o "+4", eu explico: nesse código, estou supondo que o inteiro tenha o tamanho de 4 bytes. Como cada endereço de memória aponta para um byte diferente, tenho que pular 4 bytes para chegar no início de um novo inteiro. Mais para a frente, mostrarei uma outra forma mais interessante de pular exatamente o tamanho do inteiro (independente de qual seja esse tamanho).


Como eu disse, logo esse código fará alguma coisa, mas antes precisamos de um pouco mais de informações. Em primeiro lugar, quero apresentar ao leitor dois novos operadores: o irmão gêmeo do *, e o operador &.

3.2 Os operadores * e &
Suponha agora que você saiba em que casa mora atualmente a Joana (tenha um ponteiro dela) e que queira perguntar a ela que informação ela guarda. Obviamente, dependendo do tipo da informação (int, char, etc), você terá de perguntar não só a ela, mas também a algumas outras pessoas que têm numeração imediatamente posterior a ela (no caso de um, por exemplo, serão mais 3 pessoas, além dela). O operador de desreferência (*) tem como objetivo lhe permitir isso.

Assim, dado um ponteiro (uma casa), você poderá, utilizando o *, alcançar o endereço de memória que ele aponta (o morador da casa). Utilizaremos o trecho de código anterior para exemplificar o uso do *:


Você consegue me dizer o que o trecho de código acima faz? Ele pega o valor int do endereço de memória para o qual o ponteiro está apontando, e soma-o com a variável soma. É interessante compreender aqui a importância do tipo do ponteiro: o que aconteceria se o tipo do ponteiro que estamos utilizando fosse char, que utiliza somente 1 byte? E o que aconteceria se o ponteiro apontasse para uma struct que utilizasse, por exemplo, 8 bytes? Como eu disse antes, os ponteiros lêem endereços de memória, sem se preocupar com o que tem dentro deles. Assim, o ponteiro de char leria somente 1 byte (e não seria problema nenhum, no nosso caso) e o ponteiro do tipo da referida struct leria 8 bytes (o que seria um problema quando chegássemos na última iteração do for, já que haveria a possibilidade de lermos endereços não alocados para uso do nosso programa, i.e., pessoas sem chapéu).

Com o objetivo de introduzir o operador &, preciso contar mais uma coisa sobre o mundo dos ponteiros. Todas as pessoas, no mundo dos ponteiros, podem ter um número incontável de clones (fique claro, aqui, que ser clone é um propriedade reflexiva, o que significa que, se o Mário tem um clone, então o Mário é um clone desse clone, bem como o clone é clone do Mário). Assim, normalmente, nas chamadas de funções (no mundo deles, festas), os endereços de memória, preguiçosos, em vez de irem eles mesmos, mandam clones de si. Que forma melhor para convidar alguém para uma festa do que mandar um convite justamente para a casa da pessoa? É exatamente para isso que serve o operador &. Quando usamos o &, o operador de referência, pegamos o endereço de memória da variável à qual esse operador está sendo atribuída. O trecho de código a seguir tenta exemplificar o caso:

Apesar de por agora ele parecer não ter muita utilidade, o operador & terá um uso significativamente importante no futuro.

3.3 Sizeof()
Quando apresentei o operador *, escrevi um trecho de código que somava todos os elementos de um vetor de tamanho 20 e colocava a soma numa variável chamada soma. Naquele momento, para iterar entre os elementos do vetor, simplesmente supus que o tamanho de um inteiro era de 4 bytes. Assim, a cada iteração, para atualizar o lugar para onde o ponteiro (passar a casa - o ponteiro - de um dono para o outro - os endereços de memória) estava apontando, eu somava 4 ao valor do ponteiro.

O problema é que freqüentemente o tamanho de um int muda, dependendo do compilador usado, das configurações usadas na compilação e da arquitetura para a qual o programa foi compilado. Ao mesmo tempo, seria um problema se, a cada lugar onde eu fosse compilar o programa, eu tivesse que setar todos os tamanhos direitinho. Para resolver o problema, existe a função sizeof(), que retorna exatamente o tamanho do tipo passado como parâmetro. Ela será muito mais útil para outros fins, mais para a frente. Mesmo assim, o exemplo a trecho de código a seguir exemplifica o seu uso e mostra como aquele nosso outro exemplo poderia ser escrito de uma forma mais interessante:

3.4 Passagens de parâmetros
Antes de começar a falar sobre um assunto bastante novo, gostaria de fazer algumas considerações. Em primeiro lugar, caso o leitor seja um programador principiante, sugiro que tente brincar mais com os ponteiros, fazendo códigos próprios e testando os resultados. Sugiro que volte à seção 2.2 e tente reler o código, agora entendendo melhor o que foi dito lá. Em segundo lugar, gostaria de pedir que o leitor testasse cada um dos trechos de código que serão exibidos a seguir, já que podem acabar causando alguma confusão. O assunto, admita-se, é extremamente não intuitivo, apesar de não ser difícil.

Em terceiro lugar, quero fazer uma distinção entre variável e endereço de memória. Uma variável é uma abstração de um ou mais endereços de memória. Como eu já disse, no mundo dos ponteiros, isso equivale a dar chapéus para as pessoas que estão sendo "ocupadas" para uma variável. Mesmo assim, no texto a seguir, os dois conceitos meio que se confundem, no sentido de que "chamar uma variável para uma festa" é o mesmo que "chamar os endereços de memória de uma variável para uma festa", ou, melhor "chamar as pessoas com o chapéu relativo a uma variável para uma festa". Quando falo que uma variável é preguiçosa, quero dizer que "todas as pessoas com chapéus daquela variável são preguiçosas". Com isso dito, creio que podemos ir em frente.

Figura 3.1 - Achei que era interessante por essa figura aqui =D


Como eu disse em outro momento, as pessoas, no mundo dos ponteiros, têm um número indeterminado de clones. Além disso, lá, quando falamos em chamadas de função no mundo real, estamos falando de festas. Para exemplificar o caso, peguemos a seguinte função:

O programador iniciante, ao olhar para essa função, acharia natural que, após a chamada da função, a variável passada como parâmetro tivesse o seu valor incrementado de 1. O que acontece é que, como também já foi dito antes, as pessoas no mundo dos ponteiros são preguiçosas, e, a menos que sejam chamadas em específico elas mesmas, elas naturalmente mandam clones de si mesmas para as festas. Para o mundo real, isso significa que a linguagem C, ao receber uma chamada de função como aquela, copia o valor da variável passada como parâmetro para outro endereço de memória e, em vez de manipular a variável, manipula esse novo endereço de memória, mantendo a variável intacta.

Para exemplificar, utilizemos a nossa função e o seguinte trecho de código:


Para resolver o problema, precisamos de um jeito de chamar a variável certa (e não um clone dela) para a festa. Aliás, as pessoas no mundo dos ponteiros são muito bem educadas: elas SEMPRE vão, quando chamadas, elas mesmas, para as festas. Como eu já disse em outro momento, qual modo melhor para chamar alguém para a festa do que justamente entregar o convite em sua casa? O equivalente a isso, em C, seria modificar a função incrementa de forma que ela recebesse uma casa - um ponteiro - como parâmetro. Assim, na hora da chamada, passaríamos uma casa como parâmetro, fazendo com que a própria variável comparecesse à festa. Veremos como isso ocorreria num exemplo real:


O que houve aqui? Em primeiro lugar, quero avisar ao leitor que ponteiros também são variável, e, como tais, ocupam endereços de memória. Assim, obviamente, casas são formadas por pessoas (o que talvez torne o dono de uma casa um escravocrata, no mundo dos ponteiros). Como casas são pessoas, elas também têm clones. E como elas têm clones, elas também são preguiçosas e às vezes resolvem mandar seus clones no seu lugar nas festas.

Assim, realmente, quando a casa foi passada como parâmetro, ela, em vez de ir para a festa, mandou um clone seu em seu lugar. Dessa forma, se o clone fosse modificado - no caso, não ocorreu, mas ele poderia ter sido -, a casa original permaneceria intacta. Mesmo assim, o conteúdo da casa e do clone eram o mesmo: ambos apontavam para o mesmo endereço de memória. Assim, esse endereço de memória não tinha como fugir: ele FOI sim à festa, tendo sido modificado.

Esse tipo de passagem de parâmetro (mandando a casa da pessoa, em vez de a pessoa) é chamado de passagem de parâmetros por referência, e frequentemente causa problemas até mesmo a programadores um tanto experientes, visto que é muito fácil esquecer um asterisco aqui ou ali.

3.5 Alocando espaço
Um último assunto antes de terminar o capítulo 3: malloc(), free(), e acessos a endereços inválidos de memória.

O leitor deve lembrar que, lá em cima, eu falei sobre o NULL, o cara mais rico do mundo dos ponteiros. Feliz ou infelizmente, a sua fortuna normalmente dura pouco tempo: tão logo ele ganha uma casa, ele logo já perde para um outro alguém. Traduzindo, é uma boa prática de programação atribuir NULL a todos os ponteiros que não podem ser imediatamente inicializados. Mesmo assim, ninguém cria ponteiros se não for usar, a menos que o NULL tenha algum sentido útil no seu programa (e de vez em quando tem).

De qualquer forma, como eu disse, o NULL é um cara rico. Assim, como pessoa rica, pessoas comuns não têm acesso a ele. Dessa forma, se um programador, em seu programa, tentar acessar o endereço de memória NULL, através de um ponteiro, por exemplo (utilizando o operador *, no caso), o seu programa irá travar. Além disso, há uma certa probabilidade de que, se o programa tentar acessar endereços de memória sem chapéu (ou seja, não alocados devidamente para o programa), o programa também trave. Por isso, é altamente recomendado só acessar pessoas com chapéus, já que essas são as já conhecidas pelo seu programa.

O uso de vetores e variáveis torna dar chapéus para os programas uma tarefa significativamente fácil. Mesmo assim, tem vezes em que o programador simplesmente não sabe, por qualquer motivo, quantos chapéus deverá distribuir (ou seja, quantos endereços deverá alocar). Pode ser que o tamanho mude conforme a entrada do usuário, ou mesmo que ele queira alocar o dobro do espaço alocado toda vez que todo o espaço alocado tiver sido utilisado.

Para solucionar esse problema, existe a função malloc(). Ela retorna um ponteiro do tipo void com o espaço alocado. O tipo void* é um tipo especial, na linguagem C. Ele significa "nenhum tipo", ou "qualquer tipo". Assim, podemos atribuir a esse tipo ponteiros do tipo que quisermos. O trecho de código a seguir exemplifica o uso da função (ignore a parte do "free()" por um momento):


Infelizmente, a linguagem C++ (sim, aqui falo do C++) é meio chata com atribuições de tipos diferentes. Assim, para manter a compatibilidade entre as duas linguagens, quando utilizamos malloc(), é interessante colocar um typecast (um aviso de qual é o tipo que queremos que o malloc seja) à esquerda do uso da função. No trecho de código acima, esse typecast é feito através do (int*) à esquerda do malloc(). Como parâmetro, a referida função só exige um número, que significa o espaço em bytes que queremos assim.

No nosso caso, queremos alocar o espaço de 10 inteiros para o ponteiro "meu_ponteiro" (por isso aquela multiplicação dentro do malloc(). Isso não significa que ele guardará todo esse espaço em sua variável. Diferentemente, ao término da atribuição, o ponteiro terá guardado o endereço de memória do início da área alocada. Assim, daquele endereço até o fim da área alocada (no nosso caso, sizeof(int) * 10) todas as pessoas, no mundo dos ponteiros, terão chapéus.

Para desalocar esse espaço, devemos usar a função free(). Ela recebe um ponteiro como parâmetro e simplesmente desaloca aquela área (retira o chapéu das pessoas da área).

Capítulo 4

Finalmente, chegamos ao final do nosso estudo sobre ponteiros. Esse capítulo só trás algumas considerações finais sobre o meu texto, me identifica e mais alguns detalhes.


Todas as imagens do texto foram feitas utilizando o KolourPaint, no Ubuntu. Por esse motivo, os textos nas imagens ficaram sem acento - tentei por acento, não consegui de primeira, desisti. Além disso, tentei e consegui usar o "syntaxHighlight 1.5.1". Depois de conseguir, percebi que realmente o Pastebin tinha um sistema de embedding muitíssimo bom (além de me permitir usar tabulações no código) e passei a usá-lo.

Esse post teve inspiração em várias coisas que andei vendo e pensando nos últimos tempos, mas destaco especialmente a série de aulas de C que o Fialho tem postado em seu blog, Lines of Code, de vez em quando. Além disso, não deixo nenhuma bibliografia utilizada, já que, realmente, não usei nenhuma.

Aviso especialmente que nenhum trecho de código postado foi testado, o que significa que, sim, PODE HAVER ERROS. Dessa forma, peço que o leitor me ajude com correções e sugestões, no caso de querer contribuir.


------------------------
Era isso... se tiverem algo mais com o que contribuir, peço que postem comentários. E, humildemente, peço que, se forem repostar isso em algum lugar (estou meio orgulhosinho do meu texto, e acho que ele ficou bom mesmo, né?), ao menos mantenham o link original de onde foi retirado =D

R$

21 de mar. de 2011

A um mês do Julgamento Final

Tenho quase certeza que o termo Judgement Day veio pra cá com esse nome, Julgamento Final. Por isso o nome "diferente".

Estamos a um mês do "fim do mundo". Nesse momento, um super-computador com auto-consciência deve estar ficando cada vez mais inteligente e mais irritado com o miseravelmente contraditório comportamento humano.

Durante pouco menos de 10 anos, a linha do tempo sofreu algumas variações por causa das frequentes investidas dos seres viventes no futuro em impedir que o julgamento final acontecesse. Mesmo assim, isso não deverá ter impedido que o Skynet - o nome do computador - esteja pronto para se voltar contra os seres humanos no dia 21 de abril de 2011, o dia do Julgamento Final.

Fui procurar sobre a lore do Terminator e ela parece bem mais consistente do que eu tinha crido que fosse quando assisti o seriado, menos de um mês atrás. Na wikia tem até uma wiki sobre o assunto, explicando tudo direitinho sobre quando é que deveria ter sido o Judgement Day e blá blá blá.

Eu ía postar aqui dizendo que o Julgamento Final, no fim das contas, teria sido como o futuro do De Volta para o Futuro, que hoje já é passado, no sentido de que nunca ocorreu, mas tenho que admitir que achei o Terminator bem bom em manter uma linha de tempo em conflito com a nossa realidade, de vez em quando lançando "patches" de explicações sobre o que houve no nosso tempo que impediu que a Skynet causasse o Judgement Day nesses dias que se passaram. O que quero dizer, ou seja, é que logo logo provavelmente saia alguma nova "novel" falando que o Judgement Day foi adiado para daqui a mais um tempo (em vez do dia 19 de abril - porque no fim das contas o Judgement acaba ocorrendo antes do previsto) porque alguém fez algo para impedir que ele ocorresse.

De qualquer forma, já to há tempos querendo compartilhar um video do Youtube que achei do Back to the Future que vale a pena (MUITO!!!) assistir:



Era isso.........

R$

20 de mar. de 2011

Trote universitário CiC UFRGS, bebedeira, HPS

Estou abismado.

A cada hora recebo notícias e mais notícias de um assunto que gerou polêmica desde ontem denoite, quando mandaram para a lista da graduação do curso de Ciência da Computação (CiC) da UFRGS (onde estudo) um e-mail com o link de uma notícia da ZH dizendo que um aluno do nosso curso teria entrado em coma após um trote violento no Parque da Redenção, na capital.

Na hora, achei uma extrema bobagem, mas obviamente aquilo era só a ponta do iceberg. Criou-se uma flamewar (em termos: teve um cara que resolveu dizer que trote é algo que não deveria acontecer, e blá blá blá, dizendo que trote é fascista - Hitler? -, militarista, sádico e autoritário. Gente assim, obviamente, é troll nato, que não merece atenção, lamentavelmente) na lista da graduação, ao mesmo tempo em que se comentava a cada momento no Chat da Cic, na lista da Patota e ainda na comunidade da UFRGS. Até na lista da graduação da Astrofísica (da UFRGS) teve discussão sobre o assunto (um professor que não sabia de NADA lá resolveu mandar por e-mail a reportagem MENTIROSA da Zero Hora comentando coisas como "olha a barbaridade que esses estudantes fizeram"). Na Astrofísica, meu irmão mandou um e-mail com todos os comentários e desmentiu a história do professor.

Hoje, sábado, às 12h20 da noite (ou seja, já é domingo, pra quem aceita essa coisa de trocar de dia depois da meia-noite), as notícias ainda não terminaram, de certa forma: o cara voltou pra casa, desmentiu a história através do orkut (assumiu a responsabilidade, dizendo que bebeu sim de livre e espontânea vontade) - claro que houve trolls dizendo que o perfil dele era fake u.u -, e agora dizem alguns jornais que a família tá reclamando que os veteranos não prestaram socorro a ele rápido o suficiente e obrigaram a família a ir levá-lo pra o hospital, em vez de eles próprios fazê-lo.

Li um horror, tanto na comunidade da UFRGS, quanto na lista da graduação e no chat da CiC (e até no buzz) e concluí que o melhor lugar a se ler sobre o assunto, no fim das contas, é esse blog.

No fim, uma conclusão: sabem aquelas reportagens de jornal onde se fala um monte de coisas sobre as quais a gente fica assustado pensando que deve ter sido um negócio horrível (ou acha tri, no meu caso, porque a barbárie foi grande e divertidamente sádica)? Em geral, elas são só sensacionalismo barato da mídia T_T (talvez feliz, talvez infelizmente)

// O Correio do Povo chegou a dizer que ele foi obrigado a ingerir ÁLCOOL DE COZINHA!!!

R$

19 de mar. de 2011

Sobre ler...

Na imagem, um livro que aprendi a gostar de ler. Infelizmente, faz um bom tempinho que não tiro um momento para apreciar suas sábias palavras n_n


Estava pensando: como eu tenho lido!

De vez em quando, me paro a pensar na quantidade absurda de coisas que eu tenho pra ler e que tenho lido. Leio livros por diversão, leio textos pra faculdade, leio blogs onde me descontraio com assuntos de que não preciso pra viver, leio os meus textos - quando escrevo-os -, para ter certeza de que não cometi nenhum erro grosseiro de escrita, leio livros porque decidi que quero aprender sobre o assunto de que eles tratam, leio e-mails e leio artigos para a "bolsa", além das buzzadas de TODOS aqueles a quem eu sigo.

Quando eu era criança, detestava ler. Achava cansativíssimo, chato, coisa de gente que queria se aparecer. Lembro até que na minha sétima série minha prima me obrigou a, durante as férias, ler um livro do Arquivo X que ela me fez tirar na biblioteca da UNISINOS (ela trabalhava lá e eu fui passar uns dias na casa dela). Em 3 dias eu li um livro de quase 100 páginas. Fiquei até orgulhoso, no fim das contas, apesar do trabalho que deu.

Depois de um tempo, algumas vezes me aventurei a pegar livros e tentar ler, normalmente parando logo no meio do livro. Lembro que em 2004, quando fomos pra casa dessa minha mesma prima, em Salvador, eu li o Senhor dos Anéis - A Sociedade do Anel. Demorei UM HORROR pra ler o livro, e lia frequentemente enquanto com sono, o que me impediu em muito de entender algumas coisas que eram realmente importantes no livro.

Quando teve o terceiro ano e os vestibulares (até logo antes de entrar pra UFRGS), eu já até lia um pouquinho mais. Mas ainda era pouco demais. Das leituras obrigatórias - convenhamos, os livros do Machado de Assis são fantásticos[!!!], apesar de eu só reconhecer isso hoje -, li só "três": Quincas Borba, Os Ratos (e nem li até o fim) e alguns contos do Primeiras Histórias.

Com a chegada na faculdade, tudo mudou. Tive de ler, no primeiro semestre, vários capítulos do How to Design Programs, para aprender Scheme mais direitinho. E também tinha os livros de Cálculo I e II, que eram gigantescos, e dos quais me obriguei (principalmente em Cálculo II, já que a professora era um lixo) a ler vários capítulos. Dali pra frente, posso dizer com certeza que muito da minha vida "de leitura" mudou bastante, inclusive pela inclusão de textos grandes em inglês pra ler - até então, apesar de ler coisas aqui e ali, nunca lia nada como um livro em inglês, ou vários capítulos de um.

Infelizmente, boa parte da minha leitura (e-mails, blogs, notícias e até mesmo às vezes alguns artigos "da falsamente chamada ciência") apresenta até que com uma certa frequência alguns erros. No inglês admito que até que é mais difícil - principalmente pela minha inexperiência e pela minha facilidade em aceitar que talvez aquele possa ser um jeito de dizer aquilo que se quer que eu ainda não conheço -, mas no português é incrível a facilidade que tenho em listar erros e mais erros gritantes nas minhas leituras. Não que eu seja o cara mais polido do mundo ou que eu seja o cara que define os caminhos pelos quais a minha língua deve andar (eu até mesmo digo "truce" - do verbo trazer), mas admito que às vezes sinto falta de um "respeito" maior à minha língua materna.

Tenho andado cansado de tanto ler, e tenho tido até certa dificuldade pra focar em objetos distantes em alguns momentos (e atribuo isso às minhas leituras às vezes quase ininterrompíveis). Hoje mesmo, enquanto assistindo à TV, não conseguia focar perfeitamente nas letras que apareciam na imagem, tendo até mesmo perguntado aos meus parentes se a imagem estava embaçada.

De qualquer forma, estou em início de semestre, e a tendência é que a quantidade de leitura só aumente, o que não é de todo ruim: cada vez mais eu gosto desse eu leitor em que estou me transformando u.u

Era isso...

R$

15 de mar. de 2011

Início das aulas

Estou caindo de sono.

A planta em que o beija-flor está acho que é parecida com aquela que tem lá no instituto, perto da janela da minha sala de aula.


Minhas aulas, em teoria, começaram na quinta-feira passada, dia 10 de março. Ao término daquele dia, dormi como uma pedra: tinha ido dormir tarde na noite anterior e havia acordado às 6h da manhã para ir pra aula (agora moro em Guaíba, tenho que pegar ônibus às 6h40 T_T).

De qualquer forma, na sexta-feira não tive aula, o que possibilitou um descanso bem bom. Ontem, segunda-feira, dia 14, foi o meu segundo dia de aula. Fui para a aula às 6h40, como normalmente, e fui parar efetivamente em casa só depois das 10h30 da noite - quando comi um maravilhoso xis que me impediu de ir para a cama cedo - medo de passar mal por comer muito e logo ir dormir, já que isso piora o refluxo. Assim, fui dormir quase 1h da manhã (passei a limpo o pouco que até então tinha escrito num caderno novo que comprei ainda ontem e vi um pouco de CQC, além de tocar um pouco de flauta transversal - minha vizinha deve ter me odiado), e hoje, novamente, acordei às 6h.

Minhas aulas de segunda-feira e quarta-feira têm sido ótimas (só tive uma de cada até agora, mas elas serão ótimas, de qualquer forma). Peguei só professor bom, que dá aula "envolvente" e de quem todo mundo gosta. Em compensação, as terças e quintas (ao menos eu só tenho aula até meio-dia) serão os dias terríveis. Felizmente, algo já me aconteceu duas vezes na aula de MLP (Modelos de Linguagens de Programação), uma na quinta-feira e outra hoje: no meio da aula, um beija-flor se pára a "beijar" as flores de uma planta bem na cara da janela para a qual passo boa parte do tempo da aula olhando. Depois, durante a aula de Engenharia de Software, fiquei olhando a janela, de tempos em tempos, esperando que talvez a bela ave aparecesse "para mim", de forma que eu pudesse contemplá-la um pouco, esquecendo o sono e o cansaço que o falar da professora me traz. Fiquei em vão: o bicho não apareceu. Mas espero que logo apareça, já que ao menos assim me entretenho (ou entreto, como eu sempre gostei de dizer) com alguma coisa e perco o sono.

Falando em sono, como eu disse, estou morrendo de sono. Acho que até deveria ir dormir agora, nem sei........ mas acho que nem: tem um monte de coisas pra ler. Vejamos o que consigo aprender sobre bioquímica nas próximas horas =D

R$

11 de mar. de 2011

Terminator: The Sarah Connor Chronicles



(caso queira baixar, sugiro que tente este link - pensei que fosse óbvio, mas vale o comentário: pra burlar o "protetor de download", basta pegar o que está escrito depois de "url=", em cada link, inverter, e usar como link "de verdade" pra download)

Em 4 dias, assisti à série que dá nome à postagem. Gostei, admito. Mesmo assim, acho que é porque nem criei muita expectativa sobre ela.

Estava eu procurando alguma coisa pra assistir nas férias quando, por acaso, me deparei com esta. Era curtinha, com só duas temporadas, e os links todos eram para Megaupload. Além disso, estava em rmvb (eu não sou desses cheios de frescuras que acham que faz TODA a diferença assistir em ".avi" - ou seja lá o que for - em vez de ".rmvb" ou ".mp4", numa tela de 14 polegadas), extensão de que gosto justamente por ser bem compactazinha.

Baixei: como tinha de ler um monte de coisas para o início das aulas, ía baixando enquanto lia. Admito que não consegui ler direito tudo o que eu pretendia, mas ao menos não deixei de fazer algo que queria ter feio nas férias: assistir a ao menos alguma série (não que tenha algum motivo em especial, mas ao menos eu queria poder dizer que fiz algo de lazer e de útil - ao mesmo tempo - nas minhas férias).

Tomara que o leitor "curta", se resolver assistir, como eu "curti". Spoilando um pouco, é verdade que não gostei do primeiro e do último episódios, ambos por causa de inconsistências. Mas não posso dizer mais nada: tirem suas próprias conclusões.

Assisti, enfim. Foi boa. Recomendo. Só queria não deixar de ter comentado isso. A próxima deve ser Dexter: de vez em quando alguém me fala bem dela. Mas não sei com que tempo assistirei. Não sei quanto tempo terei pra isso. Só sei que estou cheio de coisas pra fazer agora e não deveria estar escrevendo aqui.

R$

4 de mar. de 2011

Músicas de Megaman 8-bits

Eu adoro música de Megaman em versão 8-bits.



Como estava meio vidrado na música do Boomer Kuwanger hoje cedo, resolvi procurar no Youtube por ela e, tendo encontrado um video de uma versão da mesma música em 8-bits, resolvi clicar para ver se era boa. Era! Me inspirei e comecei a procurar por versões de 8-bits daquelas que considero as melhores músicas do MegamanX (fora a do Boomer, que já tinha acabado de achar): Armored Armadillo e Storm Eagle (tem espaço pra música das Boss Battles, mas essa eu nem procurei, porque, sei lá, achei que talvez não ficasse boa uma versão em oito bits dela).

Como não achei uma versão que agradasse da música do Storm Eagle, postarei duas. Se eu juntasse o que tem de bom nas duas, a música ficaria ótima. Só uma ou só a outra não me agradou (lamento):





Só faltava uma: o Armored Armadillo. No meio da busca, encontrei o seguinte video, que achei PERFEITO. Me prestei a ir abrir a música original só pra me certificar de que a música era realmente 8-bits (no início, sério, não consegui distinguir). Mas, aí, quando abri a música original ficou bem óbvio. Aliás, pra quem não sabe onde achar a trilha do Megaman X no Youtube, eu sugiro que procure aqui (pra mim esse é o melhor canal pra se ouvir as músicas do jogo). Mas acho que essa informação todo mundo já tem, né?



De qualquer forma, meu objetivo principal era Armored Armadillo, no que achei essa versão aqui:



Achei o cara muito bom e, como entre os relacionados havia uma versão do Chill Penguin (outra música que me agrada horrores no jogo), resolvi clicar pra ver:



Como também gostei da música do Chill Penguin, resolvi entrar no canal do cara pra ver. Ele posta uns 4 videos por mês, todos com músicas usando o Famitracker. Deve ser meio vagabundo, pra ter tempo pra essas coisas, mas é realmente fantástico! Mas infelizmente pouquíssimos o conhecem: seus videos tem normalmente menos ou em torno de 1000 views. Assim, resolvi postar aqui e ver se alguém se interessa.

Para deixar um pouco mais interessante a coisa, posto o seguinte video, com uma música que há alguns dias já postei aqui: The Dreadful Battle (ou Battle with the Four Fiends, pra alguns).



EEE... por fim, só pra não deixar passar, deixo a música do Boomer em versão Mario Paint, que encontrei no meio da bagunça das minhas buscas. Sei que já chega de video, mas não queria perder a oportunidade.



Gostei do iniciozinho, com aquela abertura das fases que segue o padrão dos Megamans "normais" (ou seja, NOT(X)) e que só aparece no Megaman X: nos outros essa musiquinha se perdeu T_T

Enfim... era isso...

R$

Trilha de Chico Buarque

Não sei se já disse isso aqui antes, mas baixei a discografia do Chico Buarque.

(Já faço uma definição antes que me xinguem: ao longo do texto, chamo todos os álbuns de CD. Não faço distinção entre disco, CD, e o devil at four. Assim, pra mim, tudo vira CD, e é mais fácil tratar assim do que ficar cuidando a partir de quando foi que começou a sair discos por aí x_x)

Não digo que seja completa, mas, se não for, engana bem: tem MUITO CD pra ouvir. De todos os CDs, até agora conheci bem pouca coisa. Ouvi o primeiro, que já conhecia até que bem, e me agradei muito. Depois dele, vinha "Morte e Vida Severina", o qual ouvi bem pouco, porque não gostei: é bem diferente do que eu estou acostumado a esperar das músicas do Chico Buarque (conheço alguns sambas de outros CDs onde ainda não cheguei e nada é parecido com aquilo) e, sinceramente, nada contra, mas não me agrada em nada essa coisa de falar de nordeste, terra seca e tudo mais (me desculpe o leitor nordestino, se houver).

Por fim, cheguei ao terceiro CD da discografia, onde estou parado há alguns dias, conhecendo bem as músicas: Chico Buarque de Hollanda volume 2. No início admito que não gostei dessas músicas tanto quanto das do primeiro CD. Parecia que faltava a graça e a animação que aparecia naquelas músicas (e eu não via nessas). Mas, com o tempo, estou me agradando cada vez mais. Acho que estou aprendendo a ver essas características onde antes não enxergava. É muito bom, mas ainda tem muito pra conhecer. De qualquer forma, não posso deixar de sugerir ao leitor que ouça a algumas músicas e, quem sabe, comente o que achou =D

De tudo o que ouvi, sinceramente, isso foi o que mais ficou preso em minha mente (excluo "A Banda", a primeira musica do primeiro CD, porque ela é conhecida de todos, e eu já enjoei um pouco de tanto ouvir):




(notem como a partir da segunda vez em que ele começa a cantar essa música o instrumental começa a se assemelhar cada a vez mais àquele das músicas do The Sims 1)


Disparada, essa foi a música que eu mais gostei.


Essa pra mim é a que mais ficou presa na minha cabeça de todas as que ouvi (apesar de que eu acho que gosto mais de Pedro Pedreiro e de Ole Olá).


Pra mim, a música com a melhor letra, apesar de pequena =D


(não encontrei a música original, do CD do Chico Buarque mesmo, então me obriguei a pôr esse video, de outra gente cantando. Sinceramente, foi a melhor versão que eu achei, e até que é bem boinha. O certo é que eu não poderia deixar essa música passar, já que está há uns 3 dias presa na minha cabeça)

Enfim, a última música, aliás, era mais um desejo de bom carnaval (que acho que de certa forma já começa amanhã, sexta-feira denoite) a todos os leitores do blog, que não são muitos, mas, enfim...

R$