Como compilar um programa escrito em C++/QT

Depois de ter decidido aprender a utilizar o [cute four] escrevi o típico “Hello World!”.

Como este é extremamente simples, vou utilizar um exemplo um nadinha mais complexo às custas do qual, aqui entre nós, cheguei a “fazer cenas tristes” por não estar a perceber o motivo pelo qual o botão “reset” não funcionava :)

Esta é uma aplicação muito simples que permite definir três valores compreendidos entre 0 e 255.

O seu funcionamento é intuitivo e é composto por três ficheiro:

  • main.cpp
  • mainwindow.cpp
  • mainwindow

main.cpp

#include <QApplication>
#include "mainwindow.h"
int main ( int argc, char *argv [] ){
	QApplication app ( argc, argv );
	MainWindow *janela = new MainWindow;
	janela->setWindowTitle ("Modelo RGB!");
	janela->show();
	return app.exec();
}

mainwindow.cpp

#include <QtGui>
#include "mainwindow.h"
MainWindow::MainWindow (QWidget *parent):QWidget(parent){
	//objects
	botaoReset	= new QPushButton("Reset");
	botaoSair	= new QPushButton("Sair");
	textoRed	= new QLabel("Red");
	textoGreen	= new QLabel("Green");
	textoBlue	= new QLabel("Blue");
	spinBoxRed	= new QSpinBox;
	spinBoxGreen= new QSpinBox;
	spinBoxBlue	= new QSpinBox;
	//properties
	spinBoxRed->setRange(0, 255);
	spinBoxGreen->setRange (0, 255);
	spinBoxBlue->setRange (0, 255);
	sliderRed = new QSlider(Qt::Horizontal);
	sliderGreen = new QSlider(Qt::Horizontal);
	sliderBlue = new QSlider(Qt::Horizontal);
	sliderRed->setRange(0, 255);
	sliderGreen->setRange(0, 255);
	sliderBlue->setRange(0, 255);
	// Signals and slots :
	connect ( spinBoxRed, SIGNAL(valueChanged( int)), sliderRed, SLOT(setValue (int)));
	connect ( sliderRed, SIGNAL(valueChanged( int)), spinBoxRed, SLOT(setValue (int)));
	connect ( spinBoxGreen, SIGNAL(valueChanged(int )), sliderGreen, SLOT(setValue (int)));
	connect ( sliderGreen, SIGNAL(valueChanged(int)), spinBoxGreen, SLOT(setValue (int)));
	connect ( spinBoxBlue, SIGNAL(valueChanged(int)), sliderBlue, SLOT(setValue (int)));
	connect ( sliderBlue, SIGNAL(valueChanged( int)), spinBoxBlue, SLOT(setValue (int )));
	connect ( botaoSair, SIGNAL(clicked()), this, SLOT(close ()));
	connect ( botaoReset, SIGNAL(clicked()), this, SLOT(resetSliders()));
	// Layouts :
	QGridLayout *layoutCores = new QGridLayout;
	layoutCores->addWidget(textoRed, 0, 0, 1, 1);
	layoutCores->addWidget(spinBoxRed, 0, 1, 1,1);
	layoutCores->addWidget(sliderRed,0, 2, 1, 1);
	layoutCores->addWidget(textoGreen, 1, 0, 1, 1);
	layoutCores->addWidget(spinBoxGreen, 1, 1, 1, 1);
	layoutCores->addWidget(sliderGreen, 1, 2, 1, 1);
	layoutCores->addWidget(textoBlue,2, 0, 1, 1 );
	layoutCores->addWidget(spinBoxBlue, 2, 1, 1, 1);
	layoutCores->addWidget(sliderBlue, 2, 2, 1, 1);

	QHBoxLayout *layoutControlo = new QHBoxLayout;
	layoutControlo->addWidget(botaoReset);
	layoutControlo->addWidget(botaoSair);

	QVBoxLayout *layoutJanela = new QVBoxLayout;
	layoutJanela->addLayout(layoutCores);
	layoutJanela->addLayout(layoutControlo);
	setLayout(layoutJanela);
}

