segunda-feira, 22 de dezembro de 2008

Uma mensagem de encerramento de mais um ano

Rodem o código e vejam a mensagem.

#include <stdio.h>
void PrintBitMap( unsigned long long int bitmap ){
    if ( bitmap > 1ULL ) PrintBitMap( bitmap / 2ULL );
    printf("%c", ( bitmap % 2ULL ) ? '*' : ' ');
}
unsigned long long int bitmap[13] = {  
    0x1000000000000000LL, 0x10000000114447CELL,
    0x100000001B444111LL, 0x1000000015444111LL,
    0x1000000011444111LL, 0x100000001138410ELL,
    0x1000000000000000LL, 0x100039E78438E78ELL,
    0x1000451444411451LL, 0x100045E7847DF451LL,
    0x1000451504451451LL, 0x100039E48439178ELL,
    0x1000000000000000LL 
};
void main(){
    for (int i=0; i<13; i++) {
        PrintBitMap( bitmap[i] );
        printf("\n");
    }
    fflush(stdin);
    getchar();
}

Até a próxima.

sábado, 22 de novembro de 2008

Matrizes e Vetores Equivalentes

O código a seguir apresenta a técnica de alocação dinâmica de vetor (matriz linha ou matriz coluna) na linguagem de programação C. Foi usado o Borland C-Builder 6.

O usuário poderá definir o tamanho de uma matriz bi-dimensional e em seguida fornecer os valores para cada elemento, que neste estudo de caso é do tipo inteiro.

A função "sizeof(int)" retorna o tamanho em bytes para cada elemento da matriz[m][n].

Com a função "malloc( m * n * sizeof( int ) )" são alocados bytes na memória RAM suficientes para armazenar a quantidade de elementos ( int ) que compõem a matriz[m][n]. Esta função retorna um ponteiro do tipo (void*) sendo necessária a conversão para ponteiro do tipo (int*).

Para a entrada de dados, o algoritmo percorre de maneira bi-dimensional a matriz[m][n], sendo necessária a conversão dos índices m e n para a posição efetiva no vetor:

posição no vetor = t * n + u

onde:

t : linha corrente na matriz[m][n]

u: coluna corrente na matriz[m][n]

n : quantidade de colunas por lina na matriz[m][n]

Na segunda parte do código, o algoritmo percorre linearmente o vetor de dados que armazena a matriz[m][n] desejada, e para informação é calculada de maneira inversa os índices correntemente sendo impressos:

v = t / n (divisão inteira)

w = t % n (resto de divisão inteira)

onde:

t : posição corrente no vetor

n : quantidade de colunas por linha na matriz[m][n]

v : linha corrente da matriz[m][n]

w : coluna corrente da matriz[m][n]

Antes de analisar o código, acompanhe o diagrama de blocos a seguir:

Diagrama1

Agora temos o código na linguagem C:

//---------------------------------------------------------------------

#pragma hdrstop

//---------------------------------------------------------------------

/*

    Alocação dinâmica de memória

    Estudo de caso: matrizes e vetores equivalentes

    malloc, free, fflush, printf, scanf

*/

#include <stdio.h>
#include <stdlib.h>

#pragma argsused
int main(int argc, char* argv[])
{
    int *A;

    int m, n, c, t, u, valor;

    printf("Matriz A[m][n]:\n");

    fflush(stdin);

    printf("Digite valor de m:");
    scanf("%d",&m);

    printf("Digite valor de n:");
    scanf("%d",&n);

    // Alocar recurso de memória RAM ----------

    c = m * n;

    A = (int*) malloc( c * sizeof( int ) );

    // ----------------------------------------

    if ( A == NULL )
    {
        printf("\n\nErro ao alocar memoria RAM!!!\n");
        printf("\n\nTecle ENTER para encerrar");
        fflush(stdin);
        getchar();
        return 1;
    }

    printf("\nDigite os elementos da matriz A[%d][%d]\n", m, n);

    for ( t=0; t<m; t++ )
    {
        for ( u=0; u<n; u++ )
        {
            printf("Digite elemento[%d][%d]:", t, u);
            scanf("%d", &valor);

            A[ t * n + u ] = valor;

        }
    }

    printf("\n\nMatriz A[%d][%d]:\n", m, n);

    for ( t=0; t<c; t++ )
    {
        printf("\nA[%d][%d]=%d", (t / n), (t % n), A[t]);
    }

    printf("\n\nTecle ENTER para encerrar");

    fflush(stdin);
    getchar();

    // Liberar recurso de memória RAM -----

    free(A);

    // ------------------------------------

    return 0;
}
//---------------------------------------------------------------------

 

Links sugeridos para outros esclarecimentos:

http://www.ime.usp.br/~pf/algoritmos/aulas/aloca.html

http://en.wikipedia.org/wiki/Malloc

http://cplus.about.com/od/learningc/ss/pointers_7.htm

http://informatica.hsw.uol.com.br/programacao-em-c29.htm

 

Cópias de tela da execução do código aqui apresentado:

teste

teste2

Para estudo, desenvolver uma aplicação para multiplicar duas matrizes bi-dimensionais:

C[m][j] = A[m][n] . B[i][j]

restrições:

  • n igual a i
  • m, n, i, j maiores que zero

Links com fundamentos matemáticos para multiplicação de matrizes:

 

Bom estudo e até a próxima.

sexta-feira, 3 de outubro de 2008

Código em C para ler código de tecla pressionada

As funções getch() e kbhit() da biblioteca CONIO proporcionam funcionalidades para monitoramento de teclas pressionadas, permitindo obter o código da tecla sem precisar aguardar que o usuário pressione ENTER, como ocorre com a getchar() padrão.

 

//---------------------------------------------------------------------------

#pragma hdrstop

#include <stdio.h>      // printf

