Deveria Funcionar, não? Linguagem C 1

Pessoal, isso tá me dando nos nervos. Estou implementando um simples banco de dados em C. Ele permite criar e abrir tabelas e adicionar, ler, editar e apagar registros. A função de leitura é muito parecida com a de edição. A diferença é que após posicionar o cursor do arquivo na posição onde está o registro, a função de leitura lê um registro e a de edição sobrescreve esse registro. Ou deveria. Acontece que a edição não funciona, e acho que a culpa é do fwrite! A seguir o código:

As estruturas que representam a tabela na memória

Um campo da tabela
struct ltfield {
	char name[LT_ID_LEN + 1];
	int size;
	char type;
};

typedef struct ltfield LTField;

struct ltable {
	int version[3];
	int fieldsLen;
	int registerLen; /* Esse é o comprimento de um registro de acordo com o vetor de campos */
	int count;
	long data; /* Esse é a posição no arquivo onde os registro começam a ser gravados */
	long insert;
	char match;
	int pos;
	int cursor; /* Esse é o registro sobre o qual a operação será realiza */
	LTField *fields; /* Esse é o vetor de campos fornecido na criação da tabela */
	FILE *file;
	char **buffer; /* Este buffer serve para a leitura e gravação de registros */
	unsigned opened :1;
	unsigned error :7;
};

typedef struct ltable LTable;

A função de leitura

#include "ltables.h"
#include "lterr.h"
#include <stdio.h>
#include <string.h>

int lt_read(LTable *table) {
	register int F;
	char active = 0;

	/* Checa a tabela */
	if (table->error)
		return LTERR_TABLE_HAS_ERROR;
	if (!table->opened)
		return LTERR_TABLE_IS_CLOSED;

	/* Corrige cursores atrevidos :-) */
	if (table->cursor >= table->count)
		table->cursor = table->count - 1;
	else if (table->cursor < 0)
		table->cursor = 0;

	/* Acha a posição de leitura */
	fseek(table->file,
			table->data + table->cursor * (sizeof(char) + table->registerLen),
			SEEK_SET);

	/* Checa se o registro está ativo */
	active = getc(table->file);
	if (!active)
		return LTERR_INACTIVE_REGISTER;

	/* Limpa o buffer, para que dados anteriores não deixem fragmentos */
	for (F = 0; F < table->fieldsLen; F++)
		memset(table->buffer[F], '\0', table->fields[F].size);

	/* Lê o registro para o buffer AQUI FUNCIONA*/
	for (F = 0; F < table->fieldsLen; F++)
		fread(table->buffer[F], sizeof(char), table->fields[F].size,
				table->file);

	return 0;
}

A função de Edição

#include "ltables.h"
#include "lterr.h"
#include <stdio.h>
#include <string.h>

int lt_edit(LTable *table) {
	register int F;
	char active = 0;
	long int offset=0;

	/* Checa a tabela */
	if (table->error)
		return LTERR_TABLE_HAS_ERROR;
	if (!table->opened)
		return LTERR_TABLE_IS_CLOSED;

	/* Corrige cursores atrevidos :-) */
	if (table->cursor >= table->count)
		table->cursor = table->count - 1;
	else if (table->cursor < 0)
		table->cursor = 0;

	/* Acha a posição de edição */
	offset=table->data + table->cursor * (sizeof(char) + table->registerLen);
	fseek(table->file, offset, SEEK_SET);

	/* Checa se o registro está ativo */
	active = getc(table->file);
	if (!active)
		return LTERR_INACTIVE_REGISTER;


	// Grava o buffer AQUI !NAO! FUNCIONA!
	for (F = 0; F < table->fieldsLen; F++)
		fwrite(table->buffer[F], sizeof(char), table->fields[F].size, table->file);
	fflush(table->file);

	// Limpa o buffer, para que dados anteriores não deixem fragmentos
	for (F = 0; F < table->fieldsLen; F++)
		memset(table->buffer[F], '\0', table->fields[F].size);

	return 0;
}

O link para o codigo completo vai aqui? http://www.4shared.com/zip/rRuN9OLB/ltables.html
Meu email: paioniu@gmail.com
Obrigado.

Cara, que bagunça. Misturou c++ com c.

Se for usar c++ as estruturas de dados estão prontas e os arquivos pode ser lidos e gravados com fstream. C++ e C são coisas diferentes.

Olha aqui:

Stl Io
http://www.cplusplus.com/reference/iolibrary/

Stl containers
http://www.cplusplus.com/reference/stl/

Mas onde é que está misturado? É código C mesmo, mas tem uma coisinha chata - não estou conseguindo imaginar corretamente o layout do arquivo.

Você vai ter de debugar seu programa com cuidado. Não vi, nesse programa, onde é que você acerta o valor de “registerLen”, por exemplo.

Mas onde é que está misturado? É código C mesmo, mas tem uma coisinha chata - não estou conseguindo imaginar corretamente o layout do arquivo.

[/quote]

string é c++

Juliocbq? string é c++ string.h é c mesmo. registerLen é calculado quando se cria a tabela com lt_open. Voce fornece um vetor de campos (LTField[]) e a funcao calcula o tamanho do registro.

