How to avoid unnecessary cast and extraneous variable involving ptr to ptr to ptr

I have the following code that totally works 100% fine, no errors, compile or runtime. But it's damn ugly because I have to cast and use an extraneous variable when I'm sure there's a way to do without either.

structMSGB ***init_bstack(int Blk_Size,int Blks_N)
  {
  structMSGB **Mp=calloc(Blk_Size,Blks_N);
  void *M=(void*)Mp+sizeof(structMSGB*)+sizeof(structMSGB*)*Blks_N;

  structMSGB ***startStack=(structMSGB***)Mp++;

  for(int i=0;i<Blks_N;i++)
    {
    *Mp=M+(Blk_Size-sizeof(structMSGB*))*i-(i==1)*sizeof(structMSGB*);
    (*Mp)->blk_size=Blk_Size-sizeof(structMSGB)-sizeof(structMSGB*)-(i==0)*sizeof(structMSGB*);
    Mp++;
    }

  *startStack=(structMSGB **)Mp;
  return startStack;
  }

Specifically, it's the startStack variable that is pissing me off. I feel there should be a way of doing without it altogether. The return value is the address of a ptr to a ptr to a struct, i.e. It needs to return a ptr to a ptr to a ptr to a struct.

The result returned is the starting address of a memory block that is Blk_Size bytes in size and is composed of the following in order:

**ptr variable

table of ptrs of Blk_N length

sequential blocks of size Blk_Size - sizeof(ptr) except for the first block which is sizeof(ptr) smaller.

It's done this way to ensure that the entire memory allocation is used, no more and no less.

Answers


Your code invokes undefined behavior when it performs arithmetic on an expression of type void *. Some compilers will treat that as if void * were char *, and if your code in fact works then that's what's happening, but it's still wrong. And probably unnecessary, to boot.

Allow me to introduce you to pointer arithmetic. Given a pointer p of type some_type * and an integer value x, the expression p + x is equivalent to (some_type *) (((char *) p) + (x * sizeof(some_type)). By no coincidence whatever, that's also equivalent to &p[x]. That is, pointer arithmetic is defined in terms of the size of the pointed-to object.

The code you present performs a lot of casting and arithmetic with explicit object sizes that could be eliminated by relying on ordinary pointer arithmetic. For example, this ...

void *M = (void*) Mp + sizeof(structMSGB*) + sizeof(structMSGB*) * Blks_N;

... would be better written

structMSGB **M = Mp + 1 + Blks_N;

Similar applies elsewhere in your code.

More generally, good code rarely requires sizeof other than for memory allocation, and requires very few casts. Any time you find yourself writing a cast, you should ask yourself why, and be sure you have a good answer.

Update:

As for getting rid of variable startStack, it looks like you could do so at the cost of some additional arithmetic. You initialize it to the original value of variable Mp. You then increment Mp at total of Blks_N + 1 times. At the only points where you use startStack, then, its value is equal to Mp - (Blks_N + 1). You could use that expression instead of a variable. I certainly would not make such a change, though.


Need Your Help

Equivalent Objective-C code for Google Maps GMap2.getBoundsZoomLevel(bounds)?

objective-c api google-maps mapkit geocoding

I'm familiar with the Google Maps API and I'm trying to learned the iOS MapKit library now. I have an iPhone application which takes an input string and geocodes it using Google Maps geocoder serv...

Android reschedule alarmmanager alarm when app is killed

android xamarin broadcastreceiver alarmmanager

I've developed an app to schedule multiple local notifications to remind users to do something. Every month in the current year there should an notification be raised.