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
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-
{
// 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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
>>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,b ooks[i-1]. subject) != 0);
// Do the print.
fprintf ( file_out, "%20.20s%20.20s\n", printSubject?books[i].subj ect:"", books[i].autor );
I've chosen 20 as a reasonable column width. You can chose any other.
Paul
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,b
// Do the print.
fprintf ( file_out, "%20.20s%20.20s\n", printSubject?books[i].subj
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.
>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.
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
(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
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
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);
printf((d > 9)?"%d\n": "0%d\n", d);
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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
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
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