1

In a solution I posted I got comments that the solution contains Undefined Behavior. However, I do not see how. The basic of the solution posted is:

typedef struct {
    int n;
    int a[1];
} t_x;

void example(void)
{
    int i;
    t_x *t= malloc (sizeof(t_x) + 99*sizeof(int));
    t->n= 100;

    for (i=0; i < t->n; i++)
        t->a[i]= i;

    free(t);
}

The comment of UB centered on whether the array now has 1 element (as declared) or has 100 elements (as allocated).

The parts of the standard quoted were 6.5.6 (pointer/int addition) and 6.5.2.1 (array subscripting)

  • "6.5.6 defines what happens when you add a pointer and an integer. The resulting pointer points to a corresponding element of the array, if such an element exists, or to one element past the end. The result is undefined otherwise."

  • "6.5.2.1 defines what a[n] means in terms of a+n. It follows that you cannot say a[n] if a doesn't have at least n+1 elements."

With both quotes the commenter seems to imply that element a[99] would not exist, however, looking at the memory lay-out it clearly exists:

enter image description here

Please help me understand if/why this is UB and what types of UB I may expect.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • 1
    The answer might depend upon which C standard (C89, C99, C11) you are addressing. In C99 and later, your code smells bad since you should use [flexible array member](https://en.wikipedia.org/wiki/Flexible_array_member), but I guess it is not UB – Basile Starynkevitch Sep 03 '15 at 11:44
  • 1
    It is UB, atleast by pre-C99 standards, accessing `a` out of bounds. It's of type `int [1]`; any access above `a[0]` is undefined. – legends2k Sep 03 '15 at 11:46

2 Answers2

4

This is a pretty popular trick in pre-C99 code. It works in many implementations, but is not strictly speaking legal (thus not portable). The standard doesn't say how the strcture of t_x aligns in memory. See C FAQ for detail.

C99 introduced flexible length array, which is preferred for such problem.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • +1 for flexible length array. Basically, OP needs to leave out the array size for the last member (just have `int a[];`), and later `malloc(sizeof(t_x) + 100*sizeof(int));` – Nicu Stiurca Sep 03 '15 at 11:59
  • Thanks. I am indeed a pre-C99 programmer. I learn that it is not portable, although your links says "it does seem to work under all known implementations", because there may be memory alignment issues. – Paul Ogilvie Sep 03 '15 at 12:00
  • @SchighSchagh, wouldn't that be _exactly_ identical to my solution? Wouldn't that invoke the same memory alignment issues? – Paul Ogilvie Sep 03 '15 at 12:06
  • @Paul AFAICT, no. Using the special syntax where you don't define the array size in the struct is explicitly defined in C99 to do what most folk did in pre-C99 in a non-standard/non-portable fashion. – Nicu Stiurca Sep 03 '15 at 22:05
0

Ok, so the problem is, that you want to allocate memory for a table, that you defined in code. This table will always be of size one as you written, so you can store one object of type int in there.

If you want to allocate memory dynamically for a, then you should:

typedef struct {
int n;
int* a;
} t_x;

and then

t_x someStruct;
someStruct.a=(int*)malloc(numberOfElements*sizeof(int));
DawidPi
  • 2,285
  • 2
  • 19
  • 41