void MainWindow::resetSliders (){
	sliderRed-> setValue (0);
	sliderGreen->setValue (0);
	sliderBlue->setValue (0);
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDialog>
class QPushButton;
class QLabel;
class QSpinBox;
class QSlider;
class QGridLayout;
class QVBoxLayout;
class QHBoxLayout;
class MainWindow : public QWidget{
	Q_OBJECT
	public :
	MainWindow ( QWidget* parent = 0 );
	private slots :
	void resetSliders ( );
	private :
	QPushButton *botaoReset;
	QPushButton *botaoSair;
	QLabel *textoRed;
	QLabel *textoGreen;
	QLabel *textoBlue;
	QSpinBox *spinBoxRed;
	QSpinBox *spinBoxGreen;
	QSpinBox *spinBoxBlue;
	QSlider *sliderRed;
	QSlider *sliderGreen;
	QSlider *sliderBlue;
};
#endif

Vamos então tratar de compilar este exemplo para vermos isto a funcionar.
Vou optar por uma exposição passo a passo.

#1 Que ficheiros temos
Nesta fase convém ter um directoria “rgb” contendo os três ficheiros main.cpp, mainwindow.cpp e mainwindow.h.

  • main.cpp
  • mainwindow.cpp
  • mainwindow.h

#2 Criar o projecto

$ qmake -project
  • main.cpp
  • mainwindow.cpp
  • mainwindow.h
  • rgb.pro

#3 Gerar a Makefile

$ qmake rgb.pro
  • main.cpp
  • mainwindow.cpp
  • mainwindow.h
  • Makefile
  • rgb.pro


#4 E finalmente compilar todos os ficheiros que fazem parte do projecto

$ make
  • main.cpp
  • mainwindow.cpp
  • mainwindow.o
  • moc_mainwindow.cpp
  • rgb
  • main.o
  • mainwindow.h
  • Makefile
  • moc_mainwindow.o
  • rgb.pro

Agora basta executar o binário obtido (rgb) para ver este exemplo em acção.
Facilmente se pode concluir que à medida que os projectos adquiram uma dimensão maior, será necessário algum trabalho de arrumação, de forma a evitar esta mistura de ficheiros de diferentes tipos.
Outro aspecto que considero importante aqui referir é que este processo pode ser executado independentemente da plataforma que estivermos a utilizar. Eu utilizo Debian GNU/Linux, mas os utilizadores de Windows (e outros) podem igualmente testar este exemplo.

Neste momento estou a utilizar montes de “hand coding” mas não se assustem! Mais para a frente vamos pedir ajuda ao QT Designer.

Números Aleph e a Linguagem C

Tudo no mundo que nos rodeia é de natureza contínua, ao contrário do que se passa no interior de um computador.

O mundo dos computadores é digital, pelo que as grandezas que neles pretendemos representar sofrem um processo de digitalização, materializando-se fisicamente na forma binária, que é simbolicamente é representada recorrendo ao 1 (um) e ao  0 (zero).

O universo binário tem uma cardinalidade muito simples de compreender porque só tem dois elementos.

Ao bom estilo “The Matrix” vamos fechar o olhos e 0110100101101101011000010110011101101001011011100110000101110010001000000111000101110101011001010010000001110110011011110111010100100000011000110110111101101110
0111010001101001011011100111010101100001011100100010000001100001001000000110010101110011011000110111001001100101011101100110010101110010001000000110010101110011
0111010001100101001000000110000101110010011101000110100101100111011011110010000001110101011101000110100101101100011010010111101001100001011011100110010001101111
0010000001110101011011010110000100100000011100100110010101110000011100100110010101110011011001010110111001110100011000011110011111100011011011110010000001100010
01101001011011101110000101110010011010010110000100100001

No que diz respeito à representação do texto as limitações são poucas, ou praticamente inexistentes. Basta escolher uma tabela de caracteres compatível com o tipo de linguagem que estamos a utilizar.

O problema coloca-se quando pretendemos representar grandezas contínuas que, como facilmente se pode compreender, nunca irão ser rigorosamente representadas neste cenário binário.

Vamos imaginar um programa muito simples escrito em Linguagem C, que pretende apenas armazenar três números reais em memória, exibindo-os de seguida com o máximo de precisão possível para o tipo de dados utilizado (float).


#include <stdio.h>
int main(){
    float x = 1.1;
    float y = 123.1;
    float z = 123.2;
    printf("x = %f\n", x);
    printf("y = %f\n",y);
    printf("z = %f\n", z);
    return 0;
}

Output resultante da execução do programa.

x = 1.100000
y = 123.099998
z = 123.199997

Foi ao tentar compreender este facto que me cruzei com os  números Aleph , mas como espero possam entender, não me vou adiantar muito neste terreno tão matemático.
O tipo de dados float apenas pode representar um gama de valores pertencentes a um conjunto de cardinalidade infinita ( Aleph-um), pelo que importa aqui reter que nunca vamos conseguir uma representação exacta das grandezas contínuas. É fundamental escolhermos um tipo de dados adequado aos dados que pretendemos tratar.
No que à programação em Linguagem C diz respeito, e quando o que estiver em causa forem este tipo de questões, talvez seja bom pensarmos noutra linguagem mais orientada para o cálculo científico.

Espero não ter atropelado nenhum conceito matemático pelo caminho mas, daqui em diante, muito cuidado com os números Reais quando estivermos a utilizar todas as aplicações que os manipulam.

Alocação dinâmica de memória – C++

Depois de escrevermos o nosso programa temos que o compilar.

Nas linhas de código encontramos declarados vários tipos de variáveis que, como se pode imaginar, irão corresponder a áreas de armazenamento alojadas na memória principal.

Podemos então afirmar que existe uma classe de variáveis que são definidas quando o programa é compilado.

Eis alguns exemplos deste tipo de variáveis:

  • Variáveis globais/static (data segment)
  • Variáveis locais (stack)

Este tipo de alocação é muito rígido, pois obriga a conhecer exactamente a quantidade de memória que o nosso programa vai utilizar.

Na maior parte da vezes, e claro sem estarmos a falar de pequenos programas do tipo “Hello world!”, nem sempre é possível conhecer antecipadamente a quantidade de memória de que vamos necessitar.

A linguagem C possui as funções malloc() e free() que permitem alocar memória durante a execução do programa numa área da memória designada por heap ou free store. Deixo aqui um link para um artigo que exemplifica muito bem a utilização destas duas funções.

Embora a linguagem C++ suporte estas funções, disponibiliza uma forma mais eficiente para gerir de forma dinâmica a memória principal na área designada de free store, e mediante a utilização dos operadores new() e delete().

Entre livros e “Googladas” acabei por construir esta imagem que dá uma visão simplificada sobre a forma como o C++ gere a memória do computador.

Os URLs que deixo no final deste artigo permitem saber o principal sobre a Alocação Dinâmica de Memória em C/C++, mas o exemplo que vou dar é aquele que me chamou à atenção para este assunto.

Aqui à uns tempos tive uma dúvida que me surgiu quando confrontei o programa “Hello World!”, escrito em C++ e utilizando QT, do livro oficial ( C++ GUI Programming with Qt 4 ) com o tutorial do sítio da Troltech.
in: Troltech


#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[]){
    QApplication app(argc, argv);
    QPushButton hello("Hello world!");
    hello.show();
    return app.exec();
}

