Entradas Recentes »

MobSym

O FoG está desenvolvendo um jogo de estratégia. Com influências de DotA e LoL, haverão monstros sendo criados a intervalos regulares (“mobs”). Porém, ao invés d’eles seguirem caminhos pré-definidos, o mapa será um grafo, onde cada vértice terá uma “plaquinha”, indicando que sentido os mobs deverão seguir ao chegar na bifurcação. Todos os mobs (aliados e inimigos) seguirão o mesmo sentido. Os jogadores (e somente eles) podem alterar o sentido das plaquinhas se chegarem próximo a ela e realizarem uma ação.

Para ter uma idéia de como isso iria ficar, fiz um simulador de mobs. Não faz muito sentido um screenshot (já que precisa de movimento para entender o que está acontecendo), mas vai lá…

 

Está em python + pygame, e você pode baixá-lo aqui. Juntamente, está um manual com as instruções atuais.

Nota: ainda não é possível remover vértices e arestas…

Feliz Natal!

Olá!!

Não exatamente do tema desse blog, mas tem algo que aprece programação, então vou deixar aqui. =)

Feliz Natal!

Feliz Natal pra você!

(clique para ver o tamanho original!)

Desenhado com uso do programa POVRay, um renderizador de imagem. É muito legal, pois você descreve a cena matematicamente, depois manda desenhar!

Se quiser o código para essa figura, pode obtê-lo aqui: ChristmasTree.pov .

Não tem presentes porque não deu tempo de fazê-los já passou o Natal e já levaram os presentes embora!

Então, Feliz Natal! \o/

Olá! Já faz um tempo que postei pela última vez, pois acabaram as aulas de monitoria. =)

Hoje vou escrever sobre (adivinhe!) Cinemática básica, isto é, como modelar matematicamente as posições dos objetos em movimento, iniciando o uso do blog com a finalidade original, que era passar um pouco sobre animações. Se quiser simplesmente ver o código (em python), clique aqui.

Relembrando

No colegial, os professores de física passam as equações de “Movimento Retilíneo Uniforme” e “Movimento Retilíneo Uniformemente Variado” – MRU e MRUV, respectivamente. O MRU é um caso particular do MRUV, onde a aceleração vale 0. Assim, deixo aqui apenas a do MRUV, que é mais genérica:

Equação Cinemática tempo completo

MRUV - Movimento Retilíneo Uniformemente Variado

A notação está em forma vetorial, para informar que as variáveis possuem módulo, direção e sentido. Para problemas de balística, o eixo X geralmente não possui aceleração e o eixo Y é afetado pela aceleração da gravidade. As equações do eixo X e Y, geralmente, são tratadas separadamente, para facilitar a resolução. Supondo uma velocidade inicial de lançamento de um objeto com componentes não-nulas tanto para o eixo x quando para o eixo y, e considerando uma aceleração da gravidade (geralmente negativa, pois a gravidade atrai para baixo e o eixo y cresce para cima), é possível notar uma trajetória parabólica para o objeto lançado. Essa equação fornece a posição a cada instante, considerando-se as condições ideais (sem atrito, sem resistência do ar, apenas a gravidade atuando etc) num tempo contínuo.

Em computação, contudo, o tempo não é contínuo, mas isso não chega a ser um problema na maioria dos casos: aproximando-se o suficiente do real é o bastante para que nossos olhos não notem a diferença.

Um modo equacionar o MRUV em computação é dada abaixo (trecho de código em python) , considerando-se que o tempo, na verdade, é o número do “frame” desde o início da simulação. Dessa forma, t = 1 significa o 1o. frame, t = 2 o segundo e assim por diante.

## Antes de iniciar:
 self.xs0 = self.posx
 self.ys0 = self.posy

 self.xv0 = v0 * math.cos(ang)
 self.yv0 = -v0 * math.sin(ang)    # o eixo y aumenta pra baixo; queremos que suba!

 self.xa = 0        # sem aceleracoes no eixo x
 self.ya = grav    # gravidade (para baixo!)