#include <conio.h>      // kbhit, getch

//---------------------------------------------------------------------------

#pragma argsused
int main(int argc, char* argv[])
{
    int keycode, normalkey;

    while ( keycode != 27 )         // ESCAPE
    {


        // aguardar uma tecla ser pressionada
        while ( ! kbhit() ) ;

        // ler o código da tecla pressionada
        keycode = getch();

        // keycode = 0 se for tecla especial
        normalkey = keycode;

        // se tecla especial,
        // pegar o próximo código para identificar a tecla pressionada
        if ( !normalkey )
            keycode = getch();

        if      ( normalkey && keycode >= 48 && keycode <= 57 )
            printf("\nteclou digito %c = %d = valor decimal %d",
                    keycode, keycode, (keycode - 48) );

        else if ( normalkey && keycode >= 65 && keycode <= 90 )
            printf("\nteclou letra maiuscula %c = %d",
                    keycode, keycode);

        else if ( normalkey && keycode >= 97 && keycode <= 122 )
            printf("\nteclou letra minuscula %c = %d",
                    keycode, keycode);

        else if ( !normalkey && keycode >= 59 && keycode <= 68 )
            printf("\nteclou F%1d = %d",
                    (keycode - 58), keycode);

        else if ( !normalkey && keycode >= 133 && keycode <= 134 )
            printf("\nteclou F%2d = %d",
                    (keycode - 122), keycode);

        else if ( normalkey && keycode == 27 )
            printf("\nteclou ESCAPE = %d", keycode);

        else if ( normalkey && keycode == 8 )
            printf("\nteclou BACKSPACE = %d", keycode);

        else if ( normalkey && keycode == 9 )
            printf("\nteclou TAB = %d", keycode);

        else if ( normalkey && keycode == 13 )
            printf("\nteclou CARRIAGE-RETURN (ENTER) = %d", keycode);

        else if ( normalkey && keycode == 10 )
            printf("\nteclou LINE-FEED (CTRL-ENTER) = %d", keycode);

        else if ( !normalkey && keycode == 75 )
            printf("\nteclou SETA A ESQUERDA = %d", keycode);

        else if ( !normalkey && keycode == 77 )
            printf("\nteclou SETA A DIREITA = %d", keycode);

        else if ( !normalkey && keycode == 72 )
            printf("\nteclou SETA PARA CIMA = %d", keycode);

        else if ( !normalkey && keycode == 80 )
            printf("\nteclou SETA PARA BAIXO = %d", keycode);

        else if ( !normalkey && keycode >= 82 && keycode <= 83 )
            printf("\nteclou %s = %d",
                    (keycode == 82 ? "INSERT\0" : "DELETE\0"), keycode);

        else if ( !normalkey && keycode == 71 )
            printf("\nteclou HOME = %d", keycode);

        else if ( !normalkey && keycode == 79 )
            printf("\nteclou END = %d", keycode);

        else if ( !normalkey && keycode == 73 )
            printf("\nteclou PAGE-UP = %d", keycode);

        else if ( !normalkey && keycode == 81 )
            printf("\nteclou PAGE-DOWN = %d", keycode);

        else
            printf("\nteclou %c = %d (%s)",
                    keycode, keycode, (normalkey ? "normal\0" : "especial\0") );
    }

    return 0;
}
//---------------------------------------------------------------------------

 

Com o código acima, espero ter apresentado dicas para os exercícios propostos em sala de aula.

 

Bom estudo e até a próxima.

quarta-feira, 1 de outubro de 2008

Trabalhando com cadeias de caracteres (strings)

O código apresentado a seguir foi escrito em C e se propõe a demonstrar o uso de cadeias de caracteres.
A aplicação é bastante simples, envolvendo uma lista de nomes de frutas previamente estabelecida e a interação com o usuário para que este faça uma consulta.
Dado um nome de fruta, o algoritmo fará uma busca seqüencial na lista a partir do primeiro elemento.
Se o nome for localizado, será indicado em qual posição da lista e o nome apresentado com efeito especial: letra por letra pausadamente e com barulho de máquina de datilografia.

O programa foi testado na plataforma MS Windows XP e Borland C Builder.

//---------------------------------------------------------------------------
#pragma hdrstop
//---------------------------------------------------------------------------

#include <stdio.h>      // printf, scanf, fflush
#include <windows.h>    // Sleep, Beep

#define MAX_FRUTAS 5
#define MAX_COMPR 12

#pragma argsused
int main(int argc, char* argv[])
{

        char frutas[MAX_FRUTAS][MAX_COMPR] =
                {
                        { 'a', 'b', 'a', 'c', 'a', 'x', 'i' },
                        { "mamao" },
                        { "laranja" },
                          "banana",
                          "kiwi"
                };


        char nome[MAX_COMPR];

        int i, j;

        printf("\nDigite um nome de fruta: ");

        scanf("%s", nome);

        printf("\nVoce digitou %s", nome);

        // Pesquisa do nome na lista

        for (i=0; i<MAX_FRUTAS && strcmp( frutas[i], nome ) ; i++) ;

        if ( i == MAX_FRUTAS )
        {
                printf("\nNome nao catalogado");
        }
        else
        {
                printf("\nLocalizada em %d", i);
                printf("\n\n");

//              for (j=0; j<MAX_COMPR && frutas[i][j] != '\0'; j++)
                for (j=0; j<MAX_COMPR && nome[j] != '\0'; j++)
                {

//                      putchar( frutas[i][j] );
                        putchar( nome[j] );

                        Beep(3700, 5);  // frequencia (Hz), duracao (s)
                        Beep(300,2);
                        Beep(80,8);

                        Sleep(500);     // hibernar (ms)

                }
        }

        fflush( stdin );        // limpar buffer da entrada padrão
        getchar();

        return 0;

}
//---------------------------------------------------------------------------

 

