Search code examples
cdynamic-memory-allocationfile-handlingscanf

sscanf till end of file in c


I have a C program that creates a binary file from a text file.

/*makeBinry.c*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, char *argv[]){
    char *ptext, *btext="file.bin";
    if(argc != 2){
        printf("Using default \"text.txt\" file to create mnemonics table\n");
        ptext = "text.txt";
    }else{
        ptext = argv[2];
    }

    FILE *fp, *fb;
    if(!(fp=fopen(ptext, "r"))){
        fprintf(stdout, "Error: File %s is not available\n", ptext);
        exit(1);
    }

    if(!(fb = fopen(btext, "wb"))){
        fprintf(stdout, "Error: File %s is cannot be opened to write\n", btext);
        exit(1);
    }

    int i, j, k;
    char s[8], c, stringed[20];

    while(!feof(fp)){
        memset(stringed, '\0', sizeof(stringed));
        fscanf(fp, "%X %d %c %d %[^\n]s", &i, &j, &c, &k, s);
        sprintf(stringed, "%X %d %c %d %[^\n]s", &i, &j, &c, &k, s);
        fwrite(stringed, 1, strlen(stringed), fb);
    }
    fprintf(stdout, "Success: %s file successfully created\n", btext);

    fclose(fp);
    fclose(fb);
    return 0;
}

I have another program that reads the data in the binary file and stores into an array.

/*mainProg.c*/
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>

typedef struct opStruct{
    int hexv, fv, kv;
    char str[8], key;
} node;

node* makeTable(char *filename){
    FILE *fp;
    if(!(fp = fopen(filename, "rb"))){
        fprintf(stdout, "Error: Unable to open file %s\n", filename);
        exit(1);
    }
    int hv, fv, kv;
    char s[8], c, str[20];

    while(!(feof(fp))){
        sscanf(fp,"%X %d %c %d %[^\n]s", &hv, &fv, &c, &kv, str);
        fprintf(stdout, "%X %d %c %d %s", hv, fv, c, kv, str);
    }
    fclose(fp);
    return NULL;
}

int main(){
    int i;
    char *filename = "file.bin";
    node *t_table = makeTable(filename);
    return 0;
}

When I run the mainProg.c the program goes into an infinite loop. I figured it is because fp is never increased. How could I increase the file pointer and still use sscanf to read the binary file in the formatted manner? I'm not allowed to use fread(). Since currently, I'm not creating the table the function makeTable returns NULL.

Also, since the number of lines in the binary file would be unknown, how can I create the array dynamically using realloc?


Solution

  • the following code

    1. properly handles error conditions
    2. actually produces a binary file, rather than just another text file
    3. uses the returned value from fscanf() rather than the faulty feof()
    4. uses perror() so system error message is displayed on stderr
    5. follows the axiom: only one statement per line and (at most) one variable declaration per statement

    error checking for the calls to fwrite(), fclose() could be added but they are VERY unlikely to produce an error

    and now the code

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
        struct record
        {
            unsigned int hv;
            int fv;
            int kv;
            char c;
            char s[8];
        };
    
    int main(int argc, char *argv[])
    {
        char *ptext, *btext="file.bin";
        if(argc != 2)
        {
            printf("Using default \"text.txt\" file to create mnemonics table\n");
            ptext = "text.txt";
        }
    
        else
        {
            ptext = argv[1];
        }
    
        FILE *fp;
        FILE *fb;
    
        if(!(fp=fopen(ptext, "r")))
        {
            perror( "fopen for read of text file failed" );
            fprintf(stdout, "Error: File %s is not available\n", ptext);
            exit(1);
        }
    
        if(!(fb = fopen(btext, "wb")))
        {
            perror( "fopen for write of binary file failed" );
            fprintf(stdout, "Error: File %s is cannot be opened to write\n", btext);
            fclose( fp ); // cleanup
            exit(1);
        }
    
        struct record myRecord;
    
        // produce binary file from text input
        // note: leading space in format string, to consume any left over newline, etc
        while(5 == fscanf(fp, " %X %d %c %d %7[^\n]",
                          &myRecord.hv,
                          &myRecord.fv,
                          &myRecord.c,
                          &myRecord.kv,
                          myRecord.s) )
        {
            fwrite( &myRecord, sizeof myRecord, 1, fb );
        }
    
        fprintf(stdout, "Success: %s file successfully created\n", btext);
    
        fclose(fp);
        fclose(fb);
        return 0;
    }
    
    
    
    /*mainProg.c*/
    #include <stdio.h>
    #include <stdlib.h>
    //#include <malloc.h>
    #include <string.h>
    
    //typedef struct opStruct
    //{
    //    int hexv, fv, kv;
    //    char str[8], key;
    //} node;
    
    struct record
    {
        unsigned int hv;
        int fv;
        int kv;
        char c;
        char s[8];
    };
    
    //node* makeTable(char *filename)
    void makeTable( char *filename )
    {
        FILE *fp;
        if(!(fp = fopen(filename, "rb")))
        {
            fprintf(stdout, "Error: Unable to open file %s\n", filename);
            exit(1);
        }
    
        // implied else, fopen successful
    
        struct record myRecord;
    
        // use fscanf() not sscanf()
        while( fread( &myRecord, sizeof myRecord, 1, fp) )
        {
            //sprintf( , "%X %d %c %d %s\n" hv, fv, c, kv, s );
            //fprintf(stdout, "%s", str );
            fprintf( stdout, "\n%X",   myRecord.hv  );
            fprintf( stdout, " %d",    myRecord.fv  );
            fprintf( stdout, " %c",    myRecord.c   );
            fprintf( stdout, " %d",    myRecord.kv  );
            fprintf( stdout, " %8.8s", myRecord.s   );
        }
        fprintf( stdout, "\n" ); // force flush
    
    
        fclose(fp);
        //return NULL;
    } // end function: makeTable
    
    
    int main( void )
    {
        //int i;
        char *filename = "file.bin";
        //node *t_table = makeTable(filename); // raises compiler warning about unused variable
        makeTable(filename);
        return 0;
    } // end function: main