Instance variable is pointer to C struct, crashing

Discussion in 'Mac Programming' started by MarcVanH, Sep 12, 2008.

  1. macrumors newbie

    Joined:
    Sep 12, 2008
    #1
    Hello all,

    I have been playing with an issue for hours now and can't figure it out. Basically, I am writing a class, and trying to initialize an instance variable that has a user-defined type (C struct). If I declare it as a direct variable (without a "*"), I can assign a value to it in init. But if I make it a pointer, my app compiles fine, but freezes when I try to assign a value. Here is a sample that reproduces the error:

    Code:
    typedef struct Mystruct_s {
        int subVar;
    } Mystruct_t;
    
    @interface MyClass : NSObject {
        Mystruct_t noPointer;
        Mystruct_t *yesPointer;
    }
    -(MyClass*)init;
    @end
    @implementation MyClass
    -(MyClass*) init {
        self = [super init];
        if ( self ) {
            noPointer.subVar   = 123;  // works just fine
            yesPointer->subVar = 123;  // compiles, but program chrashes here. mem not allocated?
        }
        return self;
    }
    @end
    
    This code compiles just fine. But it crashes where the comments indicate.

    Can anyone out there help me assign a value to "yesPointer->subVar" without it crashing?

    (and I'd also love to know why I need to use a "." for the noPointer variable, and a "->" for the yesPointer variable :) )
     
  2. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #2
    So a pointer in C is a variable that holds a memory address, and at that memory address there is the data type declared. So a Mystruct_t * that is not set to the address of a structure instance (i.e. &nopointer) or assigned the result of a malloc the sizeof(Mystruct_t) will be pointing to someplace in memory that you don't own.

    The dot operator allows access to a field in a structure. The arrow operator dereferences the structure first, then allows access to the field. It's just a shortcut. You are using them properly with the Mystruct_t and Mystruct_t *, but as mentioned above, the Mystruct_t * is just uninitialized.

    -Lee
     
  3. macrumors regular

    Joined:
    Sep 11, 2008
    #3
    You need to allocate space for that pointer.

    Code:
    @implementation MyClass
    -(MyClass*) init {
        self = [super init];
        if ( self ) {
            yesPointer = malloc (sizeof(Mystruct_t));  // NEW
            noPointer.subVar   = 123;  // works just fine
            yesPointer->subVar = 123;  // compiles, but program chrashes here. mem not allocated?
        }
        return self;
    }
    Plus you can check if yesPointer is not NULL before you use it later. I'm new to ObjC, but I suppose pointers are pointers.
     
  4. macrumors G5

    gnasher729

    Joined:
    Nov 25, 2005
    #4
    Your code does exactly what I would have expected it to do.

    Your "noPointer" variable is a struct that can hold data. When any NSObject is allocated, all memory within the object is filled with zeroes, so all elements of "noPointer" initially contain zeroes, and you can change them any way you like.

    The "yesPointer" variable is a pointer which can hold the address of data (or pointer to the data, it's the same thing). The data itself must be somewhere else. When any NSObject is allocated, all memory within the object is filled with zeroes, and that makes all pointers in the object "null pointers". A null pointer points nowhere, and if you try to store data into the object that the null pointer points to, your application _will_ crash. It is your responsibility to find an object, or create an object, and store the address of that object into "yesPointer". For example, you could write

    Code:
    yesPointer = malloc (sizeof (Mystruct_t)); 
    This allocates memory for an object with the size of a Mystruct_t, returns a pointer to that memory, and stores that pointer into yesPointer.

    The "." syntax means: I have a struct on the left side; use an element of that struct. The "->" means: I have a pointer to a struct on the left side; take the struct that it points to, and use an element of that struct.
     
  5. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #5
    This won't crash anymore, but unless you free elsewhere this will leak. i would think dealloc would be a good choice of where to do your free. I don't think there's an advantage to using alloc and free here instead of using an instance variable. The object is allocated on the stack anyway, so the memory is all coming from the same place.

    -Lee
     
  6. macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #6
    Precisely -

    yesPointer->subVar is just a shortcut for (*yesPointer).subVar.

    Also init methods generally return an id, not a defined type; I don't know if that will cause any issues, but I think it's good practice to adopt that convention.
     
  7. macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #7
    Nope, if you use malloc, the memory is allocated on the heap, not the stack.
     
  8. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #8
    damnit, that's what i meant. Objects and malloc'd things both end up on the heap, so there's no advantage to malloc'ing.

    -Lee
     
  9. thread starter macrumors newbie

    Joined:
    Sep 12, 2008
    #9
    Wow, what a great forum!

    Thanks everyone. I swear I fiddled with malloc but couldn't get it to work.

    Also, to confirm, I do not need to free the allocated memory?
     
  10. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #10
    No you still need to free it.

    Override dealloc in your class and do it there:
    Code:
    - (void)dealloc {
        free(yesPointer);
        [super dealloc];
    }
     
  11. macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #11
    No, I can confirm you do! :)

    The alternatative, just use a struct, rather than a struct pointer as an instance variable; and then you don't need to allocate or free it.
     
  12. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #12
    Seconded. That was the point i ended up bumbling through above... just use an instance variable, and you don't have to free it. When your object is destroyed, the memory for that struct goes with it. Otherwise you have to deal with the free as kainjow demonstrated. It's not so bad, but there's no advantage to the approach. Note that if you pass the pointer around to this struct (whether it is an instance variable or pointer), bad things can happen once the free happens or the object is destroyed. Just be cautious about this.

    -Lee
     

Share This Page