Mostrando postagens com marcador C. Mostrar todas as postagens
Mostrando postagens com marcador C. Mostrar todas as postagens

quarta-feira, 6 de agosto de 2008

Algumas pessoas PRECISAM fazer programas interativos

Este código:

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

int main(int argc, char **argv){
int i;
double total =0;

for(i=1;i < argc;i++){
total = total + atof(argv[i]);
}

printf("A soma dos %d parametros eh %f\n",(argc - 1),total);

return 0;
}


É limpo, prático e scriptável. Não preciso fazer pergunta nenhuma nem tratar nada que o usuario informe: no maximo posso ver o número de parâmetros e reclamar. Basta saber como funciona o laço for e saber que argc é o número de parâmetros que eu passei para o programa e argv é um vetor de strings (que, em C puro, são vetores de chars) onde cada elemento é um parâmetro. O primeiro é sempre o nome do programa (a posição 0, que eu pulei).

$ gcc -Wall soma.c
$ ./a.out 1 2 3 4 5
A soma dos 5 parametros eh 15.000000


Eu compilo e pelo para que todos os warnings possiveis sejam mostrados. Novamente não tive nenhum problema e o código funciona bem. Nem um flush de stdin foi preciso. Se eu colocar uma palavra no meio, como abóbora, será ignorado.

Não é mais facil assim do que fazer milhões de menus? Nem precisa de system("pause") system("cls")!

quarta-feira, 2 de abril de 2008

Programando em C para console - parte 1

(Depois de um fecundo primeiro de Abril... )

Cada vez mais eu me espanto com a quantidade de novatos que tentam fazer programas para o "modo console" que não fazem o menor sentido.

Programas com menuzinho (1 - saque , 2 - deposito, 3 - sair) ou do estilo "digite um numero (q para sair)" são totalmente contra-produtivos. O novato perde TEMPO fazendo um monte de código desnecessário quando esquece o que deveria fazer (o tal do algoritmo).

Veja um exemplo: um programa que receba uma quantidade variavel de números e que imprima a soma dos mesmos. IMHO a forma mais interessante para fazer isso é pegar os números como argumentos do programa principal. Vc cria um programa console absolutamente limpo e facil de scriptar, por exemplo.

Veja só:

#include <stdio.h>

int main(int argc, char *argv[]){
double soma = 0.0;

printf("A soma dos numeros eh %g\n",soma);

return 0;
}


Feito esse simples arquivo, vamos compilar
$ gcc -Wall soma.c
$ ./a.out 1 2 3 4 5
A soma dos numeros eh 0


Ai vc fala "po, ta errado!", mas claro, eu primeiro escrevi a base do meu programa. Perceba que eu compilei com a opção -Wall, que me informa todos os warnings que a compilação pode gerar (o que sempre é uma excelente pratica, eu procuro compilar sempre com 0 warnings).

Feito isso, vamos definir 2 coisas:
- O algoritmo da soma e
- Possiveis fluxos de excessão.

Vou partir do suposto que, se vc digitar alguma coisa que não seja um numero, eu vou ignorar e considerar como 0. Caso eu não informe nenhum numero ao programa, isso significa que estou faltando com alguma coisa, nesse caso vou informar uma mensagem elucidativa sobre o uso do programa.

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

int main(int argc, char *argv[]){
int i;
double soma = 0.0;

if(argc == 1){
fprintf(stderr,"Faltando Argumentos!\n");
fprintf(stderr,"Uso: %s x1 [ x2 .. xN ]\n",argv[0]);
return 1;
}

for(i=1;i<argc;i++)
soma += atof(argv[i]);

printf("A soma dos numeros eh %g\n",soma);

return 0;
}


Todos os argumentos que eu passo para o programa, incluindo o nome do mesmo, ficam no vetor argv, e o número de argumentos fica na variavel arcc. Dessa forma, o nome do programa é o argv[0] e, se eu não passar nenhum argumento adicional, argc será 1. A função atof converte a string para um número de ponto flutuante e retorna 0 se não for possivel converter.

Simples, não? Agora vamos executar:

$ ./a.out          
Faltando Argumentos!
Uso: ./a.out x1 [ x2 .. xN ]
$ echo $?
1
$ ./a.out 1 2 3 4 5
A soma dos numeros eh 15
$ echo $?
0


A mensagem de uso utiliza uma notação no manual de alguns programas do mundo unix: colocar os argumentos opcionais entre colchetes. Eu informo que preciso de pelo menos um argumento. Caso eu entre no fluxo de excessão, o meu main retorna um valor diferente de 0 para o sistema operacional que pode ser capturado pela variavel de ambiente $? (nesse caso estou em um linux utilizando o bash, em outros sistemas mais exotéricos como o Windows eu não imagino como vc poderia capturar essa informação, tampouco imagino se ela seria util).

Perceba que eu posso criar um script extremamente simples para utilizar esse programa, assim como testar o resultado é uma tarefa de um grep (ou diff). Eu poderia juntar um script de teste e um makefile nesse post mas estou esperando um exemplo um pouco mais interessante.