in: C++ GUI Programming with Qt4

#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[]){
    QApplication app(argc, argv);
    QPushButton *hello = new QPushButton("Hello world!");
    hello->show();
    return app.exec();
}

Ambas as versões executam a mesma tarefas, apenas fazem uma gestão diferente da memória.
Na primeira o objecto hello é criado na stack, pelo que apenas é visível na função main, e irá deixar de existir assim que esta função termine a sua execução.

No segundo exemplo hello, é criado como um apontador e utiliza-se o operador new para lhe associar uma área na memória livre (free store), onde permanecerá até que a aplicação termine ou seja explicitamente libertado mediante a utilização do operador delete.

Alguns links recomendados para aprofundar este assunto:

http://www.inf.pucrs.br/~pinho/PRGSWB/Ponteiros/ponteiros.html#Alocacao_Dinamica_de_Memoria
http://www.vivaolinux.com.br/artigo/Alocacao-dinamica
http://www.tech-faq.com/lang/pt/cpp-pointer.shtml
http://www.inf.ufsc.br/~ine5384-hp/Estruturas.AlocDinamica.html
http://www.linhadecodigo.com.br/Artigo.aspx?id=1198X

Está prestes a sair a nova versão do Debian … Lenny

De onde vêm estes nomes escolhidos para as várias versões do Debian GNU/Linux?