Bom estudo e até a próxima.

segunda-feira, 22 de setembro de 2008

Código C do Programa de Estatística

 

O programa aqui apresentado foi escrito com base nos diagramas de blocos comentados em sala de aula. Este código foi testado nas plataformas Borland C Builder e Linux GCC.

//---------------------------------------------------------------------------
//    Estatistica.c
//    Josimar Nunes de Oliveira
//    20/Set/2008
//---------------------------------------------------------------------------

#pragma hdrstop

// bibliotecas referenciadas

#include <stdio.h>   // printf, scanf, getchar
#include <math.h>    // pow, sqrt
#include <string.h>  // strcmp

// constantes figurativas

#define MAX     5000        // capacidade máxima de dados
                            // para o array de termos da amostra

#define BATCH   "--batch"   // parâmetro de execução do programa:
                            // lote ou interativo

// criando macro definições

#define RaizQuadrada(x) sqrt(x)
#define Potencia(x,y) pow(x,y)

#pragma argsused

int main(int argc, char* argv[])
{
    // declaração de variáveis locais da função "main"

    int proc_interativo;

    int a[MAX], vmin, vmax, s, i, n, q;

    float vmed, ss, dp;

    // verificar argumentos de execução do programa

    proc_interativo = 1;
    if ( argc > 1 )
    {
        if ( strcmp(argv[1], BATCH) == 0 && argc == 2)
        {
            proc_interativo = 0;
        }
        else
        {
            printf("\n\nSintaxe:\n\n");
            printf("\t./progteste [--batch] [< arqentrada] [> arqsaida]\n\n");
            // término prematuro -- erro de sintaxe
            return 1;
        }
    }

    // entrada do parâmetro "n"

    if ( proc_interativo )
    {
        printf("\n\nInforme qual o n-ésimo termo: ");
    }
    scanf("%d", &n);

    // validar o parâmetro "n" fornecido pelo usuário

    if (n >= MAX)
    {
        if ( proc_interativo )   
        {
            printf("\n\nErro: excedeu capacidade do programa!!!\n\n");
        }
        // término prematuro do programa -- erro de capacidade
        return 2;
    }

    // quantidade de termos na amostra
    q = n + 1;

    // entrada dos termos { a0, a1, a2, ..., aN }
    // e armazenagem em array

    for (i=0; i<=n; i++)
    {
        if ( proc_interativo )
        {
            printf("\nDigite o valor[ %d ] : ", i);
        }
        scanf("%d", &a[i]);
    }

    // obtenção dos termos de valores mínimo e máximo
    // usando o primeiro elemento "a[0]" como referência

    vmin = a[0];
    vmax = a[0];

    for (i=1; i<=n; i++)
    {
        if ( a[i] < vmin )
        {
            vmin = a[i];
        }
        if ( a[i] > vmax )
        {
            vmax = a[i];
        }
    }

    // obter somatório dos termos

    s = 0;

    for (i=0; i<=n; i++)
    {
        s = s + a[i];
    }

    // cálculo da média aritmética

    vmed = (float)s / (float)q;

    // obter somatorio dos quadrados da diferença entre termos e média

    ss = 0;

    for (i=0; i<=n; i++)
    {
//      ss = ss + pow( (double)((float)a[i] - vmed), 2);
        ss = ss + Potencia( (double)((float)a[i] - vmed), 2);
    }

    // medida estatística denominada "variância"

    ss = ss / (float)q;


    // cálculo da medida estatística "desvio padrão"

//  dp = sqrt(  ss );
    dp = RaizQuadrada( ss );

    // saída dos cálculos

    printf("\n\nResumo Estatistico\n");

    printf("\nQuantidade de termos: %d", q    );
    printf("\nSomatorio dos termos: %d", s    );
    printf("\nValor minimo........: %d", vmin );
    printf("\nValor medio.........: %f", vmed );
    printf("\nValor maximo........: %d", vmax );
    printf("\nVariancia...........: %f", ss   );
    printf("\nDesvio padrao.......: %f", dp   );

    printf("\n\n\nListagem da Amostra\n");

    for ( i=0; i<=n; i++ ) 
    { 
        printf("\nTermo[ %04d ] = \t%d", i, a[i]); 
    }

    printf("\n\n");

    // aguardar usuário teclar ENTER em modo interativo

    getchar();
    getchar();

    // término normal do programa

    return 0;

}

No caso do Linux GCC, a linha de comando usada para compilação é:

gcc progteste.c -o progteste -lm

Nos próximos posts irei estender comentários de partes deste programa. Por enquanto apenas publiquei o código desenvolvido em sala de aula para servir de referência para construção de novos programas.

A seguir temos uma cópia de tela da execução no modo "batch":

proc

Até mais.

sábado, 30 de agosto de 2008

Exercício da intersecção entre duas equações de 2º grau

Diagrama de blocos construído com o software DIA:

 

Diagrama1

A ferramenta de apoio DIA pode ser obtida em:

http://downloads.sourceforge.net/dia-installer/dia-setup-0.96.1-8.exe

 

 

A seguir temos o algoritmo escrito em "portugol" nativo do software VISUALG:

 

algoritmo "intersecção"
// Função :
// Autor :
// Data : 29/08/2008
// Seção de Declarações
var
a, b, c, d, eh, f, i, j, k, delta, x, x1, x2 : real
Resp : caracter

inicio
// Seção de Comandos
escreva("Digite a primeira equação:")
leia(a, b, c)
escreva("Digite a segunda equação:")
leia(d, eh, f)
se ( a = 0 ) ou ( d = 0 ) entao
   Resp <- "Equações inválidas"
