Best way to release memory allocated using malloc

2019-08-01 05:27发布

问题:

I have function to convert an integer into byte array (for iPhone). To add dynamicity I have allocate the array using malloc. But I think this will leak memory. What's best way to manage this memory,

+ (unsigned char *) intToByteArray:(int)num{
    unsigned char * arr = (unsigned char *) 
                          malloc(sizeof(num) * sizeof(unsigned char));
    for (int i = sizeof(num) - 1 ; i >= 0; i --) {
        arr[i] = num & 0xFF;
        num = num >> 8;
    }
    return arr;
}

When calling,

int x = 500;
unsigned char * bytes = [Util intToByteArray:x];

I want to avoid the call free(bytes) since, the calling function do not know or explicitly knows, the memory is allocated and not freed.

回答1:

A few things:

  1. The char type (and signed char and unsigned char) all have a size of 1 by definition, so sizeof(unsigned char) is unnecessary.

  2. It looks like you just want to get the byte representation of an int object, if this is the case, it is not necessary to allocate more space for it, simply take the address of the int and cast it to a pointer to unsigned char *. If the byte order is wrong you can use the NSSwapInt function to swap the order of the bytes in the int and then take the address and cast to unsigned char *. For example:

    int someInt = 0x12345678;
    unsigned char *bytes = (unsigned char *) &someInt;
    

    This cast is legal and reading from bytes is legal up until sizeof(int) bytes are read. This is accessing the “object representation”.

  3. If you insist on using malloc, then you simply need to pass the buffer to free when you are done, as in:

    free(bytes);
    
  4. The name of your method does not imply the correct ownership of the returned buffer. If your method returns something that the caller is responsible for freeing, it is conventional to name the method using new, copy, or sometimes create. A more suitable name would be copyBytesFromInt: or something similar. Otherwise you could have the method accept a pre-allocated buffer and call the method getBytes:fromInt:, for example:

    + (void) getBytes:(unsigned char *) bytes fromInt:(int) num
    {
        for (int i = sizeof(num) - 1 ; i >= 0; i --) {
            bytes[i] = num & 0xFF;
            num = num >> 8;
        }
    }
    
  5. You could wrap your bytes into a NSData instance:

    NSData *data = [NSData dataWithBytesNoCopy:bytes length:sizeof(num) freeWhenDone:YES];
    

    Make sure your method follows the usual object ownership rules.



回答2:

Just call free(bytes); when you are done with the bytes (either at the end of method or in dealloc of the class)


since you want to avoid the free call, you could wrap your byte[] in a NSData object:

NSData *d = [NSData dataWithBytesNoCopy:bytes length:num freeWhenDone:YES];



回答3:

The conventional way of handling this is for the caller to pass in an allocated byte buffer. That way the caller is responsible for freeing it. Something like:

int x = 500;
char *buffer = malloc(x * sizeof(char));
[Util int:x toByteArray:buffer];
…
free(buffer);

I would also consider creating an NSData to hold the bytes, this would take care of memory management for you, while still allowing you to alter the byte buffer:

+ (NSData *) intToByteArray:(int)num {
    unsigned char * arr = (unsigned char *) 
                          malloc(sizeof(num) * sizeof(unsigned char));
    for (int i = sizeof(num) - 1 ; i >= 0; i --) {
        arr[i] = num & 0xFF;
        num = num >> 8;
    }

    return [NSData dataWithBytesNoCopy:arr length:num freeWhenDone:YES];
}