Encontrei no blog do “Pequeno TUX” um post muito engraçado que conta um pouco da história e mostra as várias personagens do filme ToyStory que servem de “mascote” a cada versão.

Está engraçado: http://pequenotux.blogspot.com/2008/01/de-onde-vem-os-nomes-das-verses-do.html

Este assunto volta a ser pertinente pois aguardamos ansiosamente o lançamento da próxima versão stable do nosso Sistema Operativo preferido.

Ao bom estilo do Software Livre, o Lenny sai quando estiver pronto … e suspeito que seja já este mês :)

Publicado em debian. 1 Comentário »

Manipulação de Ficheiros Binários

Depois de uma abordagem inicial à manipulação de ficheiros de texto, facilmente nos apercebemos de algumas áreas de aplicação desta matéria.

No entanto, o que fica mais evidente é que os ficheiros de texto apenas dão resposta a uma forma de manipulação de informação muito específica, no formato de sequências de caracteres que, na melhor das hipóteses, se encontram separados por caracteres de fim-de-linha.

O acesso a estes ficheiros é feito de forma sequencial, ou seja, torna necessário percorrer o ficheiro à procura da informação pretendida.

Quando os nossos dados não se encontram neste formato, é necessário recorrer ao ficheiros binários, que entre outras vantagens permitem o acesso directo aos dados.

As aplicações que utilizam este tipo de ficheiros geralmente carregam os dados do ficheiro para a memória, realizam o processamento, e voltam a transferir esses mesmos dados para a posição correspondente no ficheiro.

Abertura de ficheiros binários

A abertura é feita de forma semelhante aos ficheiros de texto ( ver aqui ), bastando acrescentar a letra ‘b’ ao modo de abertura.

fp = fopen("dados.txt", "rb");

Operação de escrita num ficheiro binário (fwrite)

A função fwrite transfere um bloco de dados, com um determinado tamanho em bytes, da memória primária para ao ficheiro.

Protótipo: int fwrite(const void *ptr, int tamanho, int n, FILE *fp)

Onde:

  • ptr é um apontador para qualquer tipo de dados e irá conter o endereço de memória do bloco de dados que pretendemos escrever no ficheiro;
  • tamanho em bytes de cada um dos elementos que vamos escrever;
  • n representa o número de elementos a escrever;
  • fp indica(aponta) o ficheiro de dados onde pretendemos realizar a operação de escrita.

Nota: O valor de retorno da função fwrite representa o número de elementos (dos n) que conseguiu escrever com sucesso.

Exemplo: escrita.c

O exemplo seguinte transfere o conteúdo do array valores para um ficheiro cujo nome é passado da linha de comandos.

#include <stdio.h>
int main(int argc, char *argv[]){
    int valores[5]={7, 3, 8, 1, 2};
    FILE *fp;
    if ((fp=fopen(argv[1], "wb"))==NULL || argc != 2){
        printf("ERRO!\nModo de utilização: %s nome_ficheiro_dados\n", argv[0]);
        return 1;
    }
    fwrite(valores, sizeof(int), 5, fp);
    fclose(fp);
    return 0;
}

Nota: É utilizado o operador sizeof(tipo_de_dados) para determinar o número de bytes ocupado por um int. Assim não precisamos de nos preocupar em saber quantos bytes são necessários para armazenar um inteiro numa determinada arquitectura/compilador.

Operação de leitura num ficheiro binário (fread)

A função fread lê um bloco de dados com um determinado tamanho em bytes do ficheiro para a memória primária.