## A cada iteracao/frame
 self.posx = self.xs0 + self.xv0 * self.tempo + (self.xa * self.tempo * self.tempo / 2.0)
 self.posy = self.ys0 + self.yv0 * self.tempo + (self.ya * self.tempo * self.tempo / 2.0)
 self.tempo += 1

self seria o objeto a ser tratado; seus componentes indicam posição inicial x e y, velocidades iniciais x e y, acelerações x e y. self.posx e self.posy são as posições “naquele instante”, no frame número self.tempo .

Significado

Bom, mas o que significam a velocidade e aceleração? Elas são taxas de variação. A velocidade é a variação (derivada com relação ao tempo!) da posiçao e a aceleração a variação da velocidade. Elas dizem o quanto uma variável vai variar em um segundo. Então, por exemplo, uma velocidade de 3 para a direita significa que, daqui um segundo, a posição do objeto aumentou de 3 unidades para a direita (eixo x, geralmente). Da mesmforma, a aceleração diz quanto a velocidade varia em um segundo ou uma unidade de tempo (no caso aqui, um frame). Seguindo essa linha, é possível modelar esse movimento de modo iterativo, da seguinte forma:

Equações de forma iterativa

Cinemática iterativa para computação

Isso deve ser feito a cada frame da simulação, preferencialmente nessa ordem. A legenda: acel = aceleração; vel = velocidade, pos = posição e equação é uma equação que controla a aceleração. Como estamos exemplificando com MRUV, a aceleração deve ser constante. Assim, é possível modelar, digamos, uma partícula que sofre ação da gravidade, como:

# preparacao, valores iniciais
self.posx, self.posy = x, y      # posicao inicial
self.velx = v0 * math.cos(ang)   # velocidade inicial
self.vely = -v0 * math.sin(ang)
self.acelx = 0                   # aceleracoes; 0 em x
self.acely = grav

# A cada frame:
self.velx += self.acelx
self.vely += self.acely

self.posx += self.velx
self.posy += self.vely

Dessa forma, se a aceleração se mantiver sempre constante, haverá um MUV (movimento uniformemente variado, não mais necessariamente “retilíneo”). Essa forma gera uma trajetória parabólica bem próxima da obtida com a equação do tempo, mas sem precisar calcular um quadrado e uma divisão a cada frame, apenas somas. =)

Vantagens

Como se sabe, no mundo real (e nas simulações… e jogos!), a aceleração não será constante por muito tempo. É possível que ela varie, devido a vários fatores, “naturais” ou não (o jogador/usuário poderia alterar a aceleração dos objetos). Exemplos de “causas naturais” que modificariam a aceleração:

Exemplos de equações de aceleração

Exemplos de equações de aceleração

sendo g a aceleração da gravidade, b um coeficiente de resistência do ar (deve ter outro nome…), v_vento a velocidade do vento e mi o coeficiente de atrito dinâmico.

Dessas, apenas a de gravidade é um movimento uniformemente variado, já que mantém a aceleração constante. As demais (e existem muitas outras por aí!) não são uniformemente variados, são apenas variados. (… o que nos deixa com um Movimento Variado?).

Nesses casos, a aceleração teria um valor “setado”/”recalculado” a cada frame, fornecendo resultados interessantes. Mais ainda, todas essas equações podem ser simplesmente somadas, combinando seus efeitos, por serem equações lineares, oferecendo efeitos mais realistas.

Em código:

# resistência do ar, apenas (a cada frame)
self.acelx = -0.01 * self.velx    # a res. do ar eh uma forca proporcional a velocidade
self.acely = -0.01 * self.vely    # e atua em sentido contrario a ela

# vento, apenas (a cada frame)
self.acelx = -0.01 * (self.velx - self.ventox)    # mas, na verdade, depende da velocidade relativa
self.acely = -0.01 * (self.vely - self.ventoy)    # do objeto com relacao ao ar, que pode estar se movendo

