segunda-feira, 19 de outubro de 2009
domingo, 31 de maio de 2009
Otimizações do compilador GCC
Usei o exemplo do post anterior, de qualquer forma segue o código abaixo:
#include
#include
double tempo()
{
struct timeval tv;
gettimeofday(&tv,0);
return tv.tv_sec + tv.tv_usec/1e6;
}
int main()
{
double t1,t2;
double i;
t1 = tempo();
printf("%lf\t",t1);
for(i=0;i<300000000;i++);
t2 = tempo();
printf("%lf\t",t2);
printf("%lf\n",t2-t1);
return 0;
}
Na hora de compilar um programa com o GCC você pode colocar alguns parâmetros, vamos usar:
-O1 Otimiza para tamanho do binário
-O2 Otimiza para desempenho de execução
-O3 Otimiza para Data cache
* Atenção é "O" (letra) e não "0" (número).
Vamos aos testes:
[helton2@hrpc ~]$ gcc teste.c -O1
[helton2@hrpc ~]$ ./a.out
1243797632.612002 1243797633.767017 1.155015
Neste exemplo o tamanho do binário ficou em 6329 bytes e demorou 1.155 segundos.
[helton2@hrpc ~]$ gcc teste.c -O2
[helton2@hrpc ~]$ ./a.out
1243797643.222072 1243797644.371347 1.149275
Neste exemplo o tamanho do binário ficou em 6345 bytes e demorou 1.149 segundos.
[helton2@hrpc ~]$ gcc teste.c -O3
[helton2@hrpc ~]$ ./a.out
1243797650.764788 1243797651.959029 1.194241
Neste exemplo o tamanho do binário ficou em 6409 bytes e demorou 1.194 segundos.
Compilando da forma padrão ...
[helton2@hrpc ~]$ gcc teste.c
[helton2@hrpc ~]$ ./a.out
1243797667.095339 1243797670.080635 2.985296
Neste exemplo o tamanho do binário ficou em 6369 bytes e demorou 2.985 segundos.
Como aqui estamos tratando de um problema fácil, apenas um simples "for" a diferença é pequena, mas com problemas mais complexos, sem dúvida essas opções de compilação podem dar um "up" no seu programa.
As opções aqui abordadas são válidas para a maioria dos compiladores C e C++ tanto em ambiente unix, linux, mac e windows.
Dica de Claudio Schepke. Obrigado!
quinta-feira, 14 de maio de 2009
Como instalar o GCC em Mandriva pela linha de comando?
O URPMI é como o APT das distribuições baseadas em Debian... um gerenciador de pacotes.
Bom, o primeiro passo é "testar" se a instalação de um dado pacote (rpm, que está nos repositórios) é possível. Para isso (com root) usamos "urpmi -- test gcc", onde "gcc" é o pacote que queremos instalar.
O URPMI então nos diz se é possíovel ou não. Para instalar então tem que dar o comando "urpmi gcc" onde gcc é o pacote que queremos instalar.
No início da tela anterior, executamos o comando "gcc" e como pode ver, não havia esse comando, instalamos, executamos novamente e tudo ok.
É essa a dica, agora você que usa uma máquina rodando alguma distribuição que usa RMPI, e acessa ela remotamente por SSH por exemplo e que não tem acesso a interface gráfica... já pode programar em C.
Welcome to jungle :)
Bye
sábado, 25 de abril de 2009
Fatorial Recursivo em C
Neste pequeno tutorial vou demonstrar o cálculo do fatorial utilizando recursividade na linguagem C. O fatorial de um número é igual a ele mesmo vezes ele menos um até chegar em um, exemplo:
Fatorial de 4 é igual a 4*3*2*1 que é igual a 24.
Fatorial de 5 é igual a 5*4*3*2*1 que é igual a 120.
Na função a seguir temos cálculo do fatorial de um número sem usar recursividade. Ela recebe como parâmetro um número inteiro e retorna o fatorial daquele número.
int fatorial (int n)
{
int i;
i = n - 1;
for (i; i!=1; i--)
n = n * i;
return n;
}
Então podemos considerar que:
- o fatorial de 5 é igual a 5 multiplicado pelo fatorial de 4;
- o fatorial de 4 é igual a 4 multiplicado pelo fatorial de 3;
- o fatorial de 3 é igual a 3 multiplicado pelo fatorial de 2 e assim por diante.
Montando uma função matemática temos:
fatorial de x = x * fatorial de ( x -1 );
Entendido isso, a nossa função recursiva está praticamente pronta, basta adicionar uma condição de fim, que na função anterior é i diferente de 1. Veja a seguir a implementação da função em C.
int fatorial (int n)
{
if(n==1)
return n;
return fatorial(n-1) * n;
}
Simples assim, até.
segunda-feira, 30 de março de 2009
Calculadora em C utilizando pilhas
Olá, exemplo muito básico, mas muito básico mesmo, de uma calculadora com as 4 operações básicas feito no Dev-C++ utilizando a linguagem C e também o conceito de pilhas. Este programa pede para o usuário digitar dois valores e armazena eles em uma pilha (vetor), depois pede para o usuário informar a operação desejada, desempilha os valores e armazena eles em variáveis auxiliares, isso poderia ser tirado fora mas pro melhor entendimento preferi deixar assim, feita a operação é armazenado o resultado na pilha novamente e chamado a função que exibe o resultado final.
/*
Name: Calculadora
Author: Bol�var Arthur Butzke
Date: 23/03/09 21:52
Description: Calculadora. Programa que utilize pilhas para efetuar as opera��es b�sicas:
adi��o, subtra��o, divis�o e multiplica��o.
*/
/* Bibliotecas de Fun��es */
#include <stdio.h>
#include <stdlib.h>
/* Constantes */
#define MAX 10
#define BASE 0
/* Vari�veis */
int TOPO=0, OPERACAO=0;
float VETOR[MAX], VALOR=0, N1=0, N2=0, RESULTADO=0;
/* Fun��o para inserir elementos na pilha */
void EMPILHAR(float VALOR)
{
if (TOPO == MAX)
printf("Buffer OverFlow - Pilha Cheia.\n");
else
VETOR[TOPO] = VALOR;
TOPO++;
}
/* Fun��o para retirar elementos da pilha */
float DESEMPILHAR()
{
if (TOPO == BASE)
printf("Buffer UnderFlow! Pilha Vazia.\n");
else
{
TOPO--;
RESULTADO = VETOR[TOPO];
}
return RESULTADO;
}
/* Fun��o para efetuar as opera��es */
void CALCULA()
{
int RESULT = 0;
if (OPERACAO == 1) {
printf("\nOperacao de Adicao\n");
N1 = DESEMPILHAR();
N2 = DESEMPILHAR();
RESULTADO = N1 + N2;
printf("\n%f + %f = %f\n",N1,N2,RESULTADO);
EMPILHAR(RESULTADO);
RESULT = 1;
}
if (OPERACAO == 2) {
printf("\nOperacao de Subtracao\n");
N1 = DESEMPILHAR();
N2 = DESEMPILHAR();
RESULTADO = N1 - N2;
printf("\n%f - %f = %f\n",N1,N2,RESULTADO);
EMPILHAR(RESULTADO);
RESULT = 1;
}
if (OPERACAO == 3) {
printf("\nOperacao de Multiplicacao\n");
N1 = DESEMPILHAR();
N2 = DESEMPILHAR();
RESULTADO = N1 * N2;
printf("\n%f * %f = %f\n",N1,N2,RESULTADO);
EMPILHAR(RESULTADO);
RESULT = 1;
}
if (OPERACAO == 4) {
printf("\nOperacao de Divisao\n");
N1 = DESEMPILHAR();
N2 = DESEMPILHAR();
RESULTADO = N1 / N2;
printf("\n%f / %f = %f\n",N1,N2,RESULTADO);
EMPILHAR(RESULTADO);
RESULT = 1;
}
// printf("Operacao informada invalida. Operacoes validas sao:\n adicao (+)\n subtracao (-)\n multiplicacao (*)\n divisao (/)\n");
if (RESULT==0)
{
printf("\nOperacao nao encontrada. \n1 -> Adicao\n2 -> Subtracao\n3 -> Multiplicacao\n4 -> Divisao\nInforme a operacao novamente: ");
scanf("%d",&OPERACAO);
CALCULA();
}
}
/* Fun��o para exibir o resultado */
void MOSTRARESULTADO()
{
printf("Resultado da operacao e' %f\n",VETOR[BASE]);
}
/* Fun��o Principal */
int main()
{
int AUXILIAR=1;
printf("\n Calculadora 1.0\n");
while (AUXILIAR != 0)
{
printf("\nDigite o valor1: ");
scanf("%f",&N1);
EMPILHAR(N1);
printf("\nDigite o valor2: ");
scanf("%f",&N2);
EMPILHAR(N2);
printf("\n1 -> Adicao\n2 -> Subtracao\n3 -> Multiplicacao\n4 -> Divisao");
printf("\nDigite a operacao: ");
scanf("%d",&OPERACAO);
CALCULA();
MOSTRARESULTADO();
printf("\nDigite 0 para sair ou 1 para realizar outra operacao: ");
scanf("%d",&AUXILIAR);
// nencess�rio para limpar a pilha ap�s realizar uma opera��o, sem isso vai mostrar sempre o resultado da primeira opera��o.
TOPO = BASE;
}
return 0;
}
Para entender melhor o conceito de pilhas, pense em uma pilha de pratos, quando você precisa de um prato você vai e retira o que está em cima, quando não precisa mais, você coloca ele em cima novamente, assim, sempre o último prato empilhado é o primeiro que sai, leia este post sobre listas encadeadas para saber mais.
sexta-feira, 20 de março de 2009
Transpor Matriz em Vetor
Olá galera do ICC!!
Hoje vou postar um programinha feito por mim durante uma aula de revisão, ele é muito simples, possui basicamente uma matriz de ordem 10 e um vetor de 100 elementos.
Segue abaixo o código-fonte.
/* Data: 09/03/2009 Autor: Bolívar Arthur Butzke E-mail: bolivarbutzke@gmail.com Blog: bolivarbutzke.blogspot.com 1) Considerando uma matriz “M”, com a seguinte definição: [ M(I,J), (I = 1..10), (J = 1..10) ] e um vetor V(I), (I = 1..100), escreva os seguintes procedimentos: i) Um procedimento que mostre a diagonal principal da matriz ii) Um procedimento de consulta e um de atribuição para os elementos da matriz “M” iii) Um procedimento que transponha a matriz “M” para o vetor “V” */ #include stdio.h #include time.h /* Prototipação das Funções */ void DiagonalPrincipal(void); void Consultar(void); void Atribuir(void); void Trasnpor(void); void ExibirVetor(void); void ExibirMatriz(void); /* Declaração das variáveis Globais */ int M[10][10], i, j, V[100], n; int main() { /* Preenche a matriz com números aleatórios */ for (i=0;i<10;i++) for (j=0;j<10;j++) { srand(time(NULL)+i*j); M[i][j] = rand() % 100; } /* Chama função que exibe a matriz */ ExibirMatriz(); /* Chama função que exibe a diagonal principal */ DiagonalPrincipal(); /* Chama função que consulta na matriz */ Consultar(); /* Chama função que cadastra valor na matriz */ Atribuir(); /* Chama função que transpoe a matriz em vetor */ Trasnpor(); /* Chama função que exibe o vetor */ ExibirVetor(); /* Encerra a função main retornando um inteiro -> 0 */ return 0; } void DiagonalPrincipal(void) { /* Procedimento que Exibe a diagonal principal da matriz */ printf("\n\n--------------------------------------------------\n"); printf(" Diagonal Principal da Matriz"); printf("\n--------------------------------------------------\n"); for (i=0;i<10;i++) for (j=0;j<10;j++) if (i==j) printf("%d ",M[i][j]); } void Consultar(void) { /* Procedimento de Consulta na Matriz M */ printf("\n\n--------------------------------------------------\n"); printf(" Consulta dos Elementos da Matriz"); printf("\n--------------------------------------------------\n"); printf("\n Informe a linha do elemento: "); scanf("%d",&i); printf("\n Informe a coluna do elemento: "); scanf("%d",&j); printf("\n Valor armazenado Matriz[%d][%d]: %d\n",i,j,M[i][j]); } void Atribuir(void) { /* Procedimento de Atribuição de Valor para um elemento da Matriz M */ printf("\n\n--------------------------------------------------\n"); printf(" Atribuição de Valor para um elemento da Matriz"); printf("\n--------------------------------------------------\n"); printf("\n Informe a linha do elemento: "); scanf("%d",&i); printf("\n Informe a coluna do elemento: "); scanf("%d",&j); printf("\n Informe o valor para armazenar: "); scanf("%d",&M[i][j]); printf("\n Valor armazenado Matriz[%d][%d]: %d\n\n",i,j,M[i][j]); } void Trasnpor(void) { /* Procedimento para transpor a Matriz M para o Vetor V */ printf("\n\n--------------------------------------------------\n"); printf(" Transposição da Matriz M para o Vetor V"); printf("\n--------------------------------------------------\n"); n = 0; for (i=0;i<10;i++) for (j=0;j<10;j++) { V[n] = M[i][j]; n++; } } void ExibirVetor(void) { /* Exibe dados no vetor */ printf("\n\n--------------------------------------------------\n"); printf(" Dados do Vetor"); printf("\n--------------------------------------------------\n"); for (n=0;n<100;n++) printf("Vetor[%d] = %d\n",n,V[n]); } void ExibirMatriz(void) { /* Exibe dados da matriz */ printf("\n\n--------------------------------------------------\n"); printf(" Dados armazenados na Matriz"); printf("\n--------------------------------------------------\n"); for (i=0;i<10;i++) { for (j=0;j<10;j++) { printf("%d ",M[i][j]); } printf("\n"); } }
Bem, no início do programa eu precisei incluir o arquivo de cabeçalho (header) stdio.h (Standart Input/Output) para poder executar os comandos de entrada e saída como printf e scanf, sendo que o printf serve para imprimir uma mensagem na tela e o scanf serve para ler algum valor formatado, por isso precisa passar um parametro dizendo qual o tipo de dados que vai receber e em qual variável vai armazenar, neste caso as variáveis eram todas do tipo integer (valores inteiros) então a máscara é %d. Também precisei incluir o time.h para usar a função time e poder atribuir valores aleatórios conforme hora do sistema nos elementos da matriz.
Quando copiar este código para testar lembre-se de que precisa ter o sinal de "menor que" antes do nome dos arquivos de cabeçalho e o sinal de "maior que" no final para que o seu compilador preferido busque estes arquivos.header na pasta padrão do compilador, se por acaso você tiver estes arquivos cole-os no mesmo diretório/pasta do arquivo com código-fonte.c e então coloque os nomes dos arquivos de cabeçalho dentro de "aspas duplas".
A função que passa os valores armazenados na matriz para o vetor é muito simples, primeiramente inicializamos a variável n com o valor zero, que corresponde ao primeiro elemento do vetor (lembre-se que sempre começamos a contar do zero). Depois fizemos dois for , que chamamos de laços aninhados para acessar os elementos da matriz, no primeiro laço dizemos qual linha estamos e no segundo a coluna, assim podemos percorrer todos os elementos da matriz.
Dentro deste laços aninhados, atribuimos o valor da matriz para o vetor e somamos 1 na variável n, assim quando o laço se repetir a segunda vez passaremos o valor armazenada na linha 0 e coluna 1 para a posição 1 do vetor, na terceira vez ainda será o valor da linha zero mas coluna dois e n valerá 2, e assim por diante até passarmos os 100 valores armazenados na matriz para o vetor.
A função "DiagonalPrincipal" serve para exibir os elementos que se encontram na Diagonal Principal, ou seja, os elementos onde o número da linha é igual ao número da coluna. Outras funções mais simples são para atribuir um valor para um determinado elemento da matriz e consultar o valor de um elemento da matriz, em nenhuma das funções eu precisei passar valores por parametros ou ponteiros porque neste programa específico estamos utilizando variáveis globais que ficam visíveis em todo o programa.
Por enquanto é isso, em breve artigo sobre listas encadeadas.
Listas Encadeadas
Olá galera do ICC!!!
Estamos de volta e com conteúdo muito divertido, esta semana tirei para estudar um pouco sobre listas em C e é muito legal. Bom para começar, sempre que queremos guardar um grupo de dados podemos utilizar vetores ou matrizes, isso faz com que você utilize um espaço contíguo na memória, que mesmo com alocação dinâmica de memória vai necessariamente ser sequencial, então podemos acessar qualquer elemento do vetor passando apenas o ponteiro para o primeiro elemento.
Até neste ponto tudo bem, mas um vetor não é uma estrutura muito flexível, é necessário definir um tamanho máximo para ele, mesmo usando alocação dinâmica para definir/alterar o tamanho do vetor isso acaba custando caro em relação a processamento e uso da região da memória livre reservada para execução do programa (Heap). Isso pode gerar muitos problemas como estouros de memória ao tentar inserir mais um elemento em um vetor cheio (Overflow) ou então Buffer Underflow ao tentar ler um vetor vazio.
Para resolver estes problemas foram criadas as listas encadeadas, são nada mais do que uma estrura de dados com elementos ordenados do mesmo tipo. Elas podem ter o formato de filas ou pilhas, nas filas os dados são inseridos em uma estremidade e retirados na outra, conhecido como FIFO (First In, First Out) e nas pilhas os dados que são inseridos por último são retirados primeiro, conhecido como LIFO (Last In, First Out).
Uma lista encadeada pode ser inicializada sem nenhum valor e a medida que vamos inserindo elementos nela vamos alocando memória dinâmicamente, assim o risco de faltar memória diminui pois não precisamos alocar uma grande quantidade de memória que não vai ser usada depois e não corremos o risco de ocorrer overflow. Quando queremos inserir um novo elemento na lista precisamos criar um nó, que é um ponteiro com endereço de memória do elemento e o valor o valor do elemento, o controle dos dados passa a ser logico e diminui o processamento necessário para recuperar os valores armazenados.
Em breve exemplos utilizando pilhas e listas encadeadas.
Até.
quarta-feira, 4 de março de 2009
Hello World multi-idiomas com alocação dinâmica de memória e ponteiros
Já vimos como desenvolver, sabemos o que precisamos tanto em Linux quanto em Windows para escrever/rodar nossos programas. É claro que se trata do modo mais básico, depois acabamos ajustando para aquilo que estamos desenvolvendo especificamente.
Bom, no post anterior você viu como fazer um "hello world" em C e também em C++. Agora o código é C, e a partir dele iniciaremos postagens referentes a alguns assuntos chaves nessa linguagem:
- Trabalhar com vetores e matrizes (bidimensionais e multidimensionais);
- Trabalhar com alocação dinâmica de memória;
- Trabalhar com strings.
Sem mais delongas confira o código:
/*
Author: Helton Eduardo Ritter
Date:2009-03-04
This program dinamic alloc memory to print "hello world" message
*/
#include// necessary to printf
#include// necessary to malloc
#include// necessary to time
int main()
{
char **texts; // this is a pointer
int i,j,k;
// dinamic allocate memory to = 4 languages, 20 space string
for(i=0;i<4;i++)
texts[i] = malloc(20 * sizeof(char));
// set texts
texts[0] = "Hello world!"; // english
texts[1] = "Hallo Velt!"; // german
texts[2] = "Ola mundo!"; // portuguese
texts[3] = "Holla mundo!"; // Spanisch
// clear values
srand(time(NULL));
k = rand() % 4;
// print the random gretings
printf("%s",texts[k]);
// the declaration of main function say that this function "retun int value"
return 0;
}
Vamos as considerações que podem parecer básicas, mas que refrescam a mente de quem está já a algum tempo sem programar em C.
- No início do arquivo principal, você deve incluir as bibliotecas das quais durante o código você vai usar funções. A biblioteca que normalmente está presente em todos os projetos é a "stdio.h" (standard I/O - input/output), ou seja sempre que precisar dar entrada ou saída em alguma informação, precisará incluir essa biblioteca.
- Os delimitadores de comentários em C são os mesmos em muitas outras linguagens de programação. /* comentário aqui de multiplas linhas */ e também tem o // comentário de uma linha.
- O main (embora seja o bloco principal) também é uma função e deve retornar um tipo de dados tal qual foi declarado, por isso daquele return antes de fechar o bloco do main (apenas evitar warning no compilador);
- Na alocação de memória, o malloc retorna void, você deve passar como parâmetro para ele quanto de memória alocar, mas esse tamanho (bytes) dependem da arquitetura da maquina, logo um int em um processador 32 bits tem um tamanho diferente de um int em um processador 64, por isso que sempre fazermos o cálculo em cima de um tipo de dados e não passamos valores fixos;
- O random no C não funciona muito bem se antes você não "limpar" ou mandar "zerar", se esquecer ele sorteará com muita frequencia o mesmo valor;
- Por último e não menos importante temos o "%s" que é a "mascara" do printf que formata o valor passado a partir do segundo parâmetro nesta função. O "%s" no caso diz que o printf deverá formatar o valor como uma string.
Temos neste artigo vários tópicos abordados por alto, bem superficialmente. Em outro momento entraremos em detalhes de cada um.
Até mais!
terça-feira, 3 de março de 2009
Compilando C/C++ no Linux e no Windows
Este é meu primeiro post aqui no ICC e pretendo mostrar o mais básico, como compilar um programa básico em C ou C++ no linux e no Windows.
Primeiramente, vamos montar uma máquina com os softwares necessárias para programar em C/C++, caso o sistema operacional de sua preferência seja o Windows, a maneira mais fácil é baixar e instalar o Bloodshed Dev-C++, é um programa gratuito e pode ser baixado aqui, após instalar o Dev-C++ sua máquina Windows está pronta. Caso você utilize Linux, é um pouco mais fácil, a maioria das distribuições Linux já vem com o compilador GCC instalado ou então nos repositórios, bastando instalar, para este post estou utilizando Ubuntu 8.10 que pode ser baixado aqui. Para deixar sua máquina com tudo em cima no Ubuntu recomendo executar os seguintes comandos para garantir o bom funcionamento.
**Importante, é necessário estar logado como root ou ter permissões de administrador para executar estes comandos, se você estiver logado com outro usuário pode usar o comando "sudo -s" para adquirir privilégios de administrador.
Atualizando o sistema:
apt-get update
apt-get upgrade
Instalando o Buil-Essential
apt-get install build-essential
Feito isso, temos nossa máquina devidamente equipada com os softwares para criar nosso primeiro programa em C/C++.
Pra começar vamos criar um programa que imprima na tela a frase "Hello World!".
Código em C:
#include
main()
{
printf("Hello World!\n");
}
Código em C++:
#include
int main()
{
std::cout << "Hello World!\n" << std::endl;
return 0;
}
Para compilar no Windows execute o Bloodshed Dev-C++, crie um novo arquivo, copie e cole o código-fonte no arquivo, salve como hello.c ou hello.cpp e pressione F9 para compilar e executar o programa. No Dev-C++ não tem diferença na compilação e execução do código-fonte, tanto para C quanto para C++, basta pressionar F9.
Para compilar no Ubuntu abra qualquer editor de texto puro, pode ser o gedit, crie um novo arquivo, salve o arquivo com código em C como hello.c e o arquivo com código em C++ como hello.cpp, para compilar vá para o terminal (CTRL+ALT+F1) ou abra um terminal em modo design mesmo, basta pressionar as teclas ALT+F2 e executar "gnome-terminal" ou "xterm" para abrir um console de linha de comando, agora vem a parte divertida, vá até o diretório (pasta) onde você salvou os arquivos e execute os seguintes comandos para compilar o programa em C:
Garantir permissão de Administrador
sudo -s
Compilar o programa
gcc -c hello.c
gcc -o hello hello.o
Executar o programa
./hello
O programa imprimirá na tela a frase Hello World!
Para compilar e executar o programa em C++, execute os mesmos passos do programa em C, mas na hora executar os comandos trocar o gcc por g++ e a extenção do arquivo para .cpp, fica assim:
Garantir permissão de Administrador
sudo -s
Compilar o programa
g++ -c hello.cpp
g++ -o hello hello.o
Executar o programa
./hello
Por enquanto é isso, até a próxima!