Protótipo: int fread(const void *ptr, int tamanho, int n, FILE *fp)

Onde:

  • ptr é um apontador para qualquer tipo de dados e irá conter o endereço de memória do bloco de dados onde pretendemos escrever os dados obtidos a partir do ficheiro
  • tamanho em bytes de cada um dos elementos que vamos escrever
  • n representa o número de elementos a ler do ficheiro
  • fp indica o ficheiro de dados onde pretendemos realizar a operação de leitura

Nota: O valor de retorno da função fread representa o número de elementos (dos n) que conseguiu ler com sucesso.

Exemplo: ler.c

O exemplo seguinte preenche o conteúdo do array com os valores obtidos a partir de um ficheiro cujo nome é passado da linha de comandos.

#include <stdio.h>
int main(int argc, char *argv[]){
	int valores[5];
	int i;
	FILE *fp;
	if ((fp=fopen(argv[1], "rb"))==NULL || argc != 2){
		printf("ERRO!\nModo de utilização: %s nome_ficheiro_dados\n", argv[0]);
		return 1;
	}
	fread(valores, sizeof(int), 5, fp);
	fclose(fp);
	for(i=0; i<5; i++)
		printf("valores[%d] = %d\n", i, valores[i]);
	return 0;
}

Muito fica ainda por dizer a este respeito, mas em termos do trabalho que estou a realizar actualmente vou ficar apenas por este aspecto, ou seja, a transferência de blocos de bytes entre a memória e o ficheiro.

Depois existem formas de se fazer o acesso directo ao ficheiro mas esse aspecto fica para outra altura.

Ecplise e C/C++ – O Projecto “Eclipse C/C++ Development Tooling – CDT”

Hoje tive um “flash”, ou melhor, um “Eclipse”!

Estava a tentar encontrar uma ferramenta que me permitisse proporcionar um ambiente simpático para programação em C/C++, na vertente de iniciação, mas que também tivesse o potencial de acompanhar o desenvolvimento do programador à medida que for necessitando de utilizar diferentes frameworks. Simultaneamente tento sempre ter presente a questão do software livre, e de que a melhor forma de o divulgar é utilizando-o.
Claro que a linha de comandos deve ser o ponto de partida, mas depois queremos sempre mais. Algo que nos poupe tempo para algumas tarefas aborrecidas relacionadas com a gestão de ficheiros e compilação dos programas.
Tenho utilizado o Anjuta, que tem feito o seu trabalho, mas agora vou experimentar o Eclipse.
Como utilizo Debian GNU/Linux todas as indicações dadas são para este S.O., mas podem facilmente ser adaptadas a qualquer outro.
Vamos ao que interessa!

O que é o Eclipse?

Eclipse é uma comunidade “open source”, cujos projectos se concentram na criação de uma plataforma de desenvolvimento aberta (open development platform) que inclui funcionalidade de expansão a várias frameworks, ferramentas e librarias para compilar, executar  e gerir o software ao longo do seu ciclo de vida. A Fundação Eclipse (Eclipse Foundation) é sem fins lucrativos,suportada pelas suas organizações membro que alojam os Projectos Eclipse e ajudam a cultivar a comunidade “open source” juntamente com um ecossistema de produtos e serviços complementares.
( saber mais … )

Como instalar o eclipse para programar em Linguagem C/C++?

Um dos projectos em curso tem o nome de  “Eclipse C/C++ Development Tooling – CDT”, que proporciona um IDE de programação em linguagem C/C++ para a plataforma Eclipse.

Utilizando a ferramente apt-get, basta instalar o pacote eclipse-cdt.

# apt-get install eclipse-cdt

Como utilizar?

Bem … façam como eu vou fazer:
1.procurar um how-to na Internet;
2.escrever o meu “Hello World!”;
3.reflectir sobre as vantagens e/ou desvantagens da utilização desta plataforma para o trabalho que pretendo desenvolver.

Aceitam-se sugestões e partilha de experiências :)

Manipulação de Ficheiros de texto em Linguagem C – exemplos avulso :)

Seguem-se alguns exemplos de programas que manipulam ficheiros de texto utilizando as funções fgetc e fputc.