senao
   i <- ( a - d )
   j <- ( b - eh )
   k <- ( c - f )
   se ( i = 0 ) entao 
      se ( j = 0 ) entao
         se ( k = 0 ) entao
            Resp <- "Qualquer x Real"
         senao
            Resp <- "sem solução Real"
         fimse
      senao
         x <- ( - k / j )
         Resp <- "X = " + Numpcarac( x ) 
      fimse
   senao
      delta <- ( j ^2 - 4 * i * k )
      se ( delta < 0 ) entao
         Resp <- "sem solução Real"
      senao
         se ( delta = 0 ) entao
            x <- ( -j / 2 * i )
            Resp <- "X = " + Numpcarac( x )
         senao
            x1 <- ( ( -j + raizq( delta ) ) / 2 * i )
            x2 <- ( ( -j - raizq( delta ) ) / 2 * i )
            Resp <- "X1 = " + Numpcarac( x1 ) + "   X2 = " + Numpcarac( x2 )
         fimse
      fimse
   fimse
fimse
escreva( Resp )
fimalgoritmo

 

 

VisuAlg pode ser obtido em:
http://www.apoioinformatica.inf.br/

E seu manual em:

http://hermes.ucs.br/carvi/cent/dpei/haklauck/algoritmos/Linguagem_Visualg2.0.pdf

 

Bom estudo e até a próxima.

sábado, 23 de agosto de 2008

Linguagem C - variáveis tipo "int"

 

Vejam teste utilizando Microsoft Visual Studio 2008 C++ 9.0 para demonstrar o tamanho em bytes alocados para cada variação de uso do tipo "int":

prog2

É isso aí.

Até a próxima.

sexta-feira, 22 de agosto de 2008

Reescrevendo o algoritmo para resolver o problema da equação 2º grau

Utilizando um editor de textos, como o Microsoft Word, Open Office ou mesmo o Notepad, facilmente podemos organizar os passos que constituem a lógica para resolver o problema apresentado:

 image

Podemos encontrar sintaxes variadas para o pseudo-código, também largamente difundido como "Português Estruturado", até mesmo com forte influência da linguagem de programação Pascal. Nessa linha de abordagem, a sintaxe praticamente constitui uma versão da linguagem Pascal traduzida para a língua portuguesa. A título de exemplo, o algoritmo acima poderia ter o seguinte aspecto:

 image

Links de interesse:

Pretendo direcionar o esforço que seria dispendido para aprender e dominar a "linguagem PASCAL VisuAlg", para um melhor aprimoramento, fixação e desenvolvimento na linguagem de programação C/C++ e testar os algoritmos diretamente numa plataforma realista, como por exemplo os compiladores Embarcadero(ex-CodeGear(ex-Borland)) C/C++ Builder, Microsoft C++ DotNet e GNU/Linux GCC.

 

 

Bom estudo e até a próxima.

quinta-feira, 21 de agosto de 2008

Implementando a solução na Linguagem de Programação C

 

O código a seguir foi elaborado com base nas soluções apresentadas anteriormente em Diagrama de Blocos e NS (Nassi-Schneiderman):

 

#include <stdio.h>
#include <math.h>

void main()
{
    char Resposta[50];

    float a, b, c, delta, x1, x2, x;

    printf( "\nDefinir coeficiente A: " );
    scanf( "%f", &a );

    printf( "\nDefinir coeficiente B: " );
    scanf( "%f", &b );

    printf( "\nDefinir coeficiente C: " );
    scanf( "%f", &c );

    printf( "\n\n Coeficientes: A=%f   B=%f   C=%f \n\n", a, b, c );

    if ( a == 0 )
    {
        sprintf( Resposta, "\n Equacao invalida \n" );
    }
    else
    {
        delta = pow( b, 2 ) - 4 * a * c;

        if ( delta < 0 )
        {
            sprintf( Resposta, "\n Nao possui solucao Real \n" );
        }
        else
        {
            if ( delta == 0 )
            {
                x = - b / 2 * a;
                sprintf( Resposta, "\n X = %f \n", x );
            }
            else
            {
                x1 = ( - b + sqrt( delta ) ) / 2 * a;
                x2 = ( - b - sqrt( delta ) ) / 2 * a;
                sprintf( Resposta, "\n X1 = %f \n X2 = %f \n", x1, x2 );
            }
        }
    }

    printf( "%s", Resposta );

}

 

Na solução foram utilizadas as seguintes funções da biblioteca <stdio.h>:

  • printf( )
  • scanf( )
  • sprintf( )

E da biblioteca <math.h>:

  • pow( )
  • sqrt( )

A seguir temos a cópia da tela "prompt de comandos" do sistema Windows XP, onde podemos observar as etapas de compilação e execução do programa:

prog1

 

A Microsoft distribui gratuitamente a versão Microsoft Visual C++ 2008 Express Edition:

http://www.microsoft.com/Express/

 

 

Até a próxima.

Uso do Diagrama de Nassi-Schneiderman

A solução para o mesmo problema, agora com o uso do diagrama Nassi-Schneiderman:

 

Equação 2o. Grau

 

Este diagrama também é chamado de Diagrama de Chapin.

Referências:

 

Até a próxima.

Uso do Diagrama de Blocos

Para resolver o problema proposto, a seguir temos a seqüência lógica dos procedimentos necessários apresentada através do recurso Diagrama de Blocos:

 

Equação 2o.Grau

 

Links indicados para leitura complementar:

http://www.manzano.pro.br/tutor/algoritmo/ptalg006.zip

http://www.fw.uri.br/~leticia/ApostilaAlgoritmos2006.pdf

 

Até a próxima.

quarta-feira, 20 de agosto de 2008

Uma abordagem para a resolução das raízes de uma equação de 2º grau

Algoritmo expresso em forma textual de uma seqüência imperativa de comandos:

