Solved

Problem comparing struct's record

Posted on 2004-10-27
398 Views
Last Modified: 2010-04-15
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
0
Question by:The_Kingpin08
    13 Comments
     
    LVL 16

    Assisted Solution

    by:PaulCaswell
    >>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
     
    LVL 16

    Expert Comment

    by:PaulCaswell
    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
     
    LVL 45

    Expert Comment

    by:Kdo
    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
     
    LVL 5

    Accepted Solution

    by:
    >>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
     
    LVL 16

    Expert Comment

    by:PaulCaswell
    >>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
     
    LVL 55

    Expert Comment

    by:Jaime Olivares
    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
     
    LVL 55

    Expert Comment

    by:Jaime Olivares
    In those cases (where character arrays are present) you have to build your own comparison function with member by member individual comparisons.
    0
     
    LVL 22

    Expert Comment

    by: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
    0
     

    Author Comment

    by:The_Kingpin08
    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
     
    LVL 5

    Expert Comment

    by:van_dy
         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
     
    LVL 45

    Assisted Solution

    by:Kdo
    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
     

    Author Comment

    by:The_Kingpin08
    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
     
    LVL 45

    Expert Comment

    by:Kdo

    Hi Frank,

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


    Kent
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone. Privacy Policy Terms of Use

    Featured Post

    How to run any project with ease

    Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
    - Combine task lists, docs, spreadsheets, and chat in one
    - View and edit from mobile/offline
    - Cut down on emails

    An Outlet in Cocoa is a persistent reference to a GUI control; it connects a property (a variable) to a control.  For example, it is common to create an Outlet for the text field GUI control and change the text that appears in this field via that Ou…
    This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
    The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
    The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.

    875 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    12 Experts available now in Live!

    Get 1:1 Help Now