A sequência é completamente aleatória e posso acrescentar outros programas a qualquer momento.

exemplo 1

Verificar se o primeiro caracter de um ficheiro de texto é o caracter 'a' (maiúscula/minúscula).
/*
 Verificar se o primeiro caracter de um ficheiro de texto é a|A
*/
#include <stdio.h>
int main(int argc, char *argv[]){
	/* declarações de variáveis */
	FILE *fp;
	char caracter;
	/* abortar caso o número de parâmetros esteja errado */
	if (argc != 2){
		printf("Modo de utilização: comando nome_ficheiro.\n");
		return 1;
	}
	/* tentar abrir o ficheiro */
	fp=fopen(argv[1],"r");
	/* abortar caso o ficheiro seja aberto com sucesso */
	if (fp==NULL){
		printf("Ficheiro %s não encontrado.\n",argv[1]);
		return 1;
	}
	/* verificar se o primeiro caracter é um a */
	caracter = fgetc(fp);
	if(caracter == 'a' || caracter == 'A')
		printf("O primeiro caracter corresponde à letra 'a'\n");
	else
		printf("O primeiro caracter não corresponde à letra 'a'\n");
	/* Fechar o ficheiro e terminar o programa com sucesso */
	fclose(fp);
	return 0;
}

exemplo2

Trocar todas as ocorrências do caracter ' ' (espaço) pelo caracter '-'(hífen) num ficheiro de texto

/*
 Trocar  o espeço pelo hífen num ficheiro de texto
*/
#include <stdio.h>
int main(int argc, char *argv[]){
	/* declarações de variáveis */
	FILE *fp, *ftmp;
	char caracter;
	/* abortar caso o número de parâmetros esteja errado */
	if (argc != 2){
		printf("Modo de utilização: comando nome_ficheiro.\n");
		return 1;
	}
	/* tentar abrir o ficheiro */
	fp = fopen(argv[1],"r");
	/* abortar caso o ficheiro seja aberto com sucesso */
	if (fp==NULL){
		printf("Ficheiro %s não encontrado.\n",argv[1]);
		return 1;
	}
	/* Fazer a cópia para um ficheiro temporário */
	ftmp = fopen("/tmp/lixo.txt","w");
	while((caracter = fgetc(fp))!=EOF)
		if(caracter == 32)
			fputc( '-', ftmp);
		else
			fputc(caracter, ftmp);
	/* Fechar os ficheiros */
	fclose(fp);
	fclose(ftmp);
	/* Realizar a operação te tranferência de ftmp para fp */
	fp = fopen(argv[1],"w");
	ftmp = fopen("/tmp/lixo.txt","r");
	while((caracter = fgetc(ftmp))!=EOF)
		fputc(caracter, fp);
	fclose(fp);
	fclose(ftmp);
	return 0;
}

exemplo3

