• C

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
The_Kingpin08Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

PaulCaswellCommented:
>>I also tried using the function strcmp but it didn't worked.
The strcmp method is the correct way to go. How did you do it and what didnt work.

>>books[i].subject==books[i--].subject
1. This compares the addresses of the two items, not their contents so it will almost always return false.
2. Using ...[i--] will not work for two reasons, a. 'i' will not be decremented untill AFTER the comparison and b. I suspect its not i-- you want, its i-1.

Try:
          if(i>0 && strcmp(books[i].subject,books[i-1].subject) == 0)

Paul

0
PaulCaswellCommented:
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
0
Kent OlsenData Warehouse Architect / DBACommented:
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
0
Firewall Management 201 with Professor Wool

In this whiteboard video, Professor Wool highlights the challenges, benefits and trade-offs of utilizing zero-touch automation for security policy change management. Watch and Learn!

van_dyCommented:
>>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 fprintf(FP, "%-30s %-20s\n", bookname, authorname);

FP -> points to the file your out put is going.

van_dy
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
PaulCaswellCommented:
>>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
0
Jaime OlivaresSoftware ArchitectCommented:
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.
0
Jaime OlivaresSoftware ArchitectCommented:
In those cases (where character arrays are present) you have to build your own comparison function with member by member individual comparisons.
0
grg99Commented:
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
0
The_Kingpin08Author Commented:
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
0
van_dyCommented:
     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);
0
Kent OlsenData Warehouse Architect / DBACommented:
Hi Frank (At last -- a REAL name!)

This is almost the same question that you had yesterday on reformatting dates.

printf ("%04d/%02d/%02d", Year, Month, Day);


Kent
0
The_Kingpin08Author Commented:
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
0
Kent OlsenData Warehouse Architect / DBACommented:

Hi Frank,

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


Kent
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.