Thread: Struct/pointer/memory allocation

  1. #1
    Registered User
    Join Date
    Jun 2005
    Posts
    2

    Struct/pointer/memory allocation

    Before I can get any longer in my life, I need to get answers to some important q's... One of these is the following:

    I wonder why the following code doesn't work? I want to use the principles that are used in the code but I cannot figure out why it doesn't work?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MSG_SIZE 100
    
    // a simple struct
    typedef struct{
    
      char *msg;
    
    }a_struct;
    
    
    // allocate memory for a struct
    void malloc_mystruct(a_struct *a_ptr){
    
      // allocate for mystruct
      a_ptr = (a_struct *)malloc(sizeof(a_struct));
    
      // allocate for msg
      a_ptr->msg = (char *)malloc(MSG_SIZE * sizeof(char));
    
    }
    
    int main(void){
    
      a_struct *a;
    
      char *txt="abc";
    
      malloc_mystruct(a);
    
      strcpy(  a->msg, txt);          // This doesn't work....
    
      sprintf( a->msg, "%s", txt); // This doesn't work either....
    
      return 0;
    
    }

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    1) You don't typecast malloc in C. Ever.
    2) To update something passed to a function, you need a pointer to it. Thus, if you're trying to update a pointer, you pass a pointer to that pointer.

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

  3. #3
    the c-dil
    Join Date
    May 2005
    Posts
    12
    // well, sprintf just sends the formatted output to the string and not to the screen . rest is ok .

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include<conio.h>
    #define MSG_SIZE 100
    
    // a simple struct
    typedef struct{
    
      char *msg;
    
    }a_struct;
    
    
    // allocate memory for a struct
    void malloc_mystruct(a_struct *a_ptr){
    
      // allocate for mystruct
      a_ptr = (a_struct *)malloc(sizeof(a_struct));
    
      // allocate for msg
      a_ptr->msg = (char *)malloc(MSG_SIZE * sizeof(char));
    
    }
    
    int main(void){
    
      a_struct *a;
    
      char *txt="abc";
      clrscr();
      malloc_mystruct(a);
    
      strcpy(  a->msg, txt);          // This  works....
      puts(a->msg);
      sprintf( a->msg, "the msg is %s", txt); // This also works ...
      puts(a->msg);
      //return 0;
       getch();
    
    }
    Rajat kochhar

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    > strcpy( a->msg, txt); // This works...
    Actually, no it doesn't.
    Try printing the value of the pointer 'a' before and after the call.
    Code:
      a_struct *a;
      printf( "%p\n", (void*)a );
      malloc_mystruct(a);
      printf( "%p\n", (void*)a );
    You just lucked out because the garbage pointer you used just happened to be pointing to some valid memory, which is all too easy on old DOS compilers
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Mar 2005
    Posts
    135
    As someone has already mentioned, you need to pass a pointer to a pointer to the structure in your malloc_mystruct() functions argument to accomplish what you want to do.

    Here's how it can be done:

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    #define MSG_SIZE 100
    
    typedef struct{
    
      char *msg;
    
    }a_struct;
    
    void malloc_mystruct(a_struct**);
    
    int main(void){
    
      a_struct *a;
    
      char *txt="abc";
    
      malloc_mystruct(&a); // pass a pointer to a pointer as was mentioned already
    
      strcpy(  a->msg, txt);
    
      sprintf( a->msg, "%s", txt);
      printf("%s\n", a->msg); // prints "abc"
    
      free(a->msg); // don't forget to free the borrowed memory!
      free(a);
    
      return 0;
    
    }
    
    void malloc_mystruct(a_struct **a_ptr){
    
      *a_ptr = malloc(sizeof(a_struct)); //dereference the pointer to get to the pointer
    
      (*a_ptr)->msg = malloc(MSG_SIZE * sizeof(char)); // dereference here as'well
    
    }
    Last edited by xeddiex; 06-03-2005 at 12:03 PM.

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    2
    Thanks for the replies and the help!

    So, if I want a function to free allocated memory for my struct, I could use this ? :
    Code:
    void free_mystruct(a_struct **a_ptr){
      free((*a_ptr)->msg);
      free(*a_ptr);
    }
    What confuses me is that the following seems to be ok as well:
    Code:
    void another_free_mystruct(a_struct *a_ptr){
      free(a_ptr->msg);
      free(a_ptr);
    }

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    > What confuses me is that the following seems to be ok as well:
    Because you're not actually modifying the pointer, only dereferencing it.

    The malloc returns a MODIFIED pointer (ie, the result of malloc), so you need some mechanism (eg, a pointer to a pointer) to get that change back to the caller.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Mar 2005
    Posts
    36
    But the whole thing can be done by:
    Code:
    typedef struct {
        char msg[1];
    }
    
    int main ( int argc, char **argv )
    {
         mystruct* a;
         char *txt = "abc";
    
         a = malloc( sizeof(mystruct+strlen(txt));
    
         strcpy(a->msg,txt);
    
         printf("&s\n",a->msg);
    
         free(a);
         retutn(0);
    }
    By placing the link pointer(s) ahead of the string in the struct, this technique can be used effectively in building linked lists of strings - fewer discrete memory allocations and frees.
    Other non-string and/or fixed string data can be ahead of the variable length string too, but
    only one variable length string can be used without more trickery.

  9. #9
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    No. That's a bad way to do it. For starters, strlen doesn't include the null. Additionally, that's a horrible way to allocate space for the string. You shouldn't be allocating the string and the node pointer in one shot, because then, what would be the "correct" way to free it?

    Well, logic would tell you that you free the string, and then a second call to free the structure. You're bastardizing that process by some horrible hack, that if works, is a miracle. Then, to anyone reading your code, they'll not know the correct way to free it. In short, it's ugly and incorrect.

    However, to address this issue:
    Quote Originally Posted by markusvinsa
    So, if I want a function to free allocated memory for my struct, I could use this ? :
    Code:
    void free_mystruct(a_struct **a_ptr){
      free((*a_ptr)->msg);
      free(*a_ptr);
    }
    What confuses me is that the following seems to be ok as well:
    Code:
    void another_free_mystruct(a_struct *a_ptr){
      free(a_ptr->msg);
      free(a_ptr);
    }
    The latter is fine. You're just freeing up the pointer, not chaning what it points to, so you don't need a pointer-to-a-pointer. Just like the call to free itself only needs one pointer, you also only need one. You simply pass the pointer you wish to free. Since in this case you need to free a string and a node, you pass the node, free its string, and then free it.

    Both are actually fine, but you don't need the pointer to a pointer. The second example is just fine.


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

  10. #10
    Registered User
    Join Date
    Mar 2005
    Posts
    36
    The struct definition contains one position - that accounts for the nul later. And only one free is required because it is all one continguous unit. It acts as a variable length struct.

    Just because you haven 't seen it before, or just came out of C class doesn't mean you shouldn't know how to understand it. You'll run into much much worse code to maintain or change out in the real world. This is effective and efficient.

  11. #11
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Quote Originally Posted by Karthur
    You'll run into much much worse code to maintain or change out in the real world. This is effective and efficient.
    Not likely. Your code won't even compile as posted.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  12. #12
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by Karthur
    The struct definition contains one position - that accounts for the nul later. And only one free is required because it is all one continguous unit. It acts as a variable length struct.
    Actually I was thinking you had that as a char * in the body of the structure, which is why I mentioned the need for the double free.

    However, it's still ugly ass code, and I stand by what I said. It's a lousy way to do it IMO.


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

  13. #13
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
    struct sstruct {
        char *s;
    } *s;
    
    int main() {
        char *m = "hippo";
    
        s = malloc(sizeof(sstruct));
        s->s = malloc(sizeof(m)+1);
    
        strcpy(s->s, m);
    
        printf("%s\n", s->s);
    
        free(s->s);
        free(s);
    
        return 0;
    }
    Last edited by dwks; 06-08-2005 at 02:24 PM. Reason: semicolon

  14. #14
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Code:
    s->s = malloc(sizeof(m)+1);
    Wrong. sizeof(m) will be the same as sizeof(char *). You need to use strlen(m) + 1 instead.
    If you understand what you're doing, you're not learning anything.

  15. #15
    Amateur
    Join Date
    Sep 2003
    Posts
    228
    Quote Originally Posted by Karthur
    It acts as a variable length struct.
    If you are going to do that, shouldn't you use a flexible array member instead? After all, it is the "standard way" designed to do the job.

    (If I remember correctly, it seems common practice in the Windows API to use that kind of extensible array at end of structures.)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. dynamic allocation from 1 instead of zero
    By cfdprogrammer in forum C Programming
    Replies: 27
    Last Post: 04-28-2009, 08:21 AM
  2. pointer to array with dynamic allocation
    By cfdprogrammer in forum C Programming
    Replies: 22
    Last Post: 04-07-2009, 09:56 AM
  3. Difference between straight and dynamic allocation?
    By darsunt in forum C++ Programming
    Replies: 10
    Last Post: 06-04-2008, 05:47 PM
  4. redundant allocation
    By George2 in forum C++ Programming
    Replies: 22
    Last Post: 03-06-2008, 06:43 PM
  5. Dynamic allocation (I thought it would crash)
    By Baaaah! in forum C Programming
    Replies: 16
    Last Post: 11-30-2005, 05:10 PM