Um outro caso interessante é utilizar as teclas pressionadas. Por exemplo, se as teclas A e D movem um bonequinho para a esquerda e direita, respectivamente, elas poderiam acelerar o boneco, dando-lhe uma inércia: ele não fica com velocidade máxima de uma vez assim que o usuário pressiona o botão. Uma equação típica para isso, utilizando pygame, é:

events = pygame.event.get()  # para atualizar o estado de tudo
teclas = pygame.key.get_pressed() # para determinar o estado de cada tecla
self.acelx = (teclas[K_d] - teclas[K_a]) * aceleracao - 0.1*self.velx # para acelerar o objeto no eixo x
self.acely = (teclas[K_s] - teclas[K_w]) * aceleracao - 0.1*self.vely # para acelerar o objeto no eixo y
# depois, somar a aceleracao na velocidade e a velocidade na posicao

É importante ter o “limitador” dele, essa “resistência de ar“, para que o objeto não acelere infinitamente. Essa resistência de ar limita a velocidade, fazendo o objeto tender a uma determinada velocidade: a chamada velocidade terminal. Se, por algum motivo, o objeto estiver acima dessa velocidade terminal, a resistência do ar fará com que a velocidade reduza até a terminal. Caso deseje-se calcular a velocidade terminal:

Velocidade Terminal

Fórmula para Velocidade Terminal

Mas, por que isso é uma vantagem? Bom, tente fazer uma equação como a do primeiro caso (dependente do tempo) que modele esses efeitos. =P Boa sorte! Além disso, modelar de forma que um efeito possa ser “ligado ou desligado” a qualquer hora (como quando um botão for pressionado pelo usuário) torna-se bastante complexo com a equação do tempo, mas praticamente não muda o outro método.

Finalizo deixando um código em python para ilustrar a diferença desses vários efeitos nas trajetórias balísticas.

Códigos: Cinemática Balística (Python)

Oi!

Segunda feira agora (14/06) será a prova final da disciplina de ICC1. Talvez esteja um pouco tarde para isso, mas deixo aqui um código fonte com, acredito que, todos os conceitos necessários para o fim da disciplina. O código não possui comentários (na verdade, tem UM, com uma pergunta…), e a ideia é que compreendam o código assim mesmo. Os nomes das funções e variáveis são uma dica do que cada coisa faz em linhas gerais, mas o objetivo é que entendam o que está acontecendo em cada linha/bloco.

Dúvidas enviadas aqui ou por serão respondidas o mais breve possível e, na monitoria, uma revisada rápida em cima deste código.

Nele, há uma parte com cadastros de alunos (Nome, Nusp, nascimento e notas) que pode ser gravado em arquivo ou lido dele. Para auxiliar, aqui tem um exemplo de arquivo que esse programa abre. Mas, claro, pode criar o seu, se quiser. Este contém 10 alunos (com pessoas famosas, inclusive).

Perguntas:

  1. O código apresenta vetores ou matrizes com alocação estática? Se sim, onde?
  2. O Código apresenta vetores ou matrizes com alocação dinâmica? Se sim, onde?
  3. Existem ponteiros nesse código? Ponteiros para ponteiros?
  4. O código apresenta funções com passagem por valor? Se sim, onde?
  5. O código apresenta funções com passagem por referência? Se sim, onde?
  6. Há geração de números aleatórios? Se sim, onde?
  7. Há definições de tipo? Se sim, onde?
  8. Há uso de laços nesse código? Se sim, onde?
  9. Qual o papel desempenhado pela funcao_misteriosa1() ?
  10. Qual o papel desempenhado pela funcao_misteriosa2() ?
  11. Por que o arquivo alunos.txt é ilegível se é um .txt ? Ele foi gravado como binário?

Boa sorte! o/

Arquivos:

