0

I am trying to implement a simple sieve and to my help I found the following code:

int main(int argc, char *argv[])
{
    int *array, n=10;
    array =(int *)malloc(sizeof(int));
    sieve(array,n);
    return 0;
}

void sieve(int *a, int n)
{
    int i=0, j=0;

    for(i=2; i<=n; i++) {
        a[i] = 1;
    }
...

For some reason this works, but I think it should not! The space that is allocated for the variable array is only enough to support one integer, but a[i] for i = 2...10 are called in the function sieve. Shouldn't this cause problems?

I tried to change the implementation to

int array[10], n = 10; 

which caused "Abort trap: 6" on runtime. However, this I understand since array[10] will be outside of the space allocated. But shouldn't the same be true also for the code where malloc i used?

Truly confusing.

JezuzStardust
  • 222
  • 2
  • 10
  • The code you "found" doesn't work. First of all you only allocate space for *one single* integer. Then you go out of bounds because you forget that arrays, no matter how they are allocated, are indexed beginning with zero. – Some programmer dude Oct 07 '16 at 17:58
  • 2
    undefined behavior (which is what you have ) includes working most of the time and failing in production at the most inconvenient time. – pm100 Oct 07 '16 at 17:58
  • 1
    You cause a memory corruption. It may appear to work but result is really undefined – SomeWittyUsername Oct 07 '16 at 17:59
  • Ok, thanks for confirming this! It does "work" at least the few times I ran the code. Just for future reference I found the code at https://rosettacode.org/wiki/Sieve_of_Eratosthenes#C – JezuzStardust Oct 07 '16 at 18:01
  • `int array[10], n = 10;` will trap because you execute `a[i] = 1;` when `i <= n`, which includes the case that `i == 10`, which is an out of bounds write. You want `i < n` in that for loop. –  Oct 07 '16 at 18:09
  • Another possible duplicate: http://stackoverflow.com/questions/4534780/writing-to-pointer-out-of-bounds-after-malloc-not-causing-error – Zan Lynx Oct 07 '16 at 18:34

1 Answers1

0

You are correct in some ways. For example this line:

array =(int *)malloc(sizeof(int));

only allocates space for one integer, not 10. It should be:

array =(int *)malloc(sizeof(int) * 10);

However, that does not mean the code will fail. At least not immediately. When you get back a pointer from malloc and then start writing beyond the bounds of what you have allocated, you might be corrupting something in memory.

Perhaps you are writing over a structure that malloc uses to keep track of what it was asked for, perhaps you are writing over someone else's memory allocation. Perhaps nothing at all - malloc usually allocates more than it is asked for in order to keep the chunks it gives out manageable.

If you want something to crash, you usually have to scribble beyond an operating system page boundary. If you are using Windows or Linux or whatever, the OS will give you (or malloc in this case) some memory in a set of block, usually 4096 bytes in size. If you scribble within that block, the operating system will not care. If you go outside it, you will cause a page fault and the operating system will usually destroy your process.

It was much more fun in the days of MS-DOS. This was not a "protected mode" operating system - it did not have hardware enforced page boundaries like Windows or Linux. Scribbling beyond your area could do anything!

carveone
  • 889
  • 9
  • 16
  • 1
    That explains why it works even if it is not fail safe. I also very much appreciate your brief historical comment which was enlightening. – JezuzStardust Oct 07 '16 at 18:21
  • 1
    Compilers like Borland's "Turbo C" actually put a fixed string in the data segment and then checked when your program exited was it still intact. If not, it would print a little message to that fact to warn that you'd done something silly! – carveone Oct 07 '16 at 18:33