Thread: Structure Passing, Index Problem

  1. #1
    Registered User ChipS's Avatar
    Join Date
    Oct 2011
    Posts
    16

    Structure Passing, Index Problem

    Why is this acting strange? Can someone explain why the first index doesn't print and why it increments into non-allocated memory?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #define BUFSIZE 25
    
    
    struct tag{
        char *first,
        *middle,
        *last;
    };
    
    
    struct social{
        struct tag name;
        char *socialnum;
    };
    
    
    void printdata(struct social a);
    
    
    int main (int argc, const char * argv[]) 
    {
        struct social fellow[5] = {
        {
            (char*)malloc(sizeof(char)*BUFSIZE), 
            (char*)malloc(sizeof(char)*BUFSIZE),
            (char*)malloc(sizeof(char)*BUFSIZE),
        },
            
        (char*)malloc(sizeof(char)*BUFSIZE),    
        };
        
        fellow[0].name.first = "Ally";
        fellow[0].name.middle = NULL;
        fellow[0].name.last = "Anderson";
        fellow[0].socialnum = "123456789";
        
        fellow[1].name.first = "Benny";
        fellow[1].name.middle = "Benjamin";
        fellow[1].name.last = "Baker";
        fellow[1].socialnum = "234567891";
        
        fellow[2].name.first = "Cathy";
        fellow[2].name.middle = NULL;
        fellow[2].name.last = "Cenders";
        fellow[2].socialnum = "345678912";
        
        fellow[3].name.first = "Darell";
        fellow[3].name.middle = "Dimebag";
        fellow[3].name.last = "Deezy";
        fellow[3].socialnum = "345678912";
        
        fellow[4].name.first = "Edward";
        fellow[4].name.middle = NULL;
        fellow[4].name.last = "Edison";
        fellow[4].socialnum = "456789123";
    
    
        for (int i=0; i < 5; i++)
        {
            printdata(fellow[i]);
        }
        free(fellow);
        
        puts("\n");
        return 0;
    }
    
    
    void printdata(struct social a)
    {
         printf("\n");
         printf("%s, %s ", a.name.last, a.name.first);
         if (a.name.middle) 
              printf("%c. ", toupper(*a.name.middle) );
        printf("-- %s", a.socialnum);
    }
    Output:
    //NULL - This is 0 index
    Anderson, Ally -- 123456789 // 1 index
    Baker, Benny B. -- 234567891 // 2 index
    Cenders, Cathy -- 345678912 // 3 index
    Deezy, Darell D. -- 345678912 // 4 index
    (gdb) continue
    Prob4(5304) malloc: *** error for object 0x7fff5fbff6f0: pointer being freed was not allocated
    *** set a breakpoint in malloc_error_break to debug
    Edison, Edward -- 456789123
    Last edited by ChipS; 10-15-2011 at 04:33 PM.

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Wow. Your code is almost a case study on maximising the number of ways to get things wrong.

    1) Do not use assignment to copy string literals into a character buffer. Use strcpy() (which is declared in the standard header <string.h>). For example;
    Code:
        strcpy(fellow[0].name.first, "Ally");       /*  not  fellow[0].name.first = "Ally"; */
    2) If you want to set a buffer to NULL, you need to free it first.
    Code:
    free(fellow[0].name.middle);
    fellow[0].name.middle = NULL;
    Note that, if you do this, and want to assign a string again, you need to do
    Code:
    fellow[0].name.middle = malloc(BUFSIZE);   /* reallocate.   See note 4 below for why I have removed sizeof(char) */
    strcpy(fellow[0].name.middle, "Gator");
    Keep in mind that strcpy() cannot accept NULL pointers as either argument (the resultant behaviour is indefined).

    3) Only free things you have malloced. The call free(fellow) is invalid, since fellow is not a pointer returned by malloc(). Instead you need to do
    Code:
    for (int i = 0; i < 5; ++i)
    {
        free(fellow[i].name.first);
        free(fellow[i].name.middle);
        free(fellow[i].name.last);
        free(fellow[i].socialnum);
    }
    With this, you don't need to worry if any of the pointers are NULL. free() correctly handles a NULL pointer, by doing nothing.

    4) The C standard defines sizeof(char) to be 1. You do not need to compute it.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    Registered User ChipS's Avatar
    Join Date
    Oct 2011
    Posts
    16
    Thanks for the reply, this is one of my first times actually using structures in C, still learning.

    Why can't I use an assignment when I'm using a char* type vs an array?

    I just wanted to set the string equal to NULL to see if I could get the result I needed that way for the book problem.

    I made the changes and now I just get a bad access as soon as it tries to store the string to fellow[0].socialnum..

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by ChipS View Post
    Why can't I use an assignment when I'm using a char* type vs an array?
    You can't assign an entire array with an equal sign*.


    Quzah.
    Last edited by quzah; 10-15-2011 at 05:33 PM. Reason: *some exceptions may apply, not to you right now though.
    Hope is the first step on the road to disappointment.

  5. #5
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by ChipS View Post
    Why can't I use an assignment when I'm using a char* type vs an array?
    Because the assignment is of pointers, not of the contents of the array.

    The assignment "some_pointer = some_array;" is valid, but is technically equivalent to "some_pointer = &some_array[0];" It does not copy elements of the array.

    So, if you do this;
    Code:
        char *x = malloc(25);
        x = "Hello";
        free(x);
    the behaviour is invalid. The assignment changes the value of x so it contains the address of the first character of "Hello". It does not copy contents of the string "Hello" into the 25 character buffer supplied by malloc(). The malloced memory is lost (since the value of x itself has changed) so the free() call gives undefined behaviour.

    The other problem I neglected to mention in my previous post is that your creation of fellow is invalid
    Code:
    struct social fellow[5] = {
        {
            (char*)malloc(sizeof(char)*BUFSIZE), 
            (char*)malloc(sizeof(char)*BUFSIZE),
            (char*)malloc(sizeof(char)*BUFSIZE),
        },
            
        (char*)malloc(sizeof(char)*BUFSIZE),    
        };
    This initialises fellow[0] so it contains four char pointers, each returned by malloc(). It does not replicate the malloc() calls for fellow[1] through fellow[4]. They get initialised to zero (the NULL pointer).

    So setting fellow[1].name.<anything> or fellow[1].socialnum to anything (whether by a pointer assignment, or using strcpy()) is invalid.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  6. #6
    Registered User ChipS's Avatar
    Join Date
    Oct 2011
    Posts
    16
    Ok thanks, fixed the memory problem. That was something I kind of just threw in there without thinking about to be honest. Can you explain why the program seems to skip the 0 index and output "Ally" on the 1st index instead?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <string.h>
    
    
    #define BUFSIZE 25
    
    
    struct tag {
        char *first,
             *middle,
             *last;
    };
    
    
    struct social {
        struct tag name;
        char *socialnum;
    };
    
    
    void printdata(struct social a);
    
    
    int main (int argc, const char * argv[])
    {
        struct social fellow[5];
    
    
        for (int i=0; i < 5; i++)
        {
            fellow[i].name.first = malloc(BUFSIZE);
            fellow[i].name.middle = malloc(BUFSIZE);
            fellow[i].name.last = malloc(BUFSIZE);
            fellow[i].socialnum = malloc(BUFSIZE);
        }
    
        strcpy(fellow[0].name.first, "Ally");
        strcpy(fellow[0].name.middle, "Amy");
        strcpy(fellow[0].name.last, "Anderson");
        strcpy(fellow[0].socialnum, "123456789");
    
        strcpy(fellow[1].name.first, "Benny");
        strcpy(fellow[1].name.middle, "Benjamin");
        strcpy(fellow[1].name.last, "Baker");
        strcpy(fellow[1].socialnum, "234567891");
    
        strcpy(fellow[2].name.first, "Cathy");
        strcpy(fellow[2].name.middle, "Cedar");
        strcpy(fellow[2].name.last, "Cenders");
        strcpy(fellow[2].socialnum, "345678912");
    
        strcpy(fellow[3].name.first, "Darell");
        strcpy(fellow[3].name.middle, "Dimebag");
        strcpy(fellow[3].name.last, "Deezy");
        strcpy(fellow[3].socialnum, "456789123");
    
        strcpy(fellow[4].name.first, "Edward");
        strcpy(fellow[4].name.middle, "Eddy");
        strcpy(fellow[4].name.last, "Edision");
        strcpy(fellow[4].socialnum, "567891234");
    
        for (int i=0; i < 5; i++)
        {
            printdata(fellow[i]);
        }
        for (int i=0; i < 5; i++)
        {
            free(fellow[i].name.first);
            free(fellow[i].name.middle);
            free(fellow[i].name.last);
            free(fellow[i].socialnum);
        }
    
    
        puts("\n");
        return 0;
    }
    
    
    void printdata(struct social a)
    {
        printf("\n");
        printf("%s, %s ", a.name.last, a.name.first);
        if (a.name.middle)
            printf("%c. ", *a.name.middle );
        printf("-- %s", a.socialnum);
    }
    
    
    
    Last edited by ChipS; 10-15-2011 at 05:54 PM.

  7. #7
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
     strcpy(fellow[0].name.first, "Ally");
     strcpy(fellow[0].name.last, "Amy");
     strcpy(fellow[0].name.last, "Anderson");
    Copy-paste strikes again.


    Quzah.
    Hope is the first step on the road to disappointment.

  8. #8
    Registered User ChipS's Avatar
    Join Date
    Oct 2011
    Posts
    16
    Thanks, the print loop is all goofed up and I can't understand why it is printing out of order. Any ideas? Stepping through it it prints nothing on the first pass, ally on the second, prints third and fourth and then later prints the fifth structure right before program termination.

  9. #9
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Why do people do this to themselves?

    Code:
    struct tag {
        char *first,
             *middle,
             *last;
    };
    
    
    struct social {
        struct tag name;
        char *socialnum;
    };
    when they could simply do this...

    Code:
    struct social
      { char *fname;
        char *mname;
        char *lname;
        char *socialnum; }
    or even better.... this...
    Code:
    #define MAX_FNAME 16
    #define MAX_MNAME 16
    #define MAX_LNAME 24
    #define MAX_SOCIALNUM 16
    
    
    struct social
      { char fname[MAX_FNAME];
        char mname[MAX_MNAME];
        char lname[MAX_LNAME];
        char socialnum[MAX_SOCIALNUM]; }
    Which gives them simpler access, in-struct storage and predefined buffer sizes for the rest of their code....
    Last edited by CommonTater; 10-15-2011 at 07:39 PM.

  10. #10
    Registered User ChipS's Avatar
    Join Date
    Oct 2011
    Posts
    16
    Book problem was defined that way, just did it for fun.

  11. #11
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by CommonTater View Post
    Which gives them simpler access, in-struct storage and predefined buffer sizes for the rest of their code....
    Easy if you're writing your own code. Much harder to use your technique if you are required to reuse data structures, support functions from a third-party library.. In those circumstances, nested structures are often useful.

    Your technique also hard-codes buffer lengths, which is useless if buffer lengths cannot be determined until run time.

    Either way, the techniques ChipS is trying to learn do have their uses.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  12. #12
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by grumpy View Post
    Either way, the techniques ChipS is trying to learn do have their uses.
    No they don't .... they're pure crap and should not even be allowed in the language.

    There... was that the response you were wanting?

    Gees.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Random index structure based file managment in C
    By infantheartlyje in forum C Programming
    Replies: 1
    Last Post: 10-07-2011, 01:45 AM
  2. Replies: 1
    Last Post: 08-12-2011, 03:07 AM
  3. Replies: 10
    Last Post: 05-30-2011, 08:26 AM
  4. Problem Passing Structure Reference To Function
    By soj0mq3 in forum C Programming
    Replies: 9
    Last Post: 04-24-2010, 10:27 AM
  5. ComboBox index problem
    By WaterNut in forum Windows Programming
    Replies: 7
    Last Post: 08-19-2004, 12:51 PM