Não poderei fundamentar muitas coisas hoje, fica como pendente por enquanto.

Hoje, fizemos um código mais ou menos igual a outros que já foram feitos anteriormente, de cadastros de alunos, mas, dessa vez, usando funções e passagens por referências. Como pedido, o código feito em aula, com algumas alterações (e comentários sobre as alterações) segue abaixo.

Código:

PS: lembrem-se de dar free nos vetores alocados!

Funções com passagem de parâmetros por referência

Conceitos:

  • funcões;
  • ponteiros;

Ponteiros são estruturas muito utilizadas em C. O que eles apontam são posicoes da memória. Como é na memoria que os dados sao armazenados, mostram-se ferramentas úteis para manipulação de dados.
Um de seus usos eh realizar alocação dinâmica de memória. Outro uso é a passagem de parametros por referência, demonstrado neste código.

Quando uma função recebe um parâmetro por referência, isso é indicado com um “*” entre o tipo e o nome da variável.
Por exemplo:

 void referencia(int *pri, int *seg) { ... }

Aqui, indica-se que “pri” e “seg” são ponteiros para inteiros.
O significado disso é que pri e seg “referenciam” (“apontam”), cada um, uma determinada posição da memória.
Cada variável de uma função possui um endereco. Para saber onde uma variável está alocada, utiliza-se o operador “&”.
Assim, para chamar a função “referencia”, deve-se passar um endereco.

 int main() {
     int a, b;
     ...
     referencia(&a, &b);
     ...
 }

pois “&a” é o endereco de a e “&b” o de b. E é isso que “pri” e “seg” devem receber – endereços!

Para dizer “o conteudo apontado por um ponteiro”, utiliza-se um asterisco antes do nome da variável.

 *pri = 3; // faz o endereco apontado por "pri" receber o valor 3.

Para evitar ambiguidades, convém separá-lo por parênteses. (Não achei um caso ambiguo útil, mas, no minimo, fica mais claro para ler se separar por parênteses… )

 (*pri) = 3;

Quando se utiliza o ponteiro dessa forma (com o asterisco), a posição apontada pelo ponteiro eh afetada, não o ponteiro.

Códigos:

Esta semana que passou, o assunto das aulas foram Funções com passagem de parâmetros por valor. Isto significa que os valores passados para as funções são copiados para as funções antes de serem utilizados. Como são cópias, modificações nas variáveis locais (isto é, que existem na função) não afetam as variáveis fora dessa função. Assim, por exemplo:

int funcao(int n){
    n = n*3;
    printf("Valor de n: %d\n", n);
    return n;
}

int main(){
    int n, m, p;
    n = 2;
    m = funcao(n);
    p = funcao(m);
    printf("n = %d; m = %d; p = %d\n", n, m, p);
}

Esse exemplo ilustra que a variável com nome “n” da função não tem relação “física”, digamos, com a variável n da main. Na linha

m = funcao(n);

o valor n da main está sendo passado para funcao . Explicação passo a passo:

  1. O VALOR de n da main é copiado para o n de funcao.
  2. funcao altera o valor de n e retorna.
  3. m recebe o valor de retorno (ou seja, n).

Observe que, na segunda chamada da função, algo semelhante ocorre, mas passa-se o valor de m para a função e o retorno (seu “resultado”) é armazenado em p.

No cabeçalho da função “funcao”, está dizendo que ela é “int”, ou seja, seu valor de retorno é “int”. Por isso, a variável de retorno, n, é um inteiro.

Existem funções cujo tipo é “void“. Essas funções retornam nada (ou seja, “não retornam”), não precisando de um return. É o caso de funções para, por exemplo, apenas mostrar texto (como um menu) ou fazer algo que não possui um “valor”. (Se não me engano, funções void também são chamadas de “procedimentos”, mas não tenho certeza.).

