3

Often malloc is used to allocate memory for n elements of some primitive datatype (int, float, char). This could look like this:

#define N 10

double *mem = malloc(N * sizeof(double));

for (int i = 0; i < N; ++i) {
  mem[i] = 10.0;       // Write
  double d = mem[i];   // Read
}

This would even work if I declared mem as char * and used a cast later on:

char *mem = malloc(N * sizeof(double));

for (int i = 0; i < N; ++i) {
  *(double*)(mem + i * sizeof(double)) = 10.0;
  double d = *(double *)(mem + i * sizeof(double));
}

Currently I'm wondering if this is well defined and working for every datatype (even any complex type like struct). Lets assume struct a could be anything. Is the following well defined?

char *mem = malloc(N * sizeof(struct a));

for (int i = 0; i < 10; ++i)) {
  *(struct a *)(mem + i * sizeof(struct a)) = /* something valid */;
  struct a x = *(struct a *)(mem + i * sizeof(struct a));
}

Since the return value of malloc is suitably aligned for any kind of variable the case i = 0 is definitely well defined and working, but how about I = 1, 2, ...? Will alignment screw this up? Like in this example:

char char_arr[4] = /* some value */;
int *d = &char_arr[0];

The second line is not guaranteed to work, since char_arr may not be aligned on a 4-byte boundary (required for int).

12
  • 1
    Unless the structure is packed, it will itself contain padding making it aligned. Otherwise, you could never dynamically allocate arrays of structures using malloc. Commented Apr 6, 2017 at 13:32
  • @Someprogrammerdude And by default the structure includes padding, right? In some sense the sizeof operator takes care right, since its including the padding? Commented Apr 6, 2017 at 13:37
  • 1
    Yes, sizeof will returns the full size of the structure, including padding. Commented Apr 6, 2017 at 13:38
  • 1
    For the latter the code has other issues, too. It violates the effective type rule, thus invokes undefined behaviour. The malloc parts become "problematic" (actually UB, too) if you access the allocated block via the char *, then cast to another type. Why don't you use the correct type for the pointer? Why char *? malloc & friends return void *, not char *. Commented Apr 6, 2017 at 13:55
  • 1
    @user7802048 char * is not " capable to hold any kind of data". Casts from any char * to another type pointer can be UB. Your question was about pointer from malloc(). The higher level coding goal remains unclear. Knowing that may provide even better answers. Commented Apr 6, 2017 at 14:17

2 Answers 2

1

Is the following well defined?

char *mem = malloc(N * sizeof(struct a));

for (int i = 0; i < N /* 10 */; ++i)) {
  *(struct a *)(mem + i * sizeof(struct a)) = /* something valid */;
  // struct a = *(struct a *)(mem + i * sizeof(struct a));
  struct a x = *(struct a *)(mem + i * sizeof(struct a));
}

Almost always.

In terms of alignment, *alloc() returns a pointer to memory that is valid for all fundamental alignments as OP noted. (struct a *)(mem + i * sizeof(struct a)) will also provide a well aligned pointer for all 0 <= i <= N.

Not a likely concern for OP, yet on rare machines i * sizeof(struct a) will overflow size_t math (with a large enough i and sizeof(struct a), whereas mem[i] will not. This is not seen on common implementations that use a flat memory address.


Also robust code checks for memory allocation failures.


Candidate simplified code. Notice the type ptr points to is not relevant, assuming it is not defined void *ptr. @usr.

ptr = malloc(sizeof *ptr * N);
if (ptr == NULL) Handle_OOM();

for (size_t i = 0; i < N; ++i)) {
  ptr[i] = /* something valid */;
}

`

Sign up to request clarification or add additional context in comments.

5 Comments

"Notice the type ptr pointers to is not relevant" -- it's relevant if ptr is of type void* ;-)
Thank you! That is what I was looking for. So it's right to say if ptr is suitably aligned to point to struct a, ptr + sizeof(struct a) is well suitably aligned as well?
@user7802048 char *ptra; ptra + sizeof(struct a) is OK. Curiously, why do you want to code that way? What is the coding goal does that meet well?
I'm trying to create a data structure capable to hold any kind of data (internally it uses malloc to allocate enough memory to hold some elements and reallocates more later on). The pointer is stored as char * for internal pointer arithmetic (shift by element size) and the data is returned as void *.
Do not used char * to store the data. Use a union example of a void * and function pointer. This only then works for pointers, A pointer is too small to store "any kind of data" such as long double complex.
1

Yes, you can use malloc to allocate array of structures.

7.22.3 Memory management functions

  1. The order and contiguity of storage allocated by successive calls to the aligned_alloc, calloc, malloc, and realloc functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). ...

But you don't need to do all that ugly casting:

struct a *mem = malloc(N * sizeof(struct a));

for (int i = 0; i < 10; ++i)) {
  mem[i] = /* something valid */;
  struct a var = mem[i];
}

1 Comment

In my question I even say that the pointer (returned by malloc) is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment required, but how about the second, third, etc elements? They are not directly accessed as the pointer of returned by malloc. Will this still work? Maybe I'm asking if the shift of sizeof(struct a) will always end up aligned just right?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.