Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using sizeof() with pointer to struct in C

I'm learning C right now and came to a little problem I encountered while trying out some code snippets from my uni course.

It's about typedef'd pointers to structs and their usage in the sizeof() function.

#include <stdio.h>
#include <stdlib.h>

// Define struct
struct IntArrayStruct
{
  int length;
  int *array;
};
// Set typedef for pointer to struct
typedef struct IntArrayStruct *IntArrayRef;

// Declare function makeArray()
IntArrayRef makeArray(int length);

// Main function
int main(void)
{
  // Use makeArray() to create a new array
  int arraySize = 30;
  IntArrayRef newArray = makeArray(arraySize);
}

// Define makeArray() with function body
IntArrayRef makeArray(int length)
{
  IntArrayRef newArray = malloc(sizeof(*IntArrayRef)); // ERROR
  newArray->length = length;
  newArray->array = malloc(length * sizeof(int));
  return newArray;
}

And the code really works in the IDE used in class (Virtual C), but when I try the exact same example in VSCode and compile it using GNU Make or GCC, it returns an error because sizeof(*IntArrayRef) in the malloc() function call is marked as an unexpected type name.

error: unexpected type name 'IntArrayRef': expected expression

However, when I change it to sizeof(IntArrayStruct), everything works splendidly.

Isn't *IntArrayRef the same value as IntArrayStruct?

like image 372
lbeul Avatar asked Sep 20 '25 02:09

lbeul


2 Answers

IntArrayRef is the name of a type, therefore *IntArrayRef is invalid syntax. What you can (and should) do instead is give the name of the variable and dereference that:

IntArrayRef newArray = malloc(sizeof(*newArray)); 
like image 145
dbush Avatar answered Sep 22 '25 04:09

dbush


Here's how your type names relate to each other:

struct IntArrayStruct *  == IntArrayRef

Thus, newArray has type IntArrayRef which is the same as struct IntArrayStruct *

So, if you want the size of the pointer type, you'd use one of

sizeof (IntArrayRef)
sizeof (struct IntArrayStruct *)
sizeof newArray

If you want the size of the pointed-to type (the actual struct type), you'd use one of

sizeof (struct IntArrayStruct)
sizeof *newArray

sizeof is an operator, not a function - parentheses are only required if the operand is a type name (including typedef names). It doesn't hurt to use parentheses around non-type operands like sizeof (*newArray), but they're not necessary.

As a stylistic note, it's generally a bad idea to hide pointer types behind typedefs, especially if the user of the type has to know it's a pointer type to use it correctly. IOW, if the user of the type ever has to dereference something, then the pointerness of that something should be explicit. Even if the user doesn't need ever need to explicitly dereference it, you still shouldn't hide the pointerness of the type (take the FILE * type in the standard library as an example - you never actually dereference a FILE * object, but its pointerness is still made explicit).

Otherwise, be prepared to write a full API that hides all pointer operations from the user.

like image 30
John Bode Avatar answered Sep 22 '25 04:09

John Bode