void menu(){
    printf("Opcao 1: mudar regras da disciplina\n");
    printf("Opcao 2: cadastrar aluno\n");
    printf("Opcao 3: gravar em disco estado atual\n");
    printf("Opcao 4: sair do programa\n");
}

Note que, mesmo sem retornar, ela pode receber parâmetros. Por exemplo, para imprimir todos os dados de uma variável que foi definida pelo usuário (aluno, por exemplo). A linguagem C não sabe “imprimir” os valores, cabendo ao programador determinar como imprimir os valores. Há um exemplo disso neste código, a função imprime_vetor(vetor v).

Dentro dos parênteses estão os parâmetros da função. No exemplo, o parâmetro é o n, uma variável do tipo int. Parâmetros são variáveis e sua declaração é feita ali mesmo no cabeçalho, ou seja, podem ser usadas como variáveis normalmente. Comandos como, por exemplo, “n++” são válidos e, de fato, incrementam o valor de n. Assim, se esse n possui alguma informação importante para a função e que não deve ser alterada, não o altere! No exemplo, n = n*3 altera o valor de n.

Os parâmetros de funções podem ser de qualquer tipo e a ordem em que são passados é importante. Por exemplo (exercício 2 da lista 10):

int potencia(int x, int y){ // retorna x elevado a y
    int r = 1;
    while(y > 0){
        r = r * x;
        y--;
    }
    return r;
}

Essa função potência recebe como parâmetro 2 valores: primeiro um inteiro x e depois um inteiro y. Internamente, calcula x elevado a y. Aqui, x e y precisam ser inteiros, e o resultado também é inteiro. Se y for negativo, o resultado será 1. E (comportamento estranho, porém esperado… acho. =P ) 0 elevado a 0 = 1.

Note que… potencia(2, 3) é diferente de potencia(3, 2). Por isso, a importância da ORDEM em que os parâmetros são passados.

Uma função pode receber argumentos de tipos diferentes:

double potencia(double x, int y){ // retorna x elevado a y, agora com y podendo ser negativo,
                                  // mas ainda inteiro; x pode ser real.
    double r = 1.0;
    while(y > 0){
        r = r * x;
        y--;
    }
    while(y < 0){
        r = r / x;
        y++;
    }
    return r;
}

Aqui, note que potencia (7, 1.5) não seria algo válido, já que y deve ser inteiro e 1.5 é real. O 7 ser inteiro não chega a ser um problema, pois 7 também é real. Se tentar compilar algo assim, o compilador deve reclamar, dizendo que “o tipo do argumento 2 da chamada é incompatível com o tipo do argumento 2 esperado“.

Funções também podem não receber nenhum parâmetro (novamente, o “menu” é um bom exemplo, já que ele sempre escreve a mesma coisa).

Os tipos de parâmetros e de retorno pode ser, inclusive, tipos definidos pelo programador, como pode ser visto neste código. Porém, se for esse o caso, lembre-se de que o C não sabe fazer operações como “+” ou “-” de tipos definidos pelo usuário. Assim, nesse código aí, existe uma função que “subtrai” as coordenadas de um ponto de outro ponto, coordenada a coordenada e esse resultado é que é retornado. Fazer um que some ou multiplique seria análogo.

Outra coisa importante: o valor de retorno nem sempre é um “resultado”. Pode ser um “código” que informe o programador sobre alguma coisa. Por exemplo, a função scanf retorna um número: o número de valores lidos com sucesso. Se retornar EOF, significa que não conseguiu ler nenhum valor. Porém, algumas vezes, essa informação não é desejada e pode não ser usada (que é a forma mais comum de usar o scanf, mesmo). Outros exemplos típicos são funções que podem dar certo ou não, retornando 0 se der tudo certo ou 1 se der errado. A função malloc retorna NULL se não conseguir alocar o espaço (portanto, o ideal seria verificar se o ponteiro não é igual a NULL antes de usá-lo depois do malloc). Se várias coisas podem dar errado, cada tipo de erro pode retornar um valor diferente (exemplo: 0 = sem erros; 1 = não conseguiu alocar espaço; 2 = não existe o arquivo que está tentando abrir etc.).

