Thread: Am I writing binary data correctly

  1. #1
    Registered User
    Join Date
    Jan 2013
    Posts
    42

    Am I writing binary data correctly

    I am having problems either writing data to a binary file or reading from the file. Through the process of elimination I am posting the code where the data is written to file to see if I can eliminate that as an option. I know the data is being processed correctly because, through the use of another function, I can view the data.

    I also know that fwrite must be including some padding because the file size ends up being 576 bytes after it is written instead of 540 bytes (the size it would be if no padding is used).

    Here is my struct:

    Code:
    typedef struct {
        char teams[25];
        float wins;
        float losses;
        float pct;
        int runsScored;
        int runsAgainst;
    } STATISTICS;
    Here is where I initialize it:

    Code:
    STATISTICS stats[12] =
            {
                {"Anaheim Arrays", 0.0, 0.0, .000, 0, 0},
                {"Pittsburg Pointers", 0.0, 0.0, .000, 0, 0},
                {"Indianapolis Integers", 0.0, 0.0, .000, 0, 0},
                {"Denver Double", 0.0, 0.0, .000, 0, 0},    
                {"Sacremento Strings", 0.0, 0.0, .000, 0, 0},
                {"Vancouver Vectors", 0.0, 0.0, .000, 0, 0},        
                {"Minnesota Mallocs", 0.0, 0.0, .000, 0, 0},
                {"Fargo Floats", 0.0, 0.0, .000, 0, 0},
                {"Chicago Callocs", 0.0, 0.0, .000, 0, 0},
                {"Dallas Delimeters", 0.0, 0.0, .000, 0, 0},
                {"San Diego Structs", 0.0, 0.0, .000, 0, 0},    
                {"Washington Destroyers", 0.0, 0.0, .000, 0, 0}
        };
    and here is the function that writes my data. The sA array is only used to change the scheduled games based on the variable week.

    Code:
    void schedule(STATISTICS stats[]) { //http://www.crowsdarts.com/roundrobin/sched12.html
        FILE *f;
        int sA[12], week = 0, runsPerGameA = 0, runsPerGameB = 0, runsAgainstA = 0, runsAgainstB = 0;
        int index, a = 0, b = 1, i = 0;
    
    
        f = fopen("Cleague.bin", "wb");
        
        week = stats[0].wins + stats[0].losses + 1;
        
        switch (week) {
            case 1:
                sA[0]=0, sA[1]=1, sA[2]=2, sA[3]=3, sA[4]=4, sA[5]=5, sA[6]=6, sA[7]=7, sA[8]=8, sA[9]=9, sA[10]=10, sA[11]=11;
                break;            
            case 2:
                sA[0]=10, sA[1]=0, sA[2]=1, sA[3]=2, sA[4]=3, sA[5]=4, sA[6]=5, sA[7]=6, sA[8]=7, sA[9]=8, sA[10]=11, sA[11]=9;
                break;
            case 3:
                sA[0]=0, sA[1]=2, sA[2]=3, sA[3]=1, sA[4]=4, sA[5]=6, sA[6]=7, sA[7]=5, sA[8]=9, sA[9]=10, sA[10]=8, sA[11]=11;
                break;
            case 4:
                sA[0]=5, sA[1]=0, sA[2]=1, sA[3]=10, sA[4]=6, sA[5]=3, sA[6]=2, sA[7]=9, sA[8]=8, sA[9]=4, sA[10]=11, sA[11]=7;
                break;
            case 5:
                sA[0]=9, sA[1]=0, sA[2]=1, sA[3]=8, sA[4]=2, sA[5]=10, sA[6]=3, sA[7]=5, sA[8]=7, sA[9]=4, sA[10]=6, sA[11]=11;
                break;
            case 6:
                sA[0]=0, sA[1]=8, sA[2]=9, sA[3]=1, sA[4]=3, sA[5]=7, sA[6]=6, sA[7]=2, sA[8]=10, sA[9]=4, sA[10]=11, sA[11]=5;
                break;
            case 7:
                sA[0]=0, sA[1]=3, sA[2]=5, sA[3]=1, sA[4]=2, sA[5]=7, sA[6]=6, sA[7]=9, sA[8]=8, sA[9]=10, sA[10]=4, sA[11]=11;
                break;
            case 8:
                sA[0]=0, sA[1]=6, sA[2]=7, sA[3]=1, sA[4]=8, sA[5]=2, sA[6]=4, sA[7]=9, sA[8]=10, sA[9]=5, sA[10]=11, sA[11]=3;
                break;
            case 9:
                sA[0]=4, sA[1]=0, sA[2]=1, sA[3]=6, sA[4]=7, sA[5]=9, sA[6]=8, sA[7]=5, sA[8]=10, sA[9]=3, sA[10]=2, sA[11]=11;
                break;
            case 10:
                sA[0]=7, sA[1]=0, sA[2]=10, sA[3]=6, sA[4]=4, sA[5]=2, sA[6]=9, sA[7]=5, sA[8]=3, sA[9]=8, sA[10]=11, sA[11]=1;
                break;
            case 11:
                sA[0]=8, sA[1]=6, sA[2]=1, sA[3]=4, sA[4]=5, sA[5]=2, sA[6]=7, sA[7]=10, sA[8]=3, sA[9]=9, sA[10]=0, sA[11]=11;
                break;
            case 12:
                printf("\t\tThe Season is over. Here are the final standings\n");
                showStats(stats, -1);
                break;
                
        }
        printf("Please enter the results from the week %i games.\n\n\n", week);
        printf("The home team %s plays the visiting %s\n", stats[sA[0]].teams, stats[sA[1]].teams);
        printf("The home team %s plays the visiting %s\n", stats[sA[2]].teams, stats[sA[3]].teams);
        printf("The home team %s plays the visiting %s\n", stats[sA[4]].teams, stats[sA[5]].teams);
        printf("The home team %s plays the visiting %s\n", stats[sA[6]].teams, stats[sA[7]].teams);    
        printf("The home team %s plays the visiting %s\n", stats[sA[8]].teams, stats[sA[9]].teams);
        printf("The home team %s plays the visiting %s\n", stats[sA[10]].teams, stats[sA[11]].teams);
        pause;
        cls;
            
            
        for (index = 0; index < 6; index++){
            printf("Enter the runs scored for %s  :", stats[sA[a]].teams);
            scanf("%i", &runsPerGameA);
            printf("Enter the runs scored for %s: ", stats[sA[b]].teams);
            scanf("%i", &runsPerGameB);
            runsAgainstA = runsPerGameB;
            runsAgainstB = runsPerGameA;
        
            if (runsPerGameA  < runsPerGameB){
                stats[sA[a]].losses += 1;
                stats[sA[b]].wins += 1;
            }
            else {
                stats[sA[a]].wins += 1;
                stats[sA[b]].losses += 1;
                }
        
            stats[sA[a]].runsScored += runsPerGameA;
            stats[sA[b]].runsScored += runsPerGameB;
            stats[sA[a]].runsAgainst += runsAgainstA;
            stats[sA[b]].runsAgainst += runsAgainstB;
        
            if (stats[sA[a]].wins == 0){
                stats[sA[a]].pct = .000;
            }
            else {
                stats[sA[a]].pct = stats[sA[a]].wins / (stats[sA[a]].losses + stats[sA[a]].wins);
            }
        
            if (stats[sA[b]].wins == 0){
                stats[sA[b]].pct = .000;
            }
            else {
                stats[sA[b]].pct = stats[sA[b]].wins / (stats[sA[b]].losses + stats[sA[b]].wins);
            }
            a += 2;
            b += 2;
        }
        
        
        if (!f)
        {
            cls;
            printf("Unable to open file!");
            pause;
            exit (0);
        }
        for (i = 0; i < 12; i++){
            fwrite(&stats[i], sizeof(stats[i]), 1, f);
        }
        fclose(f);
    }
    Can someone tell me if this is where my problem lies or is it more likely at a different point in the program where I am reading from the file.

    Thanks in advance,

    Michael

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Troubleshooting a problem dealing with reading and writing to a binary file is difficult. But in order to help, you will probably need to show your read function. And really a small test program that just writes and reads your structure would probably be best.

    Jim

  3. #3
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    First, what is the value of this sizeof(stats[i]) ?
    Is it what you think it should be?
    If not, the struct packing might be why the size is off.

    FYI: Writing struct out as a whole is NOT portable to even the same Compiler version.
    It is better to write each element separately unless you do not care if your data is destroyed for each program update.

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  4. #4
    Registered User
    Join Date
    Jan 2013
    Posts
    42
    Thanks, here is the function that implements the fread portion. I also included the source file, in case anyone wanted to take a further look. As you notice, I did not include a file path but that is because it is easier for my instructor not to receive multiple different paths with each assignment.

    Code:
    void showStats(STATISTICS stats[], int finalize) {
        
        FILE *f;
        int i = 0, j, size = 12;
        f = fopen("Cleague.bin", "rb");
        
        if (f==NULL){
            perror("error");
        }
        
        while(fread(&stats[i], sizeof(stats[i]), 1, f) > 0){    
                i++;                                                
            }                                            
        
        for (i = 0; i < size-1; i++) {
          int max = i;
            for (j = i+1; j < size; j++) {
                if (stats[j].pct > stats[max].pct) {
                    max = j;
                }
            }
            if (max != i) { // if you're not changing position, don't swap
                STATISTICS temp = stats[i];
                stats[i] = stats[max];
                stats[max] = temp;
            }
        }
    
    
        
        i = 0;
        printf("================================================================\n");
        printf("                     2013 C league Standings\n");
        printf("================================================================\n\n\n");
        printf("      Team               Wins  Losses     pct.    Runs    Runs \n");
        printf("                                                  for    against\n");
        printf("________________________________________________________________\n\n");
          for (i=0; i<12; i++) {
            printf("%-25s %-6.f %-6.f %-10.03f %-8i %-8i\n", stats[i].teams, stats[i].wins, stats[i].losses,
                stats[i].pct, stats[i].runsScored, stats[i].runsAgainst);
        }
        fclose(f);
        printf("\n\n\n");
        pause;
        cls;
    
    
        if (finalize == -1) 
            exit(0);
    }
    Attached Files Attached Files

  5. #5
    Registered User
    Join Date
    Jan 2013
    Posts
    42
    Quote Originally Posted by stahta01 View Post
    First, what is the value of this sizeof(stats[i]) ?
    Is it what you think it should be?
    If not, the struct packing might be why the size is off.

    FYI: Writing struct out as a whole is NOT portable to even the same Compiler version.
    It is better to write each element separately unless you do not care if your data is destroyed for each program update.

    Tim S.
    I expected that stats[i] would be stats[i].teams, stats[i].wins, stats[i].losses, stats[i].pct, stats[i].runsScoredr and stats[i].runsAgainst.

    Thanks,

    Michael

  6. #6
    Registered User
    Join Date
    Jan 2013
    Posts
    42
    I originally had the fwrite to write each individual element one at a time. This program will never need to read individual elements. My instructor said it would be easier to write and read in one shot.

  7. #7
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    So, you know nothing about how structures are packed.
    And, you do not think it is worth your time to printf sizeof(stats[i]).

    Quote Originally Posted by generaltso78 View Post
    I expected that stats[i] would be stats[i].teams, stats[i].wins, stats[i].losses, stats[i].pct, stats[i].runsScoredr and stats[i].runsAgainst.

    Thanks,

    Michael
    And, you will be wrong with most Compilers in the real world.
    In the real world the size of struct are adjusted based on compiler options.
    The compilers could add bytes to make sure all the floats/doubles are aligned on 16/32/64 bit boundaries.

    I hope I never work with students from your school.

    Tim S.
    Last edited by stahta01; 03-06-2013 at 01:52 PM.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  8. #8
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    I noticed a couple of things at first glance, First fflush() is not defined in the standard to work with input streams, only output streams.

    Next in the following snippet:
    Code:
    	f = fopen("Cleague.bin", "wb");
    	if (f==NULL){
    		perror("error");
    	}
    	fseek(f, 0, SEEK_END);
    	if (ftell(f) == 0) {   // file is empty...
    		fwrite(&stats, sizeof(stats), 1, f);
    	}
    	else {    //file is not empty, reset pointer to beginning
    		fseek(f, 0, SEEK_SET);
    	}
    	fclose(f);
    Since you use the "wb" open mode the file will always be empty, if it opened correctly. The "w" open mode erases the file upon opening is that what you want?

    Also your read and write routines seem to be fine. This is how I tested the write/read.

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <stddef.h>
    #define MAXSIZE 200
    #define TEAMSIZE 12
    
    #define pause system("pause")
    #define cls system("cls")
    
    //declare structs here
    typedef struct {
    	char teams[25];
    	float wins;
    	float losses;
    	float pct;
    	int runsScored;
    	int runsAgainst;
    } STATISTICS;
    
    void displayMenu();
    void showStats(STATISTICS stats[], int finalize);
    
    //begin main
    int main(){
    
    	displayMenu();
    
    
    	return 0;
    }
    
    void displayMenu() {
    	int userChoice = 0,	i, week = 1;
    	FILE *f;
    
    	STATISTICS stats[12] =
    		{
    			{"Anaheim Arrays", 10.0, 30.0, 2.000, 2, 2},
    			{"Pittsburg Pointers", 0.0, 0.0, .000, 0, 0},
    			{"Indianapolis Integers", 0.0, 0.0, .000, 0, 0},
    			{"Denver Double", 0.0, 0.0, .000, 0, 0},
    			{"Sacremento Strings", 0.0, 0.0, .000, 0, 0},
    			{"Vancouver Vectors", 0.0, 0.0, .000, 0, 0},
    			{"Minnesota Mallocs", 0.0, 0.0, .000, 0, 0},
    			{"Fargo Floats", 0.0, 0.0, .000, 0, 0},
    			{"Chicago Callocs", 0.0, 0.0, .000, 0, 0},
    			{"Dallas Delimeters", 0.0, 0.0, .000, 0, 0},
    			{"San Diego Structs", 0.0, 0.0, .000, 0, 0},
    			{"Washington Destroyers", 30.0, 10.0, 3.000, 4, 6}
    	};
    	f = fopen("Cleague.bin", "wb");
    	if (f==NULL){
    		perror("error");
    		exit(10);
    	}
    
    		fwrite(&stats, sizeof(stats), 1, f);
    	fclose(f);
    	STATISTICS Istats[12];
    	showStats(Istats, 0);
    
    }
    
    
    void showStats(STATISTICS stats[], int finalize) {
    
    	FILE *f;
    
    	int i = 0, j, size = 12;
    	f = fopen("Cleague.bin", "rb");
    
    	if (f==NULL){
    		perror("error");
    	}
    
    	while(fread(&stats[i], sizeof(stats[i]), 1, f) > 0){
    			i++;
    		}
    
    	i = 0;
    	printf("================================================================\n");
    	printf("                     2013 C league Standings\n");
    	printf("================================================================\n\n\n");
    	printf("      Team               Wins  Losses     pct.    Runs    Runs \n");
    	printf("                                                  for    against\n");
    	printf("________________________________________________________________\n\n");
      	for (i=0; i<12; i++) {
          printf("%-25s %-6.f %-6.f %-10.03f %-8i %-8i\n", stats[i].teams, stats[i].wins, stats[i].losses,
    			stats[i].pct, stats[i].runsScored, stats[i].runsAgainst);
    
    	}
    	fclose(f);
    	printf("\n\n\n");
    }
    Also note the sizeof() function can be tricky if you are not totally familiar with it, so it always pays to insure you have it correct.


    Jim
    Last edited by jimblumberg; 03-06-2013 at 01:54 PM.

  9. #9
    Registered User
    Join Date
    Jan 2013
    Posts
    42
    Thanks Jim,

    I cannot tell though if the displayMenu() writes correctly because the showStats() function is just outputting what is stored in memory in the array of structs.

    I know I am overwriting the file everytime with wb, that is the intent.

    to: Stahta01, I was not too lazy to write the printf sizeof command. I had not thought about it or really new it was available to use. I did put it in the code and it returned 48. Which is 3 bytes more than expected, so it seems that if padding is included with each element.

    I have heard of certain ways to prevent packing but have heard that they are not very portable as well.

    Mike

  10. #10
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Writing a "binary" file is never really totally portable because of several issues. One of these issues has to do with Endianness. If you are worried about packing then the best solution is to write each individual item to the file, and then when you read the file you read each individual item which you can then put into your structure for the rest of the program to use. But since you are deleting your file every time you open it, you shouldn't worry about any of these issues.

    Jim

  11. #11
    Registered User
    Join Date
    Sep 2008
    Location
    Toronto, Canada
    Posts
    1,834
    You can try #pragma pack - or whatever your compiler likes.

  12. #12
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    Start by reading the section on serialisation in "The Practice of Programming". They provide reasonably portable implementations of the functions pack and unpack, which work in a similar manner as printf and scanf. All your implementation needs to handle is strings (look up strncpy), floats (these are a bit tricky and you can usually get away with assuming the host implementation uses iee-754 natively, but if you want your code to be extra portable, you could probably find a portable iee-754 packer/unpacker somewhere), and 16-bit integers.

  13. #13
    Registered User
    Join Date
    Jan 2013
    Posts
    42
    As it turns out, everything was written fine for how I needed the program to operate.

    The problem lied with the fwrite that wrote to the file as soon as the program started. When I commented that out, I was able to exit the program and re-enter and view the stats on the file and they appeared how they should.

    Thanks to all for the help.

  14. #14
    Registered User
    Join Date
    Jan 2013
    Posts
    42
    Thanks Barney, my instructor could care less about portability but I do. I know that if I ever plan on pursuing anything beyond writing basic programs for class than I will need to have a better hold on portability.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. reading and writing data to a binary file
    By Eulogy in forum C Programming
    Replies: 14
    Last Post: 11-24-2012, 08:38 AM
  2. Writing binary data to a file
    By zacs7 in forum C Programming
    Replies: 5
    Last Post: 10-24-2007, 04:00 PM
  3. Help with Reading and writing binary data
    By Yasir_Malik in forum C Programming
    Replies: 3
    Last Post: 12-12-2004, 09:24 AM
  4. Writing binary data to a file (bits).
    By OOPboredom in forum C Programming
    Replies: 2
    Last Post: 04-05-2004, 03:53 PM
  5. Replies: 2
    Last Post: 12-16-2001, 09:09 PM