0

I'm trying to use a lighter primitive array, because storing hundreds of thousands NSNumbers in a NSMutableDictionary is causing like 40-50MB memory consumption..

This is my code:

NSUInteger highestModelID = [self.externalDB intForQuery:@"SELECT `id` FROM `models` ORDER BY `id` DESC"];

CGFloat modelsPricesForCustomer[highestModelID];
memset(modelsPricesForCustomer, 0, highestModelID*sizeof(NSUInteger));

NSLog(@"%i", highestModelID);
NSLog(@"%lu", (sizeof modelsPricesForCustomer));

highestModelID is 34078, yet the size says it's 136312. Do I allocate it wrong or read it wrong?

rmaddy
  • 314,917
  • 42
  • 532
  • 579

1 Answers1

3

highestModelID is the number of elements in modelsPricesForCustomer, not its size. sizeof, on the other hand, returns the size of the array in bytes, i.e. highestModelID*sizeof(CGFloat)

Since sizeof(CGFloat) on your system is 4, the results are correct:

34078 * 4 = 136312

Note:

memset(modelsPricesForCustomer, 0, highestModelID*sizeof(NSUInteger));
//                                                       ^^^^^^^^^^

should be

memset(modelsPricesForCustomer, 0, highestModelID*sizeof(CGFloat));
//                                                       ^^^^^^^

to avoid clearing part of memory or going past the end of allocated buffer when sizeof(NSUInteger) != sizeof(CGFloat)

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Yes I noticed I wrote the `memset` wrong; it should indeed be `sizeof(CGFloat)`. I also should probably do `(highestModelID + 1) * sizeof(CGFloat)` so I can actually set the final ID in it's range. Thanks for the hint :). I'll accept the answer when the time is over. –  Apr 16 '16 at 17:38
  • 1
    @Allendar Do not use the `+ 1` in the `memset`. If you do you will overwrite memory beyond the array. That's bad. – rmaddy Apr 16 '16 at 17:46
  • @dasblinkenlight Thanks for the tip! I changed it back. Can I actually set `CGFloat modelsPricesForCustomer[highestModelID]` in some way as a `@property` or should use a `static` to solve this? The problem is that the `highestModelID` is only known after running the query. `CGFloat modelsPricesForCustomer[]` obviously won't work. –  Apr 16 '16 at 17:48
  • @rmaddy how could I make it available class-wide? `static` doesn't seem to work with variable-sized. –  Apr 16 '16 at 17:59
  • @Allendar You can have the pointer to your array as a property. For example `@property (nonatomic) CGFloat* modelsPricesForCustomer`. If you do this, you'll also have to make your `highestModelID` accessible – so other classes know the array's size. – Hamish Apr 16 '16 at 18:17
  • What should `self.highestModelUnitPrices[highestModelID];` be like? I can't assign it. –  Apr 16 '16 at 18:21
  • @Allendar You should be using `self.highestModelUnitPrices = calloc(highestModelID, sizeof(CGFloat))` (this will create your array with elements set to 0). Make sure to `free()` it when done though (probably in dealloc if it lasts for the object's lifetime) – Hamish Apr 16 '16 at 18:36
  • That works great thank you. One last question; how could I do `calloc` with `CGFloat multiDimArray[int][int]` ? –  Apr 16 '16 at 18:54
  • You'll want to use a pointer to an array of pointers (`CGFloat**`). You'll need to `malloc()` the array of pointers, with a size of the array width * sizeof the elements. You'll then need to `calloc()` the individual array 'rows' with size of the array height * sizeof the elements. [See here for a slightly better answer](http://stackoverflow.com/questions/1970698/using-malloc-for-allocation-of-multi-dimensional-arrays-with-different-row-lengt). You'll also have to repeat the same (reversed) process for [freeing the array](http://stackoverflow.com/questions/5666214/how-to-free-c-2d-array). – Hamish Apr 16 '16 at 19:27