Thread: qsort and unions

  1. #1
    Registered User
    Join Date
    Jan 2003
    Posts
    3

    qsort and unions

    I have a binary file that contains vaious length records that are held in structures.
    Here is a sample of the file :-
    I10014 010006 0002 I10006 010006 0001 I10006 049301 0009 I10022 012807 0008 I10049 012106 0099 I10065 054402 0100 C10081 COVER SYSTEMS LTD ALBOY RD;KINVER;SOUTH STAFFS; ; 000234500 0010000 I10103 020109 0507 I13005 030309 0007 I14001 013404 0044 I20001 022403 0202 I22225 016004 0032 I11703 035408 0090 I11703 054402 0300 R1986X 012106 0200 I19984 010103 0085 I1518X 012505 0002 I1518X 014001 0002 D31003
    I19186 013307 0090 I19321 021504 0088 I10006 035009 0009 I19321 03530X 0092 I19321 041408 0077 I13323 05200X 0250 I1454X 011002 0066 I1454X 014206 9999 D11525 I10189 010405 0010

    And here are the structures in which the records are held:-

    struct IRRecord{
    char RecordType;
    char CustCode[6];
    char PartNo[7];
    char Qty[5];
    };

    struct DRecord{
    char RecordType;
    char CustCode[6];
    };

    struct CRecord{
    char RecordType;
    char CustCode[6];
    char CustName[21];
    char CustAddress[61];
    char CustBal[10];
    char CreditLimit[8];
    };

    I need to sort the file into customer code order! I am using malloc and qsort.

    Firstly, I declare my union:-

    union Recs{
    struct IRRecord IRStr;
    struct DRecord DStr;
    struct CRecord CStr;
    }Allrecs;

    Then some code here......
    Then...

    total_recs = ftell(d_ptr) / sizeof(union Recs);
    fseek(d_ptr,0l,SEEK_SET);

    printf("%d",total_recs);

    /*Allocate portion of memory that is to be used in sort*/
    if ((memptr = (union Recs*)malloc(sizeof(union Recs)* (int)total_recs))==NULL)
    fprintf(stdout,"Cannot allocate buffer");

    memptr2 = memptr;

    /*Read file into memory*/
    if (fread(memptr,sizeof(union Recs),(int)total_recs,d_ptr)!= (int)total_recs)
    fprintf(stdout,"\nCannot read file");

    /*reset pointer to start of allocated file*/
    memptr = memptr2;

    /*now sort file*/
    qsort(memptr,(int)total_recs,sizeof(union Recs),compare);

    /*reset pointer again*/
    memptr = memptr2;

    /*now read back to file - sorted*/
    if (fwrite(memptr,sizeof (union Recs),(int)total_recs,s_ptr)!=(int)total_recs)
    fprintf(stdout,"\nError writing to sorted data file");

    /*reset pointer again*/
    memptr = memptr2;

    /*Now produce printout with totals on*/

    fclose(prn_ptr);
    fclose(d_ptr);
    fclose(s_ptr);
    free(memptr);

    This is my qsort function...

    int compare(const void *a,const void *b)
    {
    return strcmp(((union Recs *)a)->CStr.CustCode,((union Recs *)b)->CStr.CustCode);
    }

    Can anyone see where the problem is as its not quite right?

    If you need more info let me know!
    Cheers.

  2. #2
    ....
    Join Date
    Aug 2001
    Location
    Groningen (NL)
    Posts
    2,380
    Hmmm.

    If you declare a union, realise that the size of that union is the size of the largest datamember. So a union has a fixed length and not a variable length. Note that a union is shared memory.

    If I put two members A and B in a union U and A is larger than B, then the union has size sizeof (A). The union is shared memory, so A and B are sharing the same piece of memory. But because B is smaller than A, B does not use all claimed memory. If B is for example half the size of A, than B only uses the first half of the bytes. The other half is not used for B.

    So when you are going to read the file in blocks, where each block has the size of the union, it will read blocks of the size fo the largest member of the union. This means that smaller members in the file will be read incorrectly.

    You should change they way your read your file. Create a new function to read in the file. In some way that function reading the file must be able to read records of variable sizes.
    Last edited by Shiro; 01-31-2003 at 12:15 PM.

Popular pages Recent additions subscribe to a feed