[quote=entanglement]Você vai ter de debugar seu programa com cuidado. Não vi, nesse programa, onde é que você acerta o valor de “registerLen”, por exemplo. [/quote] Ja debuguei. Quando chega na hora do fwrite em lt_edit nao ha nada de errado. Tanto e que se eu usar fread no lugar funciona. Le-se um registro para o buffer. So nao funciona gravar o buffer para o arquivo.

Olha, buffer é uma sequência de strings

Não tenho certeza, mas você não deveria alocar assim?

[quote=juliocbq]Cara, que bagunça. Misturou c++ com c.

Se for usar c++ as estruturas de dados estão prontas e os arquivos pode ser lidos e gravados com fstream. C++ e C são coisas diferentes.

Olha aqui:

Stl Io
http://www.cplusplus.com/reference/iolibrary/

Stl containers
http://www.cplusplus.com/reference/stl/[/quote]

Nao e bagunca. É código C puro. O link do 4shared fornece o codigo na integra para baixar. A estrutura ltables fornece toda a informacao que as funcoe precisarao para fazer leituras e escritas, etc.

[quote=juliocbq]Olha, buffer é uma sequência de strings

Não tenho certeza, mas você não deveria alocar assim?

[/quote]

Funciona. buffer e uma matriz bidimendional mas buffer[F] é uma string. PAra ler uma string com fread voce multiplica o tamanho de um char pelo numero de caracteres que vc quer ler, nesse caso o tamanho da string.

é verdade, essa aí não é a da stl não…

[quote=daniloMPA][quote=juliocbq]Olha, buffer é uma sequência de strings

Não tenho certeza, mas você não deveria alocar assim?

[/quote]

Funciona. buffer e uma matriz bidimendional mas buffer[F] é uma string. PAra ler uma string com fread voce multiplica o tamanho de um char pelo numero de caracteres que vc quer ler, nesse caso o tamanho da string.[/quote]

:slight_smile:

O problema se concentra na lt_edit na hora de gravar o vetor de strings, o buffer. Nao ha problemas com os ponteiros, e o buffer sempre tem o conteudo que eu escrevi. Mas O fwrite nao grava!

Danilo-san, não tenho acesso ao 4Shared. De qualquer forma, é sempre aconselhável usar a macro offsetof (quando disponível) porque, devido a problemas de “packing” e “alignment”.
Quando você tem uma estrutura do tipo:

struct X {
    char x;
    int y;
    unsigned char[10] z;
};

você tem os seguintes problemas:
a) Qual é o tamanho da struct acima? Dica: não é 1 + 4 + 10 = 15. Provavelmente é 4 + 4 + 16 ou então 8 + 8 + 16, devido ao que o compilador C faz com o layout de structs em em memória (para que dados fiquem alinhados em endereços múltiplos do tamanho da palavra do processador e que ocupem um número inteiro de palavras.
b) Se você quer usar o valor de um determinado campo, devido ao “alignment” e ao “packing”, ele fica em uma posição que não é imediatamente fácil de você achar. Nesse caso, y provavelmente está em um endereço múltiplo de 4 ou de 8, não no deslocamento 1 byte a partir do início da struct.

só uma perguntinha. Não li seu código inteiro (até porque não estou com acesso ao 4shared, e tenho uma preguiça terrível de ler código dos outros).

Mas você quer gravar com um único fwrite todos os buffers de uma vez? Eu gravaria um de cada vez, cada qual com seu fwrite.

Desculpe, é isso que você fez. Só mais uma coisa - você, debugando, está vendo que ele está realmente pegando os buffers do jeito que você quer?

Entendo entanglement. Mas se houvesse um problema dessa natureza que interferisse no acesso ao membro buffer entao a lt_read tambem na funcionaria. Foi por isso que a coloquei lado a lado com a lt_edit para comparacao. Se fread funciona, por fwrite nao. O arquivo foi aberto em modo “r+b” e a lt_insert funciona inserindo um novo dado justamente com fwrite. Porque fwrite funciona para inserir ao fim do arquivo, mas nao sobrescrever um registro existente? Esse e meu problema…

Ao debugar, o buffer chega do jeito esperado ate o momento de chamar fwrite. So nao e gravado no arquivo apos a chamada.

for (F = 0; F < table->fieldsLen; F++) fwrite(table->buffer[F], sizeof(char), table->fields[F].size, table->file);

table->fieldsLen e o numero de campos e tambem de strings no buffer. Esse codigo grava um campo do buffer, ou seja, uma string do buffer por vez.

|campo1|campo2|campo3| e assim ate finalizar o registro.

[quote=daniloMPA] for (F = 0; F < table->fieldsLen; F++) fwrite(table->buffer[F], sizeof(char), table->fields[F].size, table->file);

table->fieldsLen e o numero de campos e tambem de strings no buffer. Esse codigo grava um campo do buffer, ou seja, uma string do buffer por vez.

|campo1|campo2|campo3| e assim ate finalizar o registro.[/quote]

na documentação passam 1 na largura da data. Pode ser isso aí.

http://www.cplusplus.com/reference/cstdio/fwrite/

[code]/* fwrite example : write buffer */
#include <stdio.h>

int main ()
{
FILE * pFile;
char buffer[] = { ‘x’ , ‘y’ , ‘z’ };
pFile = fopen ( “myfile.bin” , “wb” );
fwrite (buffer , 1 , sizeof(buffer) , pFile );
fclose (pFile);
return 0;
}[/code]