Thread: Problem reading a file

  1. #1
    Registered User
    Join Date
    Jan 2005
    Posts
    204

    Problem reading a file

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void remover_newline(char *);
    
    struct dados {
    	char matricula[5];
    	char nome[40];
    	char curso[20];
    	char nota[2];
    } aluno;
    
    int main(void)
    {
    	char linha[40];
    	FILE *dados;
    	
    	
    	
    	dados = fopen("dados.txt", "r");
    	if(dados == NULL){
    		printf("dados.txt - arquivo desconhecido\n");
    		getchar();
    		exit(1);
    	}
    
    	while(fgets(linha, sizeof(linha), dados) != NULL){
    		
    		remover_newline(linha);
    		strcpy(aluno.matricula, linha);
    
    		fgets(linha, sizeof(linha), dados);
    		remover_newline(linha);
    		strcpy(aluno.nome, linha);
    
    		fgets(linha, sizeof(linha), dados);
    		remover_newline(linha);
    		strcpy(aluno.curso, linha);
    
    		fgets(linha, sizeof(linha), dados);
    		remover_newline(linha);
    		strcpy(aluno.nota, linha);
    
    		printf("aluno.matricula: %s\n", aluno.matricula);
    		printf("aluno.nome: %s\n", aluno.nome);
    		printf("aluno.curso: %s\n", aluno.curso);
    		printf("aluno.nota: %s\n\n", aluno.nota);
    
    		break;
    	}
    
    	fclose(dados);
    
    	return 0;
    }
    
    void remover_newline(char *linha)
    {
    	char *ptr;
    
    	ptr = strchr(linha, '\n');
    	if(ptr != NULL)
    		*ptr = '\0';
    }
    dados.txt:
    Code:
    20457
    Denis Rocha da Silva
    Linguagem de programação
    {5} {40} {20} {2}
    
    98364
    Tom Hanks
    Teatro
    {38} {42} {2} {27}
    
    44078
    Nicolas Cage
    História
    {11} {29} {5} {37}
    
    10904
    Sabrina da Silva Sauro
    Matemática
    {3} {43} {11} {18}
    
    12003
    Charles Petzold
    Programação
    {34} {23} {12} {1}
    The output:
    Code:
    aluno.matricula: 20457Denis Rocha da Silva
    aluno.nome: Denis Rocha da Silva
    aluno.curso: Linguagem de program{5} {40} {20} {2}
    aluno.nota: {5} {40} {20} {2}
    I've been trying to fix this for a long time and it is driving me crazy. What am I doing wrong? I also have this strange feeling that there is a better way to do this. Help please.

  2. #2
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    I'm not so great at portuguese. What are you expecting from your program that isn't happening?

    EDIT: Oh well. One thing I notice is that you're not allocating enough space for your strings:
    Code:
    	char matricula[5];
            char curso[20]
    	char nota[2];
    The string you're storing in matricula is 6 characters, but you're only allowing for 5. Don't forget about the '\0' at the end of the string. Same with curso.

    And nota, well, that string is definitely a lot longer than 2 characters.
    Last edited by itsme86; 04-18-2005 at 10:20 AM.
    If you understand what you're doing, you're not learning anything.

  3. #3
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Code:
    struct dados {
    	char matricula[5];
    	char nome[40];
    	char curso[20];
    	char nota[2];
    } aluno;
    Make enough space for the text and trailing null.
    Code:
    20457
    Denis Rocha da Silva
    Linguagem de programação
    {5} {40} {20} {2}
    [edit]Why have a loop that always breaks in the first pass?
    Last edited by Dave_Sinkula; 04-18-2005 at 10:19 AM.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  4. #4
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Geez, Dave. Give a guy enough time to edit his post will ya?
    If you understand what you're doing, you're not learning anything.

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    204
    That was lame
    Thanks.

    As for the break, I was trying to get it right first, that is why I used it.

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    204
    I'm confused now...

    Why does char nota[2] works with let's say numbers 34, 23, 54, 2 and char matricula[5] doesn't work with numbers like 12345, 74957, 35409?

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,170
    > Why does char nota[2] works with let's say numbers 34, 23, 54, 2
    That would be down to "luck".

    The character arrays inside your struct may (or may not) be padded with spare bytes. So whilst you can apparently use these and have a "working" program, it still doesn't mean that its correct code.

    Change your compiler or your struct, and it will just stop "working" for no readily apparent reason.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Jan 2005
    Posts
    204
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void remover_newline(char *);
    
    struct dados {
    	char matricula[6]; /* 1 a mais por causa do \0 no final */
    	char nome[41];     /* mesma coisa... */
    	char curso[21];    /* mesma coisa... */
    	char nota[3];      /* mesma coisa... */
    } aluno;
    
    int main(void)
    {
    	char linha[40];
    	FILE *dados;
    	
    	
    	
    	dados = fopen("dados.txt", "r");
    	if(dados == NULL){
    		printf("dados.txt - arquivo desconhecido\n");
    		getchar();
    		exit(1);
    	}
    
    	while(fgets(linha, sizeof(linha), dados) != NULL){
    		
    		remover_newline(linha);
    		strcpy(aluno.matricula, linha);
    
    		fgets(linha, sizeof(linha), dados);
    		remover_newline(linha);
    		strcpy(aluno.nome, linha);
    
    		fgets(linha, sizeof(linha), dados);
    		remover_newline(linha);
    		strcpy(aluno.curso, linha);
    
    		fgets(linha, sizeof(linha), dados);
    		remover_newline(linha);
    		strcpy(aluno.nota, linha);
    
    		printf("aluno.matricula: %s\n", aluno.matricula);
    		printf("aluno.nome: %s\n", aluno.nome);
    		printf("aluno.curso: %s\n", aluno.curso);
    		printf("aluno.nota: %s\n\n", aluno.nota);
    
    		/* pula a linha em branco */
    		fgets(linha, sizeof(linha), dados);
    	}
    
    	fclose(dados);
    
    	return 0;
    }
    
    void remover_newline(char *linha)
    {
    	char *ptr;
    
    	ptr = strchr(linha, '\n');
    	if(ptr != NULL)
    		*ptr = '\0';
    }
    dados.txt:
    Code:
    20451
    Denis Rocha da Silva
    Arquitetura Arquiter
    5
    
    98364
    Tom Hanks
    Teatro
    38
    
    44076
    Nicolas Cage
    Futebol
    44
    
    10902
    Sabrina da Silva Sauro
    Basquete
    3
    
    12008
    Charles Petzold
    Tiro ao alvo
    12
    So, is this correct now?

  9. #9
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    I'm assuming you changed the data line for nota? There's a fundamental flaw in your program and if you fixed it, you wouldn't have to worry about any buffer overflow problems. Look at how you're reading in a line:
    Code:
    		fgets(linha, sizeof(linha), dados);
    		remover_newline(linha);
    		strcpy(aluno.nome, linha);
    The use of linha is problematic because linha is bigger than your smallest struct member. I'd go with one of three options to fix it:
    1) Forget linha...get rid of it. Make your struct members 1 element bigger than you're ultimately going to need. Then you can just read in a line like so:
    Code:
    		fgets(aluno.nome, sizeof(aluno.nome), dados);
    		remover_newline(aluno.nome);
    2) Make sure linha is at least one bigger than the largest struct member and then use the size of the struct member as the second argument to fgets(). Something like:
    Code:
    		fgets(linha, sizeof(aluno.nome)+1, dados);
    		remover_newline(linha);
    		strcpy(aluno.nome, linha); // If remover_newline() didn't remove a newline it will still overflow.
    3) Use strncpy() instead of strcpy():
    Code:
    		fgets(linha, sizeof(linha), dados);
    		remover_newline(linha);
    		strncpy(aluno.nome, linha, sizeof(aluno.nome));
                    aluno.nome[sizeof(aluno.nome)-1] = '\0';
    Personally, I'd probably go with option 3.
    If you understand what you're doing, you're not learning anything.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File transfer- the file sometimes not full transferred
    By shu_fei86 in forum C# Programming
    Replies: 13
    Last Post: 03-13-2009, 12:44 PM
  2. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM
  3. Replies: 20
    Last Post: 06-12-2005, 11:53 PM
  4. Replies: 3
    Last Post: 03-04-2005, 02:46 PM
  5. Problem reading file
    By winsonlee in forum C Programming
    Replies: 2
    Last Post: 04-23-2004, 06:52 AM