1) Obter coeficientes a, b, c;
2) Coeficiente a = 0 ?
    2.1) Então: preparar Resposta = "equação inválida";
    2.2) Senão:
        2.2.1) Calcular delta = b^2 - 4*a*c;
        2.2.2) Valor de delta < 0 ?
            2.2.2.1) Então: preparar Resposta = "inexistência de solução Real";
            2.2.2.2) Senão: valor de delta = 0 ?
                2.2.2.2.1) Então:
                    2.2.2.2.1.1) Calcular x = - b / 2 * a;
                    2.2.2.2.1.2) Preparar Resposta = "X = " + ConverterParaTexto( x );
                2.2.2.2.2) Senão:
                    2.2.2.2.2.1) Calcular x1 = ( - b + RaizQuadrada( delta ) ) / 2 * a;
                    2.2.2.2.2.2) Calcular x2 = ( - b - RaizQuadrada( delta ) ) / 2 * a;
                    2.2.2.2.2.3) Preparar Resposta = "    X1 = " +
                                                        ConverterParaTexto( x1 ) + 
                                                    "    X2 = " +
                                                        ConverterParaTexto( x2 );
3) Apresentar Resposta;

 

Considerações:

1) o conceito de biblioteca de funções, previamente implementadas na maioria das linguagens de programação de alto nível, permite a abstração de certas operações elementares e corriqueiras, como exemplo a linguagem de programação C Ansi oferece:

  • obtenção de raiz quadrada:  sqrt( valor );
  • conversão/concatenação de dados diversos para texto: sprintf( buffer, "formatação", variáveis );

2) as operações aritméticas básicas são normalmente representadas pelos símbolos: + - * /

3) o operador de exponenciação ou potenciação vai depender da linguagem de programação: ** ou ^ são os casos mais usuais, porém tomando a linguagem de programação C Ansi como exemplo, existe a função de biblioteca pow(a, n) para calcular a elevado a n;

4) também é comum a necessidade de concatenção de textos, variando muito entre as linguagens de programação, mas podendo ser representada pelo operador + ou & ou até mesmo por funções de biblioteca; no caso da linguagem C Ansi podemos usar a mesma função sprintf() mencionada acima;

5) ao fazer uso de operadores relacionais >, < e = devemos tomar cuidado para não confundir o teste de igualdade com a operação de atribuição:

Atribuição Teste de igualdade Linguagem
delta = pow(b,2) - 4 * a * c if ( delta == 0 ) C ansi, C++
delta := b ** 2 - 4 * a * c if ( delta = 0 ) Pascal, Delphi

6) por último, uma consulta ao dicionário Michaelis (http://michaelis.uol.com.br/moderno/portugues/index.php?lingua=portugues-portugues&palavra=dentear) nos apresenta o verbo: "dentear (den.te.ar) (dente+ear) vtd 1 Formar dentes em. 2 Recortar, chanfrar. Var: dentelar.". Reparar que o algoritmo acima apresentado em forma textual, assim como a escrita de comandos na maioria das linguagens de programação de alto nível, devem usar este recurso para facilitar a leitura dinâmica dos mesmos e agilizar a compreensão do raciocínio, assim como acelerar e manter um controle sobre o fluxo de execução das instruções; ou seja, um hábito a ser desenvolvido.

 

Até a próxima.

 

Propondo um problema clássico para estudo

Dada uma equação de 2º grau genérica:

image

Encontrar a solução para f(x) = 0, obedecendo a restrição do domínio dos números Reais.

Os coeficientes a, b, c deverão ser informados como entrada para o algoritmo a ser desenvolvido.

Utilizar o método de Bhaskara (http://pt.wikipedia.org/wiki/Bhaskara) e como resposta considerar as possibilidades:

1) equação inválida;

2) inexistência de solução Real;

3) uma raiz apenas;

4) duas raízes;

 

Até a próxima.

LG1 - Segundo semestre de 2008

 

Boas-vindas para todos e expresso aqui meus votos para que tenham um proveitoso semestre.

Um grande abraço e até a próxima.

terça-feira, 24 de junho de 2008

Trabalhando com objetos da classe Fila<AnsiString> no Borland C++ Builder


