0

So far, I have dealt a bit with pointers and structs, but I'm not sure how to allocate an array of a structure at runtime - see below.

N.B. "user_size" is initialized at runtime.

typedef struct _COORDS
{
    double x;
    double y;
    double area;
    double circumference;
    int index;
    wchar_t name[16];
} COORDS, *PCOORDS;

PCOORDS pCoords = (PCOORDS)malloc(sizeof(COORDS)* user_size);
// NULL ptr check omitted 

After that, can I just access pCoords[0] to pCoords[user_size-1] as with an ordinary array of ints?

More to the point: I don't understand how the compiler superimposes the layout of the structure on the alloc'ed memory? Does it even have to or am I overthinking this?

user2286339
  • 184
  • 1
  • 4
  • 18
  • 3
    Well, `pCoords[0]` to `pCoords[user_size - 1]`, but yes. It doesn't have to impose any structure on the allocated memory; it just has to know the size of each item. – Paul Roub May 16 '15 at 13:16
  • 3
    p.s. [Don't cast the result of `malloc()`](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Paul Roub May 16 '15 at 13:16
  • @Paul: thank you for Array bounds – user2286339 May 16 '15 at 14:09
  • If I omit the cast, Visual Studio throws error C2440 at me (cannot convert from 'void *' to 'PCOORDS'). – user2286339 May 16 '15 at 14:16
  • That would imply that you're actually building in C++ mode, where the cast is actually required. – Paul Roub May 16 '15 at 14:22
  • 1
    I suppose that's because VS automatically creates projects with source files already ending on .cpp - so I get strict C++ type checking, right? – user2286339 May 16 '15 at 14:30

2 Answers2

1

You are probably overthinking this. The compiler does not "superimpose" anything on the malloc'ed memory - that is just a bunch of bytes.

However, pointers are typed in C, and the type of the pointer determines how the memory is interpreted when the pointer is derefenced or used in pointer artihmetic. The compiler knows the memory layout of the struct. Each field has a defined size and an offset, and the overall size of the struct is known, too.

In your case, the expression pCoords[i].area = 42.0 is equivalent to

char *pByte = (char*)pCoords + sizeof(COORDS) * i + offsetof(COORDS, area);
double *pDouble = (pDouble*)pByte;
*pDouble = 42.0;
derhass
  • 43,833
  • 2
  • 57
  • 78
1

The compiler does not super-impose the structure on the memory -- you tell it to do so!

An array of structures is accessed by multiplying the index of one element by its total size. pCoords[3], for example, is "at" pCoords + 3*sizeof(COORDS) in memory.

A structure member is accessed by its offset (which is calculated by the sizes of the elements before it, taking padding into account). So member x is at an offset 0 from the start of its container, pCoords plus sizeof(COORDS) times the array element index; and y is sizeof(x) after that.

Since you tell the compiler that (1) you want a contiguous block of memory with a size for user_size times the size of a single COORD, and (2) then access this through pCoords[2].y, all it has to do is multiply and add, and then read the value (literally) in that memory address. Since the type of y is double, it reads and interprets the raw bytes as a double. And usually, it gets it right.

The only problem that can arise is when you have multiple pointers to that same area of memory. That could mean that the raw bytes "at" an address may need interpreting as different types (for instance, when one pointer tells it to expect an int and another a double).

With the provisio that the valid range is acutally 0..user_size - 1, your code is fine.

Jongware
  • 22,200
  • 8
  • 54
  • 100