0

I have the following struct:

struct State {
    int num_walls;
    Wall walls[];

    int num_persons;
    Person persons[];
};

I want to have persons contain two Persons and walls contain one Wall:

int num_walls = 1;
int num_preson = 2;

State simState = *(State*)malloc( sizeof(simState) + num_person*sizeof(Person) + num_walls*sizeof(Wall));
simState.num_walls = num_walls;
simState.num_persons = num_person;
simState.walls[0] = w;
simState.persons[0] = p1;
simState.persons[1] = p2;

When I do that I get Bus error (core dumped). When I only set the persons, everything works fine. I.e. this works:

int num_walls = 0;
int num_preson = 2;

State simState = *(State*)malloc( sizeof(simState) + num_person*sizeof(Person) + num_walls*sizeof(Wall));
simState.num_walls = num_walls;
simState.num_persons = num_person;
// simState.walls[0] = w;
simState.persons[0] = p1;
simState.persons[1] = p2;

The code is c++11 and I'm using gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609

Why does that happen?

f.k
  • 85
  • 2
  • 9
  • Your `struct State` definition is incorrect it cannot compile. Please provide your _actual_ code. – Jabberwocky Apr 14 '20 at 08:11
  • 1
    This is not legal C++ `Wall walls[];` – john Apr 14 '20 at 08:11
  • 1
    @john Not legal C either, since not at the end of the `struct`. OP: Please tag only the language that you intend this to be. C *or* C++. At the moment the code should not compile in either of the two languages. – walnut Apr 14 '20 at 08:12
  • This is my actual code. If I change it to Wall* walls; I get an assertion error for malloc: _int_malloc: Assertion `(unsigned long) (size) >= (unsigned long) (nb)' failed. – f.k Apr 14 '20 at 08:12
  • It looks like you are trying to create a variable length structure, with a single allocation. If that is so, then this isn't the way to do it. – john Apr 14 '20 at 08:13
  • If this is your actual code, your compiler is broken. As mentioned before `Wall walls[];` is not legal. – Jabberwocky Apr 14 '20 at 08:13
  • Oh and `*(State*)malloc( ...` doesn't make any sens. What is your platform/IDE/compiler/OS/...? – Jabberwocky Apr 14 '20 at 08:15
  • 1
    @FerdiK Please form a complete [repro] and tell us which compiler you are using that is compiling it, because as it is it should not compile. – walnut Apr 14 '20 at 08:16
  • Ok, I'll edit the question – f.k Apr 14 '20 at 08:17
  • Please show a [mcve]. You struct definition cannot compile. You're not showing the code you compile. – Jabberwocky Apr 14 '20 at 08:24
  • My struct def is in a header file. It's copy pasted and what I compile. I then instantiate a State as shown in the code in the question and pass it on to a function that does a computation on it. – f.k Apr 14 '20 at 08:26
  • @FerdiK please don't _describe_ your code, show a [mcve]. This may require some work. Also condider the answer below. Ans maybe you should also tell us what you're trying to achieve. – Jabberwocky Apr 14 '20 at 08:28
  • Ok, I'll do that. – f.k Apr 14 '20 at 08:32
  • 1
    Just to clarify, the GCC version that you are using does indeed compile the code. But arrays with unknown bounds are not allowed in C++ as `struct` members and in C they are only allowed at the end of the struct (so-called "flexible array member"). That GCC allows it somewhere else in the struct seems to be a bug, which seems to be fixed since GCC 6. Use the `-pedantic-errors` flag to force GCC to issue error messages for such constructs that are not actually allowed in C++ and are just a compiler-specific extension. – walnut Apr 14 '20 at 08:47
  • Also, if you really intend to write C++, not C, then you have picked up some wrong idioms. You should not use `malloc` like this in C++. I suggest you learn the language with a [good book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – walnut Apr 14 '20 at 08:49
  • @FerdiK If you used `std::vector` and `std::vector` instead of the fake C++ syntax in that `struct`, not only will you have legal C++ code, you would not need to have those other members that hold the number, since a vector knows how many elements it has by just calling `vector::size()`, plus the code is easier to maintain. – PaulMcKenzie Apr 14 '20 at 08:55
  • Hi, thanks for the suggestions. I will clarify things shortly. The problem is that we are supposed to write code in C but a colluege started writing in Cpp. That's messy from my part, I'll clear things up and come back. – f.k Apr 14 '20 at 08:59
  • Okay, the problem actually was what @john pointed out: "do not have to allocate simState, it gets it's memory just by being declared, but you do have to allocate your two variable length arrays". Thanks a lot for the help and also thanks for the other tips about Cpp and C. My confusion about using C vs.Cpp idioms came from that we have an algorithm in C that needs to be optimized as much as possible and we write the rest in Cpp. Sorry for that! – f.k Apr 14 '20 at 09:17

2 Answers2

2

So this is legal C++, it may be what you are trying to achieve

struct State {
    int num_walls;
    Wall* walls;
    int num_persons;
    Person* persons;
};

State simState;
simState.num_walls = num_walls;
simState.walls = new Wall[num_walls];
simState.num_persons = num_person;
simState.persons = new Person[num_person];
simState.walls[0] = w;
simState.persons[0] = p1;
simState.persons[1] = p2;

It's not good C++, but at least it's legal.

The important points (in either language) is that you do not have to allocate simState, it gets it's memory just by being declared, but you do have to allocate your two variable length arrays simState.persons and simState.walls

john
  • 85,011
  • 4
  • 57
  • 81
1

It's not allowed to define dimensionless arrays in C++, you should be using pointer with allocation (new or even malloc) as stated by others.

Dimensionless arrays are valid construct in C99, it's not called VLA but flexible array member. This feature of language can be used only as last member of structure with several other restrictions on definition and usage. Definitely not regularly used feature.

Reason for "Bus error" on first example is illegal definition of wall it's not last member of struct. Since person is correctly defined you are accessing memory past structure and overwriting something else which is really not what you want to do. GCC is reason why your program compiles even when it's not valid since lot of extensions is enabled by default. Please use -pedantic flag together with version of C++ standard (-std=c++11) to get warning about that.

raliscenda
  • 426
  • 6
  • 11