Fila ADT
Uma fila é um tipo abstrato de dados (ADT: abstract data type) que pode ser implementado em C++ como mostra a classe a seguir.
Começando pela declaração da interface da classe:
// início do arquivo "Fila.h"
//---------------------------------------------------------------------------
#ifndef FilaH
#define FilaH
// interface da classe Fila<ADT>
template <class objectType>
class Fila
{
        private:
                class Node
                {
                        public:
                                objectType *objetoCorrente;
                                Node *nodeSucessor;
                        public:
                                Node( objectType* );    // construtor
                                ~Node( void );          // destrutor
                };
        private:
                Node *nodeInicial, *nodeFinal;
                int qtdNodes;
        public:
                Fila( void );                           // construtor
                ~Fila( void );                          // destrutor
                void Guardar( objectType* );
                objectType* Retirar( void );
                int Tamanho( void );
};
//---------------------------------------------------------------------------
// Implementação da classe Fila<ADT>
//---------------------------------------------------------------------------
#include "Fila.cpp"
//---------------------------------------------------------------------------
#endif
// fim do arquivo "Fila.h"
A seguir temos a implementação dos métodos:
// início do arquivo "Fila.cpp"
//---------------------------------------------------------------------------
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Atenção: RETIRAR A LINHA #include "Fila.h"
//---------------------------------------------------------------------------
// construtor da classe "Fila"
template <class objectType>
Fila<objectType> :: Fila( void )
{
        this->qtdNodes = 0;
        this->nodeInicial = NULL;
        this->nodeFinal = NULL;
}
// destrutor da classe "Fila"
template <class objectType>
Fila<objectType> :: ~Fila( void )
{
        Node *_nodeCorrente = this->nodeInicial,  *_nodeSucessor;
        while ( _nodeCorrente != NULL ) {
                // guardar ponteiro para node sucessor
                _nodeSucessor = _nodeCorrente->nodeSucessor;
                // destruir objeto corrente
                delete _nodeCorrente->objetoCorrente;
                // destruir node corrente
                delete _nodeCorrente;
                // posicionar no node sucessor
                _nodeCorrente = _nodeSucessor;
        }
}
// guardar um objeto na fila
template <class objectType>
void Fila<objectType> :: Guardar( objectType *__objetoCorrente )
{
        // instanciar um novo node
        Node *_nodeCorrente = new Node( __objetoCorrente );
        // verificar se a fila está vazia
        if ( this->qtdNodes == 0 )
        {
                // atualizar o node inicial da fila
                // para o node recem instanciado
                this->nodeInicial = _nodeCorrente;
        }
        else
        {
                // atualizar o node sucessor do final corrente da fila
                // para o node recem instanciado
                this->nodeFinal->nodeSucessor = _nodeCorrente;
        }
        // atualizar o novo node final da fila
        // para o node recem instanciado
        this->nodeFinal = _nodeCorrente;
        // incrementar qtd de nodes na fila
        this->qtdNodes ++;
}
// retirar um objeto da fila
template <class objectType>
objectType* Fila<objectType> :: Retirar( void )
{
        // guardar node inicial da fila
        Node *_nodeCorrente = this->nodeInicial;
        // obter ponteiro do objeto corrente
        objectType *_objetoCorrente = _nodeCorrente->objetoCorrente;
        // fixar novo início da fila no node sucessor
        this->nodeInicial = _nodeCorrente->nodeSucessor;
        // decrementar qtd de nodes na fila
        this->qtdNodes --;
        // se esvaziar, apontar node final para NULL
        if ( this->qtdNodes == 0 )
        {
                this->nodeFinal = NULL;
        }
        // deletar node corrente
        delete _nodeCorrente;
        // retornar ponteiro do objeto retirado do início da fila
        return ( _objetoCorrente );
}
// consultar a quantidade de objetos na fila
template <class objectType>
int Fila<objectType> :: Tamanho( void )
{
        return ( this->qtdNodes );
}
// construtor da classe "Node"
template <class objectType>
Fila<objectType> :: Node :: Node( objectType *__objetoCorrente )
{
        this->objetoCorrente = __objetoCorrente;
        this->nodeSucessor = NULL;
}
// destrutor da classe "Node"
template <class objectType>
Fila<objectType> :: Node :: ~Node( void )
{
}

// fim do arquivo "Fila.cpp"
Os conceitos básicos de uma fila determinam que os elementos que a formam devem ser organizados pela ordem de chegada, ou seja, o primeiro que chegar à fila será o primeiro a ser retirado dela (FIFO: first-in, first-out); os elementos podem ser representados por "nodes" (ou "nós") que guardam 2 ponteiros: um para a estrutura de dados que desejamos organizar e o outro para o "node" seguinte na ordem de chegada da fila.
Usando a Fila ADT em outros projetos
Como exemplo, foi escolhido um caso de uso de strings do tipo Ansi, mas que poderia ser de outro tipo de dados como float, int, double, etc, inclusive outro tipo ADT como Números Complexos ou Números Racionais.
A seguir temos trechos de códigos para o projeto de teste:
1) Incluir no projeto as definições da classe "Fila":
        #include "Fila.h"
2) Definir um ponteiro para um objeto da classe Fila<AnsiString>:
Fila<AnsiString> *minhasstrings;
3) Instanciar o objeto da classe Fila<AnsiString>:
this->minhasstrings = new Fila<AnsiString>();
4) Inserindo objetos AnsiString na fila:
        this->minhasstrings->Guardar( new AnsiString( "São Paulo" ) );
        this->minhasstrings->Guardar( new AnsiString( "Rio de Janeiro" ) );
        this->minhasstrings->Guardar( new AnsiString( "Salvador" ) );
        this->minhasstrings->Guardar( new AnsiString( "Recife" ) );
        this->minhasstrings->Guardar( new AnsiString( "Fortaleza" ) );
        this->minhasstrings->Guardar( new AnsiString( "Manaus" ) );

5) Retirando objetos AnsiString da fila:
        this->ListBox1->Clear() ;
        // deixar os ultimos da fila para testar funcionalidade do
        // método destrutor da Fila<AnsiString>

        while( this->minhasstrings->Tamanho() > 2 )
        {
                AnsiString *valor = this->minhasstrings->Retirar();
                this->ListBox1->Items->Add( (*valor) );
                delete valor;
        }

6) Destruir o objeto da classe Fila<AnsiString> e consequentemente realizar uma varredura e destruição dos possíveis nodes remanescentes, também destruindo os respectivos objetos do tipo AnsiString associados a estes nodes:
        delete this->minhasstrings;
7) Não esquecer de habilitar o CodeGuard para certificar se tudo correrá como previsto, pelo menos durante o desenvolvimento.
Até a próxima.       

segunda-feira, 23 de junho de 2008

Usando Dll no Borland C++ Builder

 

Recomendações para o desenvolvimento dos dois projetos isolados em pastas separadas:

 

1) Criar novo projeto: File -> New -> Other -> Dll Wizard

        Project1 -> ProjDll.bpr
        Unit1 -> DllMain.cpp

2) Acrescentar um Header File para a DLL: File -> New -> Other -> Header File

        File1.h -> DllMain.h

3) Incluir em DllMain.h a diretiva de compilador:

        #include "MinhaClasse.h"

4) Incluir em DllMain.cpp a diretiva de compilador:

        #include "DllMain.h"