Com tantas opções, o que não ocorre, no entanto, é uma função de C retornar mais de um valor. Pelo menos, não dessa forma. O próximo tópico, passagem de argumentos por referência, trata disso, com o uso de ponteiros.

Códigos:

Olá!

Desculpem a demora, esses dias foram muito corridos. =P Ainda não consegui preparar o material explicando (com desenhos!) sobre ponteiros e um código mais didático para explicá-lo.

Na semana passada, dia 14/05, poucos haviam começado a fazer a lista número 9, sobre alocação dinâmica de memória. O exercício desenvolvido em sala foi o exercício 1, que apenas pedia para alocar espaço na memória para determinados tipos e quantidades de dados. Esta solução foi parcialmente implementada em sala e revisada antes de ser colocado aqui. Há algumas coisas a mais, para, além de alocar o espaço, usá-los pelo menos em parte, para mostrar como devem ser usados.

Na última monitoria (segunda, 17/05), fizemos alguns exercícios de alocação dinâmica de memória e alguns usos. Uma aluna pediu para resolver o exercício para entregar do dia 11 (?), que pedia para ler um arquivo, cadastrando n produtos e escrevendo-os em outro arquivo. Este código faz isso, abrindo o arquivo entrada.txt, lendo-o e escrevendo um arquivo saida.txt. Há um trecho comentado que permite que o usuário mesmo digite os dados de entrada, caso prefiram. Aguardem por uma atualização desse post aqui (e do anterior… aaaaahhhhh!!!! XD )

Códigos:

[AVISO]: Este post será editado assim que possível, explicando melhor tudo!

[AVISO2]: Este post foi levemente modificado, adicionando-se este código, com o exerício 4 da lista, resolvido em 10/05/2010.

Monitoria sobre “struct” e “typedef”. Fizemos os primeiros exercícios da lista 8, que pediam para criar um “comprimisso” com data e horário. As datas deveriam ser compostas de dia, mês e ano; os horários de hora, minuto e segundo. O compromisso também deveria ter uma descrição. Outros exercícios foram para utilizar essas estruturas criadas. A solução final está aqui.

Além de criar a estrutura, o código faz com que dados sejam lidos,  gravados em arquivo, lidos do arquivo (para outra variável) e exibidos os dados na tela.

Mais uma vez, as funções de scanf e printf foram usadas de forma não-tão-trivial, permitindo seu uso de forma sofisticada (lendo “:” ou escrevendo tudo sem espaços e fazendo o código ler assim mesmo).

A idéia do struct é agrupar dados referentes à mesma “coisa” num único bloco. Por exemplo: ao invés de separar as informações em vetores distintos (um para nUSP, outro para notas, uma matriz para nomes) e fazer que “a posição 2 de todos os vetores referem-se à mesma pessoa”, o struct permite criar um bloco chamado “pessoa”, que têm as informações daquela pessoa dentro dele, facilitando seu manuzeio.

O typedef define um novo “tipo” (tais como “int”, “char”, “float”) para ser escrito de forma mais compacta. Então, as duas formas abaixo são equivalentes:

struct{ // note que NÃO TEM typedef aqui...
    int hora;
    int minuto;
    int segundo;
}horario;

int main(){
    // note que aqui, é necessário deixar explícito o struct horario.
    struct horario h1, h2;
    ...
} 

OU

typedef struct{ // aqui, tem o typedef
    int hora;
    int minuto;
    int segundo;
}horario;

int main(){
    // e aqui, nao precisa dizer "struct"
    horario h1, h2;
    ...
}

Mas, se for conveniente, é possível utilizar o typedef de outra forma. Suponha que será feito um programa que use vetores (de G.A.) para fazer alguma conta… um produto vetorial, por exemplo. Todos os “vetores” deverão ter 3 informações (coordenadas x, y e z). Assim, ao invés de fazer toda hora algo como