Eu criei um programa sucinto, facil de entender e muito util, sem ter que perguntar para o usuario nada. transformar esse programa num que calcula a média, por exemplo, é uma tarefa de colocar apenas uma linha (na verdade uma subtração e uma divisão) a mais. Espero que os programadores novatos se inspirem nessa forma de pensar e que utilizem os programas básicos do unix como o grep, cat, diff, cp, etc, para seus futuros trabalhos.

quarta-feira, 24 de outubro de 2007

Entendendo Ponteiros na linguagem C

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

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

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

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

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

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

return 0;
}


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

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


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

O codigo gerado pelas macros

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

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

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

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

return 0;
}


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

Para fazer este exemplo, utilizamos este arquivo header:

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

quinta-feira, 12 de julho de 2007

Introdução aos Device Drivers no Linux

Vamos fazer um /dev/hello_word ?

Aprenda a fazer um neste fascinante artigo -- nunca se sabe quando será util!

Printf Format Specifications Quick Reference

Tudo o que vc sempre quis saber sobre o printf mas tinha medo de perguntar:
http://www.pixelbeat.org/programming/format_specs.html

quarta-feira, 11 de julho de 2007

Sugestões de Leitura

Ja ouviu falar na tal Web 2.0? Veja os slides da apresentação do Philip Calçado.

Quer dominar o Vi/Vim? Veja este pequeno guia.

Se inglês não é problema, vc pode aprender Java, C++ ou Programação Avançada em Linux usando livros gratuitos e de ótima qualidade.

No site da InfoQ vc ainda pode baixar livros de SOA, Scrum & XP, Domain Driven e Dicas de Visual Studio .NET.

E, se vc se interessa por Gerência de Projetos, vai gostar desse artigo.

Boa leitura!

terça-feira, 10 de julho de 2007

Ansi C orientado à objetos

Divertido! Compila e não gera nenhum warning.


#include <stdio.h>

struct {
struct {
int (*println) (const char *);
} out;
} System = { {puts} };


int main (void){

System.out.println("ola mundo");

return 0;
}


Achei um pdf no google sobre o assunto chamado Orientação A Objetos em C Ansi. Neste caso, eu criei um ponteiro para a função puts (presente na libc), chamado println. Criei uma variavel chamada System, que é uma estrutura que possui uma variavel chamada out que, por sua vez, possui o ponteiro println.

segunda-feira, 2 de julho de 2007

O melhor de dois mundos: C e Fortran

C é uma ótima linguagem de programação, simples e clara.
Fortran, para problemas matemáticos, é imbativel!

Que tal usar o melhor dos dois mundos com este tutorial?

Vejamos o exemplo abaixo:

Arquivo testC.cpp

#include 

using namespace std;

extern"C" {
void fortfunc_(int *ii, float *ff);
}

main()
{

int ii=5;
float ff=5.5;

fortfunc_(&ii, &ff);

return 0;
}


Arquivo testF.f
      subroutine fortfunc(ii,ff)
integer ii
real*4 ff

write(6,100) ii, ff
100 format('ii=',i2,' ff=',f6.3)

return
end


Compilando

$ f77 -c testF.f
$ g++ -c testC.cpp
$ g++ -o test testF.o testC.o -lg2c


Executando

$ ./test
ii= 5 ff= 5.500


Aceito sugestões, agora que não tenho muita coisa para fazer em Fortran.

segunda-feira, 18 de junho de 2007

O Desenvolvimento da Linguagem C

Um texto cativante e histórico (por Dennis M. Ritchie):

http://cm.bell-labs.com/cm/cs/who/dmr/chistPT.html

a Linguagem C e o Sistema Operacional Unix foram revolucionários, trazendo conceitos usados até hoje. Qualquer um que queira se aventurar no mundo da informática, seja como hobbie ou profissão, tem que conhece-los ao menos um pouco.

segunda-feira, 11 de junho de 2007

Ola Mundo!

Quando aprendemos uma nova linguagem de programação, normalmente o primeiro exemplo é o famoso "Hello World!", ou seja, um pequeno código que imprime uma mensagem na tela do computador.

Em C, ele seria assim:

/* Um comentário */
#include <stdio.h>

int main ()
{
puts ("Hello world!");
return 0;
}


As vezes o puts é substituido pelo multifacetado printf no exemplo, mas o efeito é o mesmo. Vejamos como seria em Java.

/* Comentarios, igual ao C */
package Hello;

public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world");
}
}


As diferenças são várias, apesar da estrutura ser semelhante. Em C nós temos funções parametrizadas, enquanto em Java nós temos objetos (System.out) e métodos (println).

Por fim, vamos ver um exemplo em Shell Script

#!/bin/bash
# comentario
echo "Hello World!"


Diferente de uma linguagem de programação, aqui o interpretador de comandos (normalmente) chama um programa capaz de escrever mensagens para o usuario. Ou seja, alguem ja escreveu um "Hello World!" genérico o suficiente para nós.

Cada linguagem possui um propósito. Enquanto vc projeta sistemas operacionais e drivers em C, Java ocupa uma área no desenvolvimento de grandes sistemas corporativos enquanto o shell está presente na administração de determinadas tarefas de um servidor (normalmente rodando algum sabor de *nix).

Não basta comparar um hello world, pois é preciso ver muito além da sintaxe e recursos da linguagem, mas normalmente se começa por ele.

Outros exemplos podem ser encontrados aqui.

Abraços