5) Criar nova Unit: File -> New -> Unit

        Unit2.cpp -> MinhaClasse.cpp
        Unit2.h -> MinhaClasse.h

6) Declarar a classe em MinhaClasse.h com a especificação:

        class __declspec(dllexport) MinhaClasse
        {
            ...
        };

7) Gerar a DLL: Project -> Build ProjDLL

8) Depurar erros da DLL e prosseguir somente quando estiver tudo correto.

9) Criar novo projeto: File -> New -> Application

        Project1.bpr -> ProjDemo.bpr
        Project1.cpp -> ProjDemo.cpp
        Unit1.cpp -> DemoFormMain.cpp
        Unit1.h -> DemoFormMain.h

10) Copiar da pasta do projeto da DLL os arquivos:

        ProjDll.lib
        ProjDll.dll
        DllMain.h
        MinhaClasse.h

11) Acrescentar no ProjDemo: Project -> Add to Project...

        Selecionar aruivos do tipo Library (*.lib)
        Indicar o arquivo a ser adicionado ao projeto: ProjDll.lib

12) Acrescentar no DemoFormMain.h a diretiva de compilador:

        #include "DllMain.h"

14) Substituir a diretiva de compilador em MinhaClasse.h de/para:

        dllexport -> dllimport

15) A partir deste estágio, já podemos declarar variáveis do tipo MinhaClasse:

        MinhaClasse obj1MinhaClasse;
        MinhaClasse *obj2MinhaClasse;

16) Se a declaração for para objeto estático, usar:

            obj1MinhaClasse.Atributo
            obj1MinhaClasse.Método()

17) Se a declaração for para objeto dinâmico, usar:

            obj2MinhaClasse = new MinhaClasse();
            ...
            obj2MinhaClasse->Atributo
            obj2MinhaClasse->Método()
            ...
            delete obj2MinhaClasse

18) Atenção para o ciclo vida dos objetos instanciados:

        estaticamente -> escopo da função
        dinamicamente -> requer Delete antes do término da função/programa

Até a próxima.

quinta-feira, 24 de abril de 2008

Pilha de Quadrados em Borland C++ Builder 6

Esta aplicação plota quadrados a partir de parâmetros fornecidos pela seguinte interface de usuário:

image

Ao clicar no botão "Plotar", um quadrado é instanciado e plotado com o seu canto superior esquerdo dado pelos valores (X,Y) e na largura desejada.

Para manter controle sobre a população de quadrados instanciados, esta aplicação utiliza o conceito de pilha implementado sob a forma de uma classe. Assim, ao clicar no botão "Limpar" a área do paintbox é limpa, permitindo observar a reconstrução dos quadrados na ordem em que são retirados da pilha, através do click no botão "Refazer Tudo". Observe que a aplicação ao retirar um quadrado da pilha, ela salva em outra para não perder o controle sobre todos os quadrados instanciados. Um efeito colateral a ser notado é que a reconstituição é dada na ordem inversa da criação dos quadrados, pois no conceito de pilha, o mais recente será o primeiro a ser retirado da pilha e o mais antigo o último a ser retirado dela (last in, first out - LIFO).

A seguir temos as classes utilizadas:

1) Começando pela classe "Quadrado" (arquivo Unit2.h):

//---------------------------------------------------------------------------

#ifndef Unit2H
#define Unit2H

#include <graphics.hpp>             // classe de elementos gráficos do BCB6 

class Quadrado
{
        private:
                int x;
                int y;
                int largura;

        public:
                Quadrado();                                    // construtor default
                Quadrado( int, int );                         // construtor
                Quadrado( int, int, int );                   // construtor
                void Plotar( Graphics::TBitmap * );
                ~Quadrado();                                 // destrutor
};

//---------------------------------------------------------------------------
#endif

 

2) E os métodos previstos para esta classe (arquivo Unit2.cpp):

//---------------------------------------------------------------------------

#pragma hdrstop

#include "Unit2.h"          // classe Quadrado

//---------------------------------------------------------------------------

#pragma package(smart_init)

Quadrado :: Quadrado( )                               // construtor default
{
        this->x = 100;
        this->y = 200;
        this->largura = 90;
}

Quadrado :: Quadrado( int a, int b )                 // construtor
{
        this->x = a;
        this->y = b;
        this->largura = 50;
}

Quadrado :: Quadrado( int a, int b, int c)           // construtor
{
        this->x = a;
        this->y = b;
        this->largura = c;
}

void Quadrado :: Plotar( Graphics::TBitmap *tmp )
{
        tmp->Canvas->PenPos = TPoint( this->x, this->y );
        tmp->Canvas->LineTo( this->x + this->largura, this->y  );

        //tmp->Canvas->PenPos = TPoint( this->x + this->largura, this->y );
        tmp->Canvas->LineTo( this->x + this->largura, this->y + this->largura );

        //tmp->Canvas->PenPos = TPoint( this->x + this->largura, this->y + this->largura );
        tmp->Canvas->LineTo( this->x, this->y + this->largura  );

        //tmp->Canvas->PenPos = TPoint( this->x, this->y + this->largura );
        tmp->Canvas->LineTo( this->x, this->y  );

}

Quadrado :: ~Quadrado()
{
}

 

3) A classe que implementa o conceito de pilha (arquivo Unit3.h):

//---------------------------------------------------------------------------

#ifndef Unit3H
#define Unit3H

#include "Unit2.h"      // classe Quadrado

class PilhaQuadrados
{
        private:
                class Node
                {
                        public:
                                Quadrado *itemCorrente;
                                Node *nodeAntecessor;
                        public:
                                Node( Quadrado*, Node* );        // construtor
                                ~Node( void );                         // destrutor

                };

        private:
                Node *nodeTopo;
                int qtdNodes;

