-2

I have this code:

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

struct game_s {
  bool isOccupied[20][10];
};

int main() {
  struct game_s* game_p;
  game_p->isOccupied[0][8] = false;
  printf("0,8 works\n");
  game_p->isOccupied[2][8] = false;
  printf("2,8 works\n");
  game_p->isOccupied[1][7] = false;
  printf("1,7 works\n");
  game_p->isOccupied[1][9] = false;
  printf("1,9 works\n");
  game_p->isOccupied[1][8] = false; // crashes the program
  printf("1,8??");
}

As you can see from the comment, the program crashes when I try to access a specific element of the array. (More specifically, Windows tells me that "a.exe has stopped working" with the attached information.) If I use something other than 10 for the second dimension, the element will be another one. If I don't use a struct, it doesn't crash. If I use int instead of bool, it doesn't crash. If I make a variable of the struct instead of a pointer, it doesn't crash.

I'm compiling this with gcc main.c, on Windows with gcc version 4.5.2. If I use ideone, it runs without a problem.

Can someone tell me what's going on here?


Additional information Windows provides about the crash:

Problem signature:
  Problem Event Name:   APPCRASH
  Application Name: a.exe
  Application Version:  0.0.0.0
  Application Timestamp:    558f50c8
  Fault Module Name:    KERNELBASE.dll
  Fault Module Version: 6.1.7600.17206
  Fault Module Timestamp:   50e6605e
  Exception Code:   c0000005
  Exception Offset: 00011bcd
  OS Version:   6.1.7600.2.0.0.768.3
  Locale ID:    1031
  Additional Information 1: 0a9e
  Additional Information 2: 0a9e372d3b4ad19135b953a78882e789
  Additional Information 3: 0a9e
  Additional Information 4: 0a9e372d3b4ad19135b953a78882e789

Read our privacy statement online:
  http://go.microsoft.com/fwlink/?linkid=104288&clcid=0x0409

If the online privacy statement is not available, please read our privacy statement offline:
  C:\Windows\system32\en-US\erofflps.txt