Elinina as linhas de comentário (#) de um ficheiro de texto.

/*
 Elimina linhas de comentário (iniciadas pelo caracter #) de um ficheiro de texto.
	 Gera dois ficheiro:
	 1 - ficheiro destino sem comentários (default.txt ou nome indicado em argv[2])
	 2 - ficheiro nocomments.log contendo as linhas eliminadas
*/
#include <stdio.h>
void help(void);
int main(int argc, char *argv[]){
	/* declarações de variáveis */
	FILE *fp, *fdestino, *flog;
	char resposta, caracter;

	/* abortar caso o número de parâmetros esteja errado */
	if (argc < 2 || argc > 3){
		help();
		return 1;
	}

	/* verificar se existe o ficheiro de origem */
	if((fp = fopen(argv[1],"r"))==NULL){
		printf("O ficheiro %s não existe!\n", argv[1]);
		help();
		return 1;
	}

	/* Verificar se o ficheiro destino pode ser substituído (se indicado) */
	if(argc == 2)
		argv[2] = "default.txt";
	else
		if((fdestino = fopen(argv[2],"r")) != NULL){
			fclose(fdestino);
			printf("O ficheiro %s já existe.\nPretende substituir(s/n)? ", argv[2]);
			scanf("%c", &resposta);
			if(resposta == 'n'){
				fclose(fp);
				printf("Programa abortado!\n");
				return 1;
			}
		}

	/* Gerar os ficheiro de destino e de log */
	fdestino = fopen(argv[2], "w");
	flog = fopen("nocomments.log", "w");
	while((caracter = fgetc(fp)) != EOF){
		if(caracter == '#'){
			/* processar linha de log */
			while(caracter != '\n'){
				fputc(caracter, flog);
				caracter = fgetc(fp);
			}
			fputc(caracter, flog);
		}
		else{
			/* processar linha normal */
			while(caracter != '\n'){
				fputc(caracter, fdestino);
				caracter = fgetc(fp);
			}
			fputc(caracter, fdestino);
		}
	}
	/*encerrar ficheiros*/
	fclose(fp);
	fclose(fdestino);
	fclose(flog);

	return 0;
}

void help(void){
	printf("Modo de utilização:\n");
	printf("\tnocomments nomeficheiro [nomeficheirodestino]\n");
	printf("\tCaso o ficheiro destino seja omitido será utilizado \"default.txt\"\n");
	printf("\tO ficheiro de log tem o nome nocomments.log\n");
}

exemplo 4

Contar as palavras num ficheiro de texto.

<pre>

Manipulação de Ficheiros de texto em Linguagem C – leitura/escrita formatada

A manipulação de ficheiros de texto pode ser feita mediante uma abordagem caracter-a-caracter, que à partida cobre todas as necessidade do programador em termos de leitura e escrita.

No entanto, e para algumas situações específicas, pode recorrer-se às funções fscanf e fprintf para realizar as operações de input/output com algum tipo de formatação.

fprintf – Escreve dados no ficheiro num formato indicado

Protótipo: int fprintf(FILE *nomeficheiro, const char *formato, …)

Observações:

  • Devolve EOF caso seja detectado o fim do ficheiro;
  • Devolve o número de parâmetros que conseguiu ler com sucesso;
  • Deve ser usada apenas para ficheiros de texto.

Exemplo de escrita 1:

#include <stdio.h>
int main(int argc, char *argv[]){

	FILE *fp;

	int a=1;
	char b[30]="maria";
	float c=2.3;

	if(argc == 2){
		fp = fopen(argv[1], "w");
		fprintf(fp, "%d %s %.1f", a, b, c);
		fclose(fp);
	}
	else
		printf("É necessário especificar um nome de ficheiro.\n");
	return 0;
}

Observações:

  • A operação de escrita só é executada se fornecermos o nome do ficheiro a criar;
  • O ficheiro criado irá conter um registo(linha) com informação sobre uma pessoa.

Exemplo de escrita 2:

O exemplo seguinte aceita registos formados pelos campos número, nome e idade e escreve-os num ficheiro. A leitura dos dados termina se fornecermos um número de aluno negativo.

/* Nome do programa: fprintf_avancado */
#include <stdio.h>

typedef struct {
	int numero;
	char nome[20];
	int idade;
} ALUNO;

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

	FILE *fp;
	ALUNO registo;

	/* verificar se o comando foi invocado com o nome do ficheiro */
	if (argc != 2){
		printf("Modo de utilização: %s nome_ficheiro\n", argv[0]);
		return 1;	/* terminar o programa sem sucesso */
	}

	/* criar ficheiro */
	fp = fopen(argv[1], "w");

	/* inserir dados - terminar o input com uma número de aluno negativo ou nulo */
	printf("Introduza os dados relativos aos alunos.\n");
	printf("Para terminar introduza um número de aluno negativo.\n");
	printf("\nNúmero: "); scanf("%d", &registo.numero);
	while(registo.numero > 0){
		printf("Nome: "); scanf("%s", registo.nome);
		printf("Idade: "); scanf("%d", &registo.idade);
		fprintf(fp, "%d %s %d\n", registo.numero, registo.nome, registo.idade);
		printf("\nNúmero: "); scanf("%d", &registo.numero);
	}

	/* fechar o ficheiro */
	fclose(fp);

	/* terminar o programa com sucesso */
	return 0;

}