        public:
                PilhaQuadrados( void );                 // construtor
                ~PilhaQuadrados( void );               // destrutor

                void Guardar( Quadrado* );
                Quadrado* Retirar( void );
                int Tamanho( void );

};

//---------------------------------------------------------------------------
#endif

 

4) E os métodos previstos para esta outra classe (arquivo Unit3.cpp):

//---------------------------------------------------------------------------

#pragma hdrstop

#include "Unit3.h"     // classe PilhaQuadrados 

//---------------------------------------------------------------------------

#pragma package(smart_init)

PilhaQuadrados :: PilhaQuadrados( void )                                 // construtor
{
        this->qtdNodes = 0;
        this->nodeTopo = NULL;
}
PilhaQuadrados :: ~PilhaQuadrados( void )                               // destrutor
{
        Node *nodeCorrente = this->nodeTopo,  *nodeAntecessor;
        while ( nodeCorrente != NULL ) {
                nodeAntecessor = nodeCorrente->nodeAntecessor;
                delete nodeCorrente->itemCorrente;                       // destruir quadrado corrente
                delete nodeCorrente;                                           // destruir node corrente
                nodeCorrente = nodeAntecessor;
        }
}
void PilhaQuadrados :: Guardar( Quadrado *qdr )
{
        this->nodeTopo = new Node( qdr, this->nodeTopo );
        this->qtdNodes ++;
}
Quadrado* PilhaQuadrados :: Retirar( void )
{
        Node *nodeCorrente = this->nodeTopo ;
        Quadrado *qdr = nodeCorrente->itemCorrente;
        this->nodeTopo = nodeCorrente->nodeAntecessor;
        this->qtdNodes --;
        delete nodeCorrente;
        return ( qdr );
}
int PilhaQuadrados :: Tamanho( void )
{
        return ( this->qtdNodes );
}

PilhaQuadrados :: Node :: Node( Quadrado *item, Node *no )
{
        this->itemCorrente = item;
        this->nodeAntecessor = no;
}
PilhaQuadrados :: Node :: ~Node( void )
{
}

 

5) A interface de usuário da aplicação é composta pela classe TForm1 (arquivo Unit1.h):

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>

#include "Unit2.h"              // classe Quadrado
#include "Unit3.h"              // classe PilhaQuadrados

//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TLabel *Label1;
        TEdit *Edit1;
        TLabel *Label2;
        TEdit *Edit2;
        TLabel *Label3;
        TEdit *Edit3;
        TButton *Button1;
        TButton *Button2;
        TButton *Button3;
        TPaintBox *PaintBox1;
        TLabel *Label4;
        void __fastcall Button1Click(TObject *Sender);
        void __fastcall Button2Click(TObject *Sender);
        void __fastcall Button3Click(TObject *Sender);
        void __fastcall PaintBox1Paint(TObject *Sender);
private:    // User declarations
        Graphics::TBitmap *figura;              // bitmap
        PilhaQuadrados *minhaPilha;             // pilha

public:        // User declarations
        __fastcall TForm1(TComponent* Owner);   // construtor
        __fastcall ~TForm1(void);                       // destrutor
  void __fastcall CriarFigura(void);                    // limpar figura
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

 

6) E os métodos da classe TForm1 são definidos a seguir (arquivo Unit1.cpp):

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)  // construtor
{
        this->minhaPilha = new PilhaQuadrados();        // criar pilha
        this->CriarFigura();                                     // criar bitmap figura
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1(void)                             // destrutor
{
        delete this->figura;                      // destruir figura
        delete this->minhaPilha;               // destruir pilha
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)           // plotar
{
        int x, y, larg;

        x    = StrToIntDef( this->Edit1->Text, 0 );
        y    = StrToIntDef( this->Edit2->Text, 0 );
        larg = StrToIntDef( this->Edit3->Text, 0 );

        Quadrado *qdr;                                 // declarar ponteiro de quadrado
        qdr =  new Quadrado( x, y, larg );        // instanciar quadrado
        qdr->Plotar( this->figura );                 // plotar no bitmap

        this->PaintBox1->Refresh();               // refazer paintbox

        this->minhaPilha->Guardar( qdr );       // guardar quadrado na pilha

        this->Label4->Caption = "Qtd.Quadrados: " +
                                IntToStr( this->minhaPilha->Tamanho() );
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)           // limpar
{
        delete this->figura;                 // deletar figura atual
        this->CriarFigura();                 // criar nova figura
        this->PaintBox1->Refresh();     // refazer paintbox
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)           // refazer tudo
{
        // criar uma nova pilha

        PilhaQuadrados *pilhaInvertida = new PilhaQuadrados();

        while ( this->minhaPilha->Tamanho() > 0 )
        {
                // obter quadrado do topo da pilha

                Quadrado *tmp = this->minhaPilha->Retirar();

                // plotar quadrado

                tmp->Plotar( this->figura );

                // guardar quadrado na nova pilha

                pilhaInvertida->Guardar( tmp );

                // refazer paintbox

                this->PaintBox1->Refresh();

                // aguardar 500ms

                Sleep( 500 );
        }

        // destruir pilha velha

        delete this->minhaPilha;

        // copiar referencia da nova pilha para a velha

        this->minhaPilha = pilhaInvertida;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::PaintBox1Paint(TObject *Sender)   // refazer paintbox
{
        // exibir bitmap no paintbox

        this->PaintBox1->Canvas->Draw( 0, 0, this->figura );
}
//---------------------------------------------------------------------------
void __fastcall TForm1::CriarFigura()                    // criar bitmap
{
        this->figura = new Graphics::TBitmap();

        // redimensionar largura e altura

        this->figura->Width = this->PaintBox1->Width ;
        this->figura->Height = this->PaintBox1->Height;
}
//---------------------------------------------------------------------------

 

Até  próxima.