char em struct lendo arquivo em C - Onde estou errando?

Iniciado por wdr, 27 de Julho de 2008, 22:12

tópico anterior - próximo tópico

wdr

Estou tentando ler um arquivo texto usando uma estrutura em C. Só que algo está saindo errado.

Código:
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
        FILE *arq;
        int qtd;

        struct st_func
        {
                char nome[30];
                char end[20];
                char prof[10];
        };

        struct st_func func;

        if ( (arq = fopen("arq01.txt", "r") ) == NULL )
        {
                printf("Erro ao abrir arquivo... ");
                exit(0);
        }

        qtd = fread(&func, sizeof(struct st_func)  , 1, arq);


        printf("\nNome: %s \nEnd: %s \nProf: %s\n", func.nome, func.end, func.prof);
        fclose(arq);

}


o arquivo texto a ser lido é de largura fixa e possui 30 espaços para o nome 20 para o endereço e 10 para a profissão. Exemplo.

MARIA DAS FLORES BELAS DOCASE RUA AIMORES 888 PROFESSORA
FABIO COMPLEXADO DA MAMAE JR AV TAMAMDUA 35 AP 18ESTAGIARIO


mas o programa está colocando toda a linha no campo nome, a partir da posição 31 no campo end e da 51 no campo prof : vejam a saída do programa:

wdr@local:~/prog/c$ ./prog02

Nome: MARIA DAS FLORES BELAS DOCASE RUA AIMORES 888 PROFESSORA
End: RUA AIMORES 888 PROFESSORA
Prof: PROFESSORA

como 60 caracteres couberam no vetor nome cujo tamanho eu defini em 30?? tem algo a ver com o caracter nulo?
onde estou errando? como corrigir?

Obrigado
_________________

kunigas

#1
Se não me engano, as structs são armazenadas em um espaço contínuo na memória. Desta forma, ao declarar uma variável do tipo st_func, o que você tem em mãos é uma região contínua de 60 bytes na memória.

Temos que &func e func.nome apontam para a primeira posição dessa região, func.end aponta para a posição 30 e func.prof aponta para a posição 50.

Assim, quando você passa o endereço de func para a função fread, ele não sabe que você tá passando uma struct. Ele tá vendo um endereço e vai escrever 60 bytes do arquivo a partir desse endereço. Desta forma ele acabará escrevendo exatamente o que você queria.

Entretanto, para imprimir um vetor de caracteres com %s, a função precisa saber qual o tamanho do vetor ou um caractere que marca o final da string. Em C++ a classe string armazena o tamanho da string, mas em C precisamos colocar o caractere de final de string. Neste caso é o '\0' ou simplemente o valor 0. Do modo como você está fazendo, não tá colocando esse caracter. Para isso você teria que declarar cada campo com uma posição a mais do que vai realmente utilizar, mas ia bugar a sua leitura que depende do tamanho da sua struct.

Não sei uma maneira muito enxuta de se contornar o problema. A primeira coisa que me vem em mente é ler uma linha inteira em uma string e depois usando 'for's preencher cada campo da sua struct.

EDITADO:

Na verdade você poderia fazer 3 leituras, lendo cada campo de uma vez e depois "fechando" a string. Observe que mesmo dessa forma você deve declarar seus campos com uma posição a mais:

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

int main(void)
{
        FILE *arq;
        int qtd;

        struct st_func
        {
                char nome[31];
                char end[21];
                char prof[11];
        };

        struct st_func func;

        if ( (arq = fopen("arq01.txt", "r") ) == NULL )
        {
                printf("Erro ao abrir arquivo... ");
                exit(0);
        }


        qtd = fread(func.nome, 30, 1, arq);
        qtd += fread(func.end, 20, 1, arq);
        qtd += fread(func.prof, 10, 1, arq);
        func.nome[30] = func.end[20] = func.prof[10] = 0;

        printf("\nNome: %s \nEnd: %s \nProf: %s\n", func.nome, func.end, func.prof);
        fclose(arq);

}