Jake
  • 154
  • 9
  • where is game_p defined? there is only the declaration... – Dinesh Jun 28 '15 at 01:45
  • 1
    `game_p` doesn't point to a valid place, you need to allocate memory for it. – Yu Hao Jun 28 '15 at 01:47
  • that's only a declaration, where is the allocation for the struct, e.g. a malloc – Dinesh Jun 28 '15 at 01:47
  • @Dinesh it's a variable, I declared it and then tried to initialize the array in it – Jake Jun 28 '15 at 01:47
  • I see, any idea why it seems to work for every other value but not for this one? – Jake Jun 28 '15 at 01:47
  • 1
    @Jake, in C you have a declaration that tells how to use it, and a definition which defines its place in memory – Dinesh Jun 28 '15 at 01:48
  • 1
    @Jake it works like that purely by chance – Dinesh Jun 28 '15 at 01:48
  • Hm, okay. Thanks for your help. – Jake Jun 28 '15 at 01:49
  • Why do you need the pointer in the first place? Just declare the variable `struct game_s game_p` and use the pointer when you need to pass it to a function, for example. –  Jun 28 '15 at 01:49
  • @Evert this is a minimal example; in the original file, the struct is in a different file and the internals are not exposed. – Jake Jun 28 '15 at 01:50
  • 1
    Not creating (enough) memory results in undefined behaviour, which can result in anything: your program running correctly, to your house blowing up. Example in [this SO question](http://stackoverflow.com/questions/4316736/using-unallocated-memory-without-error). –  Jun 28 '15 at 01:51

2 Answers2

2

Try something like

struct game_s* game_p = malloc(sizeof(struct game_s));

So that a memory is allocated

Dinesh
  • 4,437
  • 5
  • 40
  • 77
  • 2
    No need to cast malloc to `struct game_s*`. Also perhaps preferred (sorry, pedantic here): `struct game_s* game_p; game_p = malloc(sizeof(*game_p));` –  Jun 28 '15 at 01:51
  • Thanks! I will accept as soon as stackoverflow let's me – Jake Jun 28 '15 at 01:51
  • You _should_ not cast `void *` as returned by `malloc()` & friends! – too honest for this site Jun 28 '15 at 01:52
  • 1
    @Evert: While I agree about the cast, The second is imo nonsense. – too honest for this site Jun 28 '15 at 01:53
  • @Evert why is that important? the separation – Dinesh Jun 28 '15 at 01:53
  • 1
    @Dinesh , @Olaf It's easier. Simple example: `int *p; p = malloc(*p);`. Later, it turns out `int` is too small, and you change things to a `long`. You now only have to change int to long the very first time; otherwise you might have to change it *inside* the malloc function as well (and forgetting that would cause not enough memory to be allocated). Of course, here (and usually), it's all close together and obvious; but not all the time (you may free and malloc the same variable again later; how will you ensure you did not forget to change that `malloc(int)` to `malloc(long`?) –  Jun 28 '15 at 02:11
  • @Evert, in my pidgin English that's practical and not pedantic :-) but I will take it – Dinesh Jun 28 '15 at 02:15
  • It's certainly practical; it just feels a bit pedantic/overkill for this one-liner. I should add to my previous comment (which neither I nor Olaf explained) that this "change of variable type" is the same reason why not to cast the result of malloc (since `void *` will in a sense automatically be cast to the relevant type). –  Jun 28 '15 at 02:17
  • 1
    @Evert: I hope you mean `malloc(sizeof(*p))`! Where is the problem: `int *ch = malloc(sizeof(*ch));`? The _definition_ is completed with the `=`. Ehm, it might not have been clear, that I refer to seperating the definition and the assignment, not the argument to `malloc()`. – too honest for this site Jun 28 '15 at 02:17
  • @Olaf yes, mistake: `sizeof(*p)`, as well as `sizeof(int)` and `sizeof(long)`. Unfortunately I can't edit my comment anymore. I don't understand your question ("where is the actual problem?"): the comment explains why this is imo better practice than including the actual datatype of the variable in sizeof. In particular the second half of the comment, when you use malloc further down in the program. –  Jun 28 '15 at 02:22
  • Sorry, if I did not state this clear enough. I think I have enough programming experience to know pretty well how to use `malloc()` & friends. Note hwoever, you do not "include the actual datatype of the variable". That would be `pointer to ...`. – too honest for this site Jun 28 '15 at 02:23
  • @Olaf Ok, I think I got what you mean: no need to use two individual statements for declaring the variable and assigning it. But you do seem to agree on using the the (pointer to the) variable instead of the variable type for sizeof. I understood your "imo nonsense" to be about the latter, you meant the former (since that comment points to all of the second part of my first comment). –  Jun 28 '15 at 02:26
  • @Evert: No, I do not actually. As `*ptr` is actually not a _variable_, but an _object_ (unless it is a function pointer). Nit-picky? Maybe, but the terms are defined by the standard for god reasons. Btw: You actually _do use_ the type of the _object_ (what you call _variable_ above) by using the dereferencing operator (note that this is not _dereferencing_!). The prase "nonsense" might have been a bit harsh - sorry, I did not remember a better word. – too honest for this site Jun 28 '15 at 02:32
  • @Dinesh: Would you please remove the typecast at least? As you now should have read, this is bad practice in C (but required in C++). – too honest for this site Jun 28 '15 at 02:36
  • @Jake: Please do **not** use the cast of the result of `malloc()`. That is not required, but might hide type conflicts. The compiler is your friend; let it halp you finding erros in your code by supporting type checking. – too honest for this site Jun 28 '15 at 02:38
1

From the comments it appears that you might not appreciate pointers and memory allocation. For the moment try changing:

struct game_s* game_p;

to

struct game_s game_p; 

This will eliminate your memory corruption issue.

You should read up on memory allocation and functions like malloc and free if you need to use pointers and allocate memory.

Dweeberly
  • 4,668
  • 2
  • 22
  • 41
  • While this would work, I can't do it in my actual case, because the struct is defined in a different file and the fields are not exposed. – Jake Jun 28 '15 at 01:52
  • In that case you might take a look at Dinesh's answer which shows a malloc call. However, I encourage you to study a bit about pointers and memory allocation before continuing. – Dweeberly Jun 28 '15 at 01:57
  • I'll definitely do that. – Jake Jun 28 '15 at 01:58