float ponto_a[3], ponto_b[3], ...

é possível fazer o seguinte:

typedef float ponto[3];
ponto a, b;

e “a” e “b” são do tipo ponto, que é um vetor de tamanho 3 do tipo float.

Código:

O professor deixou na página a lista 7 de exercícios, sobre arquivos em C. Arquivos são formas de armazenar informações de forma não-volátil, isto é, informações que não se perderão quando o programa terminar.

A função para abrir arquivos é a fopen(nome, modo) e deve-se sempre lembrar de fechar o arquivo, com fclose(x). arquivos podem ser abertos em modo texto ou modo binário. Abaixo, exemplos de uso de algumas funções de arquivos. Em cplusplus.com, há referências para essas funções de arquivos. As principais são fopen, fclose, fread, fwrite, fscanf, fprintf, fgets e fputs. O uso da fprintf e fscanf são muito parecidos com o printf e scanf normais, adicionando-se um parâmetro (o arquivo a ler/escrever) ANTES das  aspas.

Abaixo, alguns exemplos de utilizações das principais funções:

FILE *arqtxt, *arqbin; // ponteiro para arquivo a ser usado
char nome[80];
char linha[80];

arqtxt = fopen("dados.txt", "w"); // modo de leitura (w) do arquivo dados.txt.
                                  // atenção com as aspas do modo.
strcpy(nome, "arquivo_de-dados.bin");

/* abrir para leitura em modo binário */
arqbin = fopen(nome, "rb"); // o arquivo com esse exato nome deve existir.

fscanf(arqbin, "Nome: %[^n]s ", linha); // Le "Nome: " e o que vier
                                        // DEPOIS (até \n) fica armazenado em linha
sprintf(arqtxt, "Nome lido: %s\n", linha) // escreve o nome lido no txt

Este código contém mais exemplos de como usar as funções de ler e escrever em arquivos.

Importante: Nos nossos exemplos, sempre usamos arquivos com extensão .txt ou .bin , podendo passar a idéia errada de que “arquivo” em C só pode ser com essas extensões. NÃO É. pode-se usar qualquer extensão (programa.c, imagem.jpg, …) para abrir um arquivo. Isso porque, no fundo, tudo são bytes e essas funções lêem bytes. A questão é que se abrir um arquivo .gif, por exemplo, e mandar imprimir na tela, haverão diversos caracteres ilegíveis e que podem não fazer sentido algum. Como texto, aqueles caracteres (bytes) não significam nada. Mas, lidos de forma adequada, representam uma imagem, por exemplo; um arquivo de audio, um filme. É possível escrever num arquivo e salvá-lo como .bmp, por exemplo, mas, ao tentar visualizá-lo, se ele não estiver escrito de uma certa forma, seu programa vai dizer “imagem não disponível” ou algo assim, e não será possível “ver” seu arquivo dessa forma.

Experiência: abra uma imagem com um bloco de notas (no Windows: clique com o botão direito -> abrir com… -> Bloco de Notas ) e veja o que acontece!

O desafio 1 da lista foi resolvido, lendo-se e escrevendo-se caractere por caractere do arquivo de entrada para o de saída. Se encontrar um “<”, não o escreve no arquivo de saída e marca uma “flag” como 1. Enquanto essa flag for 1, só leia do arquivo de entrada, mas não escreva nada na saída. Quando com, essa flag == 1, encontrar um “>”, não o escreve e muda o estado da flag para 0. Dessa forma, as tags de html (que ficam sempre escritas entre “<” e “>” ) desaparecerão do texto na saída. =) Como exemplo de código html, o código da página sobre HTML da Wikipédia.

Códigos:

Blog no WordPress.com. | Tema: Motion até volcanic.
Seguir

Obtenha todo post novo entregue na sua caixa de entrada.