fscanf – Lê dados do ficheiro no formato indicado

Protótipo: int fscanf(FILE *nomeficheiro, const char *formato, …)

Observações:

  • Devolve EOF caso seja detectado o fim do ficheiro;
  • Devolve o número de parâmetros que conseguiu ler com sucesso;
  • Deve ser usada apenas para ficheiros de texto;
  • É em tudo semelhante à função scanf, mas é especificado o stream a ser utilizado.

Exemplo de leitura 1:

#include <stdio.h>
int main(int argc, char *argv[]){

	FILE *fp;

	int a;
	char b[30];
	float c;

	if((fp = fopen(argv[1], "r"))!=NULL){
		fscanf(fp, "%d %s %f", &a, b, &c);
		printf("a = %d\n", a);
		printf("b = %s\n", b);
		printf("c = %.1f\n", c);
		fclose(fp);
	}
	else
		printf("O ficheiro especificado não existe!\n");
	return 0;
}

Exemplo de leitura 2:

O exemplo seguinte lê os dados armazenados no ficheiro criado pelo Exemplo de escrita 2. Não se esqueça de fornecer o mesmo nome de ficheiro quando testar este código.

/* Nome do programa: fscanf_avancado */
#include <stdio.h>

typedef struct {
	int numero;
	char nome[20];
	int idade;
} ALUNO;

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

	FILE *fp;
	ALUNO registo;

	/* verificar se o comando foi invocado com o nome do ficheiro */
	if (argc != 2){
		printf("Modo de utilização: %s nome_ficheiro\n", argv[0]);
		return 1;	/* terminar o programa sem sucesso */
	}

	/* Abrir ficheiro caso exista */
	if((fp = fopen(argv[1], "r"))==NULL){
		printf("ERRO!\nO Ficheiro %s não existe.\n", argv[1]);
	   return 1;
	}

	/* mostrar os dados armazenados com o programa fprintf_avancado */
	while(fscanf(fp, "%d %s %d",	&registo.numero, registo.nome, &registo.idade)==3){
		printf("%d %s %d\n", registo.numero, registo.nome, registo.idade);
	}

	/* fechar o ficheiro */
	fclose(fp);

	/* terminar o programa com sucesso */
	return 0;

}

Observações finais

Como é evidente não fica tudo dito aqui, mas sinceramente para aplicações mais complexas esta não será a melhor abordagem.

Afinal ELAS também andam nisto!

Achei curioso e resolvi divulgar.

Publicado em debian. 1 Comentário »

Os prós e contras do Magalhães

Estive a ler o artigo  (de)FORMAÇÃO «MAGALHÃES» e confesso que fiquei preocupado.

Não sei se foi por ver aqueles colegas todos contentes a cantar e a bater palminhas, ou tudo aquilo que pode estar para lá do Magalhães!

Estou um pouco baralhado!

Em vez de me lançar a “mandar bitaites”, vou coleccionar artigos e links que me ajudem a eventualmente formar a minha própria opinião.

Primeiro convém ir ao site oficial ver o que se passa: http://www.portatilmagalhaes.com/

Agora vamos coleccionar entradas neste “opinomáforo” :)

Vídeos “ridículos” – Desculpem se tiverem opinião contrária à minha

Jornal Público

Carta de uma MÃE procupada

(de)FORMAÇÃO «MAGALHÃES»

O “Magalhães” – Diário de Notícias

Nicholas Negroponte

Computadores portáteis de baixo custo chegarão ao país (Brasil)na próxima semana

Portátil Magalhães já disponível para os mais pequenos – TSF

Classmate Pc ( tive dificuldades em posicionar este!)

Gov’t. commits €400m to equip schools with IT

Venezuela splashes out on laptops

Portátil Magalhães: o sucesso público – Expresso

Chávez é fã do portátil português

Artigos relacionados:


El Corte Inglés lança portátil de baixo custo Inves Júnior

Intel prepara terceira geração do Classmate PC

Fábrica de PCs da Intel vai instalar-se em Matosinhos

Ajudem-me a formar uma opinião!

(This is a work in progress)