fread struct with unknown size

This is a discussion on fread struct with unknown size within the C Programming forums, part of the General Programming Boards category; Hi, I'm trying to read out some structs I saved in a binary file. Can I just fread(struct, sizeof(struct)... ? ...

  1. #1
    Registered User
    Join Date
    Mar 2006
    Posts
    24

    fread struct with unknown size

    Hi,

    I'm trying to read out some structs I saved in a binary file.
    Can I just fread(struct, sizeof(struct)... ?
    I can't find any info about that..

    This crashes (saving to linked list):
    Code:
    // The struct
    typedef struct quest
    {
            char question[100];
            char answer[MAX_ANSWERS][100];
            int  correct[MAX_ANSWERS];
            struct quest* next;
    } QUEST;
    
    int get_questions(QUEST** qhead, char* category)
    {
    	 FILE* fp = NULL;
    	 QUEST* q = NULL;
    	 QUEST* qprev = NULL;
    
    	 char* filename = NULL;
    	 int i = 0;
        
    	 filename = malloc(strlen(category)+5);
    	 getfilename("cat/", category, filename);
    
    	 if ( (fp=fopen(filename, "rb"))==NULL )
    	 {
    		printf(ERROR_BESTAND);
    		exit(0);
    	 }
    	 while(!feof(fp))
    	 {
    		if (qprev!=NULL)
    			qprev = q;
    		fread(q, sizeof(QUEST), 1, fp);
    		if (qprev==NULL)
    			(*qhead) = q;
    		qprev->next = q;
                                    q = NULL;
                                    i++;
    	 }
    
        return i;
    }

  2. #2
    Registered User
    Join Date
    Mar 2006
    Posts
    24
    ARgh sorry, I forgot I changed it to fixed sizes

  3. #3
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    When working with double-asterisk pointers you have to dereference the first pointer. *qprev references the caller's pointer and that's the one you want to change.

    Code:
    	//if (qprev!=NULL) <<< these two lines are unnecessry
    	//		qprev = q;            
                   q = malloc(sizeof(QUEST); <<< need to allocate memory for the object 
    		fread(q, sizeof(QUEST), 1, fp);	
                    if (*qprev==NULL)
    			*qhead = q;
                   else (add q to the end of the linked list)                     
    		//*qprev->next = q;
                            //q = NULL;<<<this line is unnecessary
                                    i++;
    In summary here is what that should look like
    Code:
    QUEST* tail = NULL;
    QUEST* q = NULL;
    QUEST obj;
    while( fread(&obj,1,sizeof(QUEST),fp) == sizeof(QUEST))
    {
           q = malloc(sizeof(QUEST));
           memcpy(q,&obj,sizeof(QUEST));
           q->next = NULL;
           if (*qprev==NULL)
           {
    	   *qhead = q;
           }
           else
           {
                  tail->next = q;
           }
           tail = q;
    }
    Last edited by Ancient Dragon; 03-27-2006 at 05:05 AM.

  4. #4
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,548
    > fread(q, sizeof(QUEST), 1, fp);
    You use the return result (which you're still not checking) to determine if you read a whole struct or not.
    If you did manage to read it, then append it to your list.
    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.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  5. #5
    Registered User
    Join Date
    Mar 2006
    Posts
    24
    @Salem: What do you mean by checking the result ? Isn't he always going to get the size of the struct out of the file ?

    UPDATE: Kay got it
    Last edited by ReggieBE; 03-27-2006 at 09:34 AM.

  6. #6
    Registered User
    Join Date
    Mar 2006
    Posts
    24
    @Dragon: why are you using memcpy ? Isn't this for strings ?
    (Sorry for asking so many questions, but I have to be able to explain every single line for school)

  7. #7
    Registered User
    Join Date
    Mar 2006
    Posts
    24
    Hmm when I run my code in debug mode. Step by Step, it works. But the moment I just run it, it crashes:

    Code:
    int main(void)
    {
    	 QUEST* qp = NULL;
    	 int i,j=0;
         i = get_questions(&qp, "realtest");
         for(j=0;j<i;j++)
         {
            printf("Vraag %d: %s\n", j+1, qp->question);
            qp = qp->next;
         }
    	 getchar();
    	 return 0;
    }
    
    int get_questions(QUEST** qhead, char* category)
    {
    	 FILE* fp = NULL;
    	 QUEST* q = NULL;
    	 QUEST* qtail = NULL;
    	 QUEST  qtmp;
      
    	 char* filename = NULL;
    	 int i = 0;
        
    	 filename = malloc(strlen(category)+5);
    	 getfilename("../cat/", category, filename);
                     fp = fopen(filename, "rb");
    	 if (!fp)
    	 {
    		printf(ERROR_BESTAND);
    		exit(0);
    	 }
    	 
    	 while((fread(&qtmp, sizeof(QUEST), 1, fp) == 0) )
    	 {
                          q = malloc(sizeof(QUEST));
                          memcpy(q, &qtmp, sizeof(QUEST));
                          q->next = NULL;
    	      if (qtail==NULL)
                                 *qhead = q;
                          else
    	            qtail->next = q;
                          qtail = q;
                          i++;
          }
          return i;
    }
    Last edited by ReggieBE; 03-27-2006 at 10:06 AM. Reason: Added main()

  8. #8
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    Quote Originally Posted by ReggieBE
    @Dragon: why are you using memcpy ? Isn't this for strings ?
    No, use strcpy() for strings. memcpy can be used to copy any unspecified data type from one memory location to another. That is why you have to specify the number of bytes to be copied. The function makes absolutely no assumptions about the data types or if there is enough memory in the destination buffer. You can't use it indiscriminately or your program will surly crash.

  9. #9
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    try this. Use another pointer to iterate through the linked list so that you don't destroy the original pointer. And don't forget to destroy the list when you are done with it (which is why you don't want to change the original pointer).

    You don't need that integer to indicate the number of nodes in the list (unless there is some other reason for it).

    Code:
        get_questions(&qp, "realtest");
        if(qp != NULL)
        {
               QUEST* p =  qp;
               while(p != NULL)
               {
                       printf("Vraag %d: %s\n", j+1, p->question);
                      p = p->next;
               }
       }

  10. #10
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,548
    > while((fread(&qtmp, sizeof(QUEST), 1, fp) == 0)
    Try while == 1

    > else
    1. Use lots of braces to make your intentions clear - a lot of this code gets executed anyway, whether the condition is true or false.
    Also, work on your indentation, especially when posting the code on the forum. It may look good in your smart IDE, but on a simple web page, it looks crap.
    Hint: don't mix spaces and tabs.
    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.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  11. #11
    Registered User
    Join Date
    Mar 2006
    Posts
    24
    Also, work on your indentation, especially when posting the code on the forum. It may look good in your smart IDE, but on a simple web page, it looks crap.
    Yeah, I'm using Dev-C++ and he gives me a hard time aligning sometimes :s

    @Dragon: I tried your code but it still crashes :s

    EDIT: BTW Any other suggestions for a c ide ?
    Last edited by ReggieBE; 03-27-2006 at 10:50 AM.

  12. #12
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    If you changed the structure between the time you wrote the data file and the time you are reading it, then you will have to re-create the data file with the new structure.

  13. #13
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    This works ok for me, which is nearly the same as you posted. So I suspect the data file isn't correct.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    // The struct
    #define MAX_ANSWERS  20
    typedef struct quest
    {
            char question[100];
            char answer[MAX_ANSWERS][100];
            int  correct[MAX_ANSWERS];
            struct quest* next;
    } QUEST;
    
    
    void get_questions(FILE* fp,QUEST** qhead, char* category)
    {
    	QUEST* tail = NULL;
    	QUEST* q = NULL;
    	QUEST obj;
    	while( fread(&obj,1,sizeof(QUEST),fp) == sizeof(QUEST))
    	{
    		q = (QUEST*)malloc(sizeof(QUEST));
    		memcpy(q,&obj,sizeof(QUEST));
    		q->next = NULL;
    		if (*qhead == NULL)
    		{
    			*qhead = q;
    		}
    		else
    		{
    			tail->next = q;
    		}
    		tail = q;
    	}
    }
    
    
    void CreateDataFile(const char* filename)
    {
    	QUEST q;
    	FILE* fp = fopen(filename,"rw");
    	memset(&q,0,sizeof(QUEST));
    	if(fp != 0)
    	{
    		strcpy(q.question,"One");
    		fwrite(&q,1,sizeof(QUEST),fp);
    		strcpy(q.question,"Three");
    		fwrite(&q,1,sizeof(QUEST),fp);
    		strcpy(q.question,"four");
    		fwrite(&q,1,sizeof(QUEST),fp);
    		fclose(fp);
    	}
    
    }
    int main(int argc, char* argv[])
    {
    	
    	QUEST* qp = NULL;
    	FILE* fp = fopen("file.dat","rb");
    	get_questions(fp,&qp, "realtest");
    
    	if(qp != NULL)
    	{
    		int j = 1;
    		QUEST* p =  qp;
    		while(p != NULL)
    		{
    			printf("Vraag %d: %s\n", j++, p->question);
    			p = p->next;
    		}
    	}
    
    	return 0;
    }
    Last edited by Ancient Dragon; 03-27-2006 at 11:22 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. An exercise in optimization
    By Prelude in forum Contests Board
    Replies: 10
    Last Post: 04-29-2005, 03:06 PM
  2. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 09:33 AM
  3. Bi-Directional Linked Lists
    By Thantos in forum C Programming
    Replies: 6
    Last Post: 12-11-2003, 09:24 AM
  4. Replies: 11
    Last Post: 03-25-2003, 04:13 PM
  5. Contest Results - May 27, 2002
    By ygfperson in forum A Brief History of Cprogramming.com
    Replies: 18
    Last Post: 06-18-2002, 01:27 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21