Link to home
Start Free TrialLog in
Avatar of The_Kingpin08
The_Kingpin08

asked on

Problem comparing struct's record

Hi all, I need to compare 2 records from 2 different structs and would like to know if its possible and if yes, how to do it. I think I've heard you could do it as long as the two struct were define identically...

The problem occurs because I need to format the text to write in a new file. I've sort the informations and now if some item (books in my case) have the same vakue (the same subject in my case), I need to print this information once only. Here's how I thought it could be made. I also tried using the funnction strcmp but it didn't worked.

// We go throught all the books we created
for( i = 0; i < num_books - 1; ++i )
                // This is where I need to format
            if(i>0 && books[i].subject==books[i--].subject)
            {
                        // We print onyl the author's name because the subject is identical
                  fprintf(file_out, "\t\t %s\n", books[i].autor);
            }
            else
            {
                        // We print both the subject and author's name, it's a new subject category
                  fprintf(file_out, "%s\t %s\t\n", books[i].subject, books[i].autor);
            }
    fprintf(file_out, "\n" );

Also I'd like to know if there's a better way to format the text going in a file, with columns always at the same place, etc.

SUBJECT                             AUTHOR
Computers                          Smith, Jim
                                          Hopkin, Marc
                                          Moore, Jack
Graphic Animation                Black, Tim
                                          James, Martin
Historical Demography 1.0    Young, Mike
Organic science                   Walters, Jennifer
X                                        Lane, Rick
 ...


Thanks all,
Frank
SOLUTION
Avatar of PaulCaswell
PaulCaswell
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
P.S.

It is more usual to use:

for( i = 0; i < num_books - 1; i++ )

as the effect of:

for( i = 0; i < num_books - 1; ++i )

can be visually ambiguous and open to misinterpretation by both readers and compilers.

Paul
Avatar of Kent Olsen
Hi The_Kingpin08,

You can compare two structures that are based on the same definition, but there are a couple of things to be considered.

typedef struct
{
  int    SomeInt;
  char SomeName[40];
} MyStruct_t;

MyStruct_t *Struct1;
MyStruct_t *Struct2;

Assuming that the two structures are properly allocated, you can compare them with memcmp().

if (memcmp (Struct1, Struct2, sizeof (MyStruct_t)))
  /* Compare failed  */

This should give you a valid test 100% of the time.  However, modifying the structure slightly may cause hard-to-find compare problems.

typedef struct
{
  char SomeInt;
  char SomeName[40];
} MyStruct_t;

In this case, the comparison might result in false failures.  By default, C aligns data on word boundaries.  This means that there are some number of unused bytes between SomeInt and SomeName.  If the structure wasn't initialized to a known value when the memory was allocated, you have no way of knowing what is in this "dark area".  It is usually whatever was in this block of memory the last time that it was assigned, which means it must be considered to be "random".

Allocating the memory for the structure with calloc() will solve this as the function initialized the entire structure to zero.

But there is still another gotcha.

typedef struct
{
  int    SomeInt;
  char *SomeName;
} MyStruct_t;


SomeName is a pointer within the structure.  It's quite possible that SomeName in one structure points to a string that is identical to the string being pointed to in another structure.  Yet a compison test of the structures will fail because they point to different addresses.  If your testing for exactness, you want the test to fail.  But if your testing whether the two structures contain {1, "Johnson"} you probably want the test to return SUCCESS.


In short, it's a dangerous kind of test that should be performed ONLY when certain, specific, conditions and needs are met.

Kent
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>Also I'd like to know if there's a better way to format the text going in a file, with columns always at the same place, etc.
Try saving it in CSV format! Then the results can be imported into databases or spreadsheets.

Or you could try:

          // Print subject on first line or when it changes.
          int printSubject = (i==0) || (strcmp(books[i].subject,books[i-1].subject) != 0);
          // Do the print.
          fprintf ( file_out, "%20.20s%20.20s\n", printSubject?books[i].subject:"", books[i].autor );

I've chosen 20 as a reasonable column width. You can chose any other.

Paul
Disagree with Kdo:

>You can compare two structures that are based on the same definition, but there are a couple of things to be considered.
>typedef struct {
>  int    SomeInt;
>  char SomeName[40];
>} MyStruct_t;
>MyStruct_t *Struct1;
>MyStruct_t *Struct2;
>Assuming that the two structures are properly allocated, you can compare them with memcmp().
>if (memcmp (Struct1, Struct2, sizeof (MyStruct_t)))
>  /* Compare failed  */
>This should give you a valid test 100% of the time.  However, modifying the structure slightly may cause hard-to-find compare problems.

This won't ensure a correct comparison because of char array nature

Even if SomeName is loaded with the same string, let's say "John Doe", which occupies 8 characters plus null character, remaining 31 character will have garbage because them are not used, so comparison could fail if both "garbages" are not the same.
In those cases (where character arrays are present) you have to build your own comparison function with member by member individual comparisons.
Avatar of grg99
grg99

In some very special cases you can compare structs by comparing their memory images, but there are MANY MANY gotchas:

(1)  Some structs have hidden padding bytes that may have random garbage in them, thereby failing a strict byte by byte comparison.

(2)  Any fields that are pointers, sometimes you do want to compare the pointers values (when comparing for very strict type  identity), sometimes you want to compare what they point to, or maybe several levels down in indirection from that.  A simple byte compare won't and can't do this.

(3)  Some fields you may want to compare in a case-independent fashion.  For instance a subject name may work better compared case-insensitive, while a password field is (usually) case sensitive.

(4)  In some cases you may want to compare the numeric values for equality, or "close" equality, even though they may be radically different formats, like some left justified, space filled, or right justified, leading zeroes, or some with leading plus signs.  A simple structure compare won't work for these either.

(5)  You may want to comapre dates for equality, when they may be written in one of many formats: 10-Jan-2001, 01/10/01, 10/1/1, 10/01/2001, and many others.  

--------------------------------
The cleanest way might be to write a structure comparision function that handles each field in its own way:

a rough example:

int MyStructCompare( MyStruct A, MyStruct B )
{
    int Ans;
    Ans = strnocasecmp( A->Name, B->Name );
   if( Ans == 0 ) {
         Ans = strdatecmp( A->SellDate, B->SellDate );
          if( Ans == 0 )  Ans = IntCmp( A->Age, B->Age, 5 )
   }
   return( Ans )
}
... where strnocasecmp() does a case-independent compare (ignoring leading and trailing blanks too)
.... where strdatecmp() accepts a variery of date styles
.... where IntCmp() compares strings for integer nearness, allowing for leading zeroes and spaces and signs
Avatar of The_Kingpin08

ASKER

Ok thanks  all for the quick answers.

BTW is there a way to force my date into a certain format  when printing in the file ?

Like if my date is 1900-1-1  to print 1900-01-01 instead ?

Thanks againn,

Frank
     printf((m > 9)?"%d-%d\n": "%d-0%d-", y, m);           //y = year, m = month, d = day.. if that is how u mean
      printf((d > 9)?"%d\n": "0%d\n", d);
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Yes thanks Kent, it workd perfectly yesterday except sometimes the 0 didn't appeared. Gonna try this directly in the print instead.

BTW didn't I posted my name before ? ;)

Frank

Hi Frank,

You need the leading '0's in the format string to force leading zeros in the output.


Kent