C: How do I assign a value to a pointer following malloc?

Discussion in 'Mac Programming' started by moonman239, Dec 3, 2015.

  1. moonman239 macrumors 68000

    Joined:
    Mar 27, 2009
    #1
    I'm an Obj-C developer who's starting to pick up ANSI C, and I've been wondering how to give a pointer a value to point to following a call to malloc. In Obj-C, all variables are initialized at some point, like this:
    Code:
    NSObject *obj = [[NSObject alloc] init]
    As I understand, this is functionally equivalent to doing something like this in ANSI C:
    Code:
    NSObject *obj = malloc(sizeof(NSObject));
    *obj = // some value
    
    I tried running the following ANSI C code, and the program outputted 6:
    Code:
    int main(int argc, const char * argv[]) {
    
        int *p = malloc(sizeof(int));
    
        *p = 6;
    
        printf("%d/n",*p);
    
        return 0;
    
    }
    
     
  2. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #2
    A malloc'ed pointer is not an NSObject pointer. Do not assign the pointer returned by malloc() to any kind of Objective-C object pointer or id type.

    This code is wrong, in both C and Obj-C:
    Code:
    NSObject *obj = malloc(sizeof(NSObject));
    *obj = // some value
    
    The reason a malloc'ed pointer isn't an object is because it hasn't been properly filled in. malloc() doesn't guarantee anything about the contents of the memory it allots. It could contain anything. If the Obj-C message-sending code receives such a block of memory, it may fail badly at the first message-send.

    If you want to look at the details, look into the underlying mechanics of Obj-C's isa (is-a) pointer, and how the compiler and runtime create objects.


    Your plain-C code is correct:
    Code:
    int *p = malloc(sizeof(int));
    
    If you want more examples, look in a C tutorial or book. malloc() and calloc() are both standard C. Any reference explaining standard C should cover them.

    An Obj-C tutorial or book will cover Obj-C, which is a superset of plain C. To learn plain standard C, use something that explains plain standard C.
     
  3. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #3
    In most cases you will not get away with a simple assignment to initialize a C object, usually it's something more complex than a primitive type like an int.
     
  4. moonman239 thread starter macrumors 68000

    Joined:
    Mar 27, 2009
    #4
    No, I think you misunderstand. I'm not trying to use Obj-C in C code; what I was trying to do is figure out what to do to a plain-C variable after an malloc call. In my mind, the first two blocks of code I posted were simply analogous to each other. In the tutorial I was following, I didn't see what happens after malloc, thus my question.

    But the plain-C code I posted works regardless of what C type p belongs to, right?
     
  5. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #5
    No it doesn't, normally you would not malloc an int, it's usually something larger, which means you'll need an init function, do it manually or possibly use memcpy if you have a copy in the desired state.
     
  6. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #6
    They're not analogous. The second block of code is wrong.

    Was the third block of code from the tutorial? Which tutorial? The more context you provide, the better we can understand your questions, and give suitable answers.

    If the C type is a non-array type, then yes, it works. Scalars or structs/unions, or typedefs of them, will work as shown.
     
  7. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #7
    Provided that you have a copy around in the desired init state, which isn't usually the case.
     
  8. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #8
    I took the question to refer only to the malloc(). That is, this line of code:
    Code:
    int *p = malloc(sizeof(int));
    This code assigns a value to a pointer following malloc(). The value assigned to the pointer is the value returned by malloc().

    The code that comes after it is this:
    Code:
    *p = 6;
    This code doesn't "assign a value to a pointer". It assigns a value to the memory location that p is pointing at. That's not the same thing at all.

    The following plain C code is exactly equivalent to the above line:
    Code:
    p[ 0 ] = 6;
    This doesn't assign a value to a pointer, either. Instead, it subscripts the pointer and assigns a value to the 0th location in the memory p is pointing at.

    Pointers in C can always be subscripted, even when they don't point to arrays of multiple items. It may be non-obvious if one doesn't understand the pointer/array nature of C, but that's a different and subtler issue. Conceptually, it may be ahead of the OP's current understanding.

    A malloc'ed composite can be initialized in parts. Example:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    struct foo
    {
        int a;
        int b;
    };
    
    typedef  struct foo  foo_t;
    
    int main( int argc, const char * argv[] )
    {
        foo_t * pf;
    
        pf = malloc( sizeof(foo_t) );
        pf -> a = 7;
        pf -> b = 8;
    }
    
     
  9. moonman239 thread starter macrumors 68000

    Joined:
    Mar 27, 2009
    #9
    OK, so what do I do when a simple assignment won't suffice?
     
  10. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #10
    Right, but the question rather seems to be, what's the C equivalent to the Obj-C init method. Look at typical library code, or instances where you need to init newly malloced memory. Either it's initially set up to zero with calloc or malloc/memset, followed by a function that inits the memory, or done manually.
     
  11. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #11
    Either do it manually or with an init function.
     
  12. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #12
    It sounds like this isn't actually a question about using pointers, but about initialization of C types. What you're interested in is initialization of C types, and maybe scratching at hiding implementation details of a type (making it opaque).

    For one, we have to be clear that you're really dealing with structs (or arrays) when you're malloc'ing normally. There are a few options, but it really comes down to a few approaches:
    Code:
    foo_t *createFoo(int, char, double)
    void initFoo(foo_t *, int, char, double)
    
    The first would both allocate and initialize the struct (and make the caller implicitly in charge of free'ing the pointer). The second takes an allocated struct and initializes it. This gives the caller more flexibility, because they can choose how and where to allocate the memory (and free it).

    One way you can get real value out of patterns like this vs directly accessing members is in making opaque structures that can change (field names, types, order, etc.) and still stay compatible with existing code, even binaries. It forces consumers to use a more verbose API, calling methods to do anything with this data instead of just manipulating it directly. It's a tradeoff. Transparent data types vs. ease of future upgrades (and better control of data state).

    -Lee
     
  13. moonman239 thread starter macrumors 68000

    Joined:
    Mar 27, 2009
    #13
    Well, I'm not necessarily thinking about initializing my own types per se. What I'm kind of leaning towards now is how to initialize any type following an malloc. It seems there isn't exactly a one-size-fits-all approach. Coming from an Obj-C background, I find this fact awkward because in Obj-C, we alloc & init in the same line of code.
     
  14. lee1210, Dec 9, 2015
    Last edited: Dec 9, 2015

    lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #14
    If it's not your type, either it needs to be a documented struct that you simply set the fields on manually, or it's opaque and you need to use provided methods to perform initialization. Another possibility is if all zeros (i.e. Null pointers, 0 for primitives) is a good "initialization state", you can allocate with calloc rather than malloc and it will zero the memory for you.

    I don't have a compiler handy to test, but there are compound initializers. The availability varies based on C standard revision, but you can put values in {} and set the elements of your struct at-once (omitted elements are set to zero).

    -Lee

    Edit: Objective-C has a CONVENTION that makes this seem simple. People generally adhere to it and we know what's going on. You can use similar constructs in C, but there isn't a single strong convention. The way to do things most similarly:
    Code:
    SomeType *myVar = SomeType_init((SomeType *)malloc(sizeof(SomeType)), 6, 4.5, 'x');
    ...
    SomeType *SomeType_init(SomeType *toInit, int length, double height, char label) {
      if (toInit != NULL) { //or handle null how you want... Crash handler, whatever
        toInit->length = length;
        toInit->height = height;
        toInit->label = label;
      }
      return toInit;
    }
    
    There's a million ways to try to replicate various systems in C. It comes down to discipline, though, because you're making it yourself or adhering to a library's approach. It's not part of the language or a strongly adhered to convention.
     
  15. Toutou macrumors 6502a

    Toutou

    Joined:
    Jan 6, 2015
    Location:
    Prague, Czech Republic
    #15
    There's no need to allocate memory for a simple int, you just declare and initialize at once:
    Code:
    int number = 6;
    If you, for whatever reason, wanted to allocate memory for an array of integers (maybe to be able to resize it later), you would have to use malloc, then assign values to them manually:
    Code:
    int * array = (int *)malloc(5*sizeof(int));
    *array = 1;
    *(array+1) = 2;
    *(array+2) = 3;
    *(array+3) = 4;
    *(array+4) = 5;
    
    (or by a function, often a loop that goes through the memory by incrementing a pointer (in this case "int * pointer") and assigns a default value to every position)

    An allocated chunk of memory is just a chunk of memory. It doesn't care what's stored in it. Malloc allocates the memory and gives you a pointer to its beginning and doesn't care anymore. It is possible to malloc a memory, store a hundred integers, then - in the middle - switch to a char * pointer and start storing chars and then put a structure at the end. Nobody would care, but you'd have to be very careful with your pointers and functions handling the data.

    In other words - allocated memory isn't typed, it's an empty box and whatever you'd like to have inside you have to put there first manually.
     
  16. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #16
    Unless you need it on the heap because you're using the pointer for something that will outlive a stack frame.

    This is a somewhat puzzling example. It's certainly correct and does what's advertised, but [] alleviates a lot of the manual pointer arithmetic and dereference.
    Code:
    array[1] = 2;
    Seems a lot easier to follow.
    I guess my point is that knowledge of pointer arithmetic is worthwhile, but might over-complicate things for a beginner.

    -Lee
     
  17. Toutou macrumors 6502a

    Toutou

    Joined:
    Jan 6, 2015
    Location:
    Prague, Czech Republic
    #17
    I agree, I just wanted it to be self-explanatory. IMHO pointers are fundamental in C and one needs to understand them well, beginner or not. OP stated he is an Obj-C developer (!), so an asterisk shouldn't be too much of a complication :D
     

Share This Page