Search code examples
arrayscmemory-managementdynamic-memory-allocation

When I compile my short and simple C code I get "stack smashing detected", while the same code in JavaScript runs fine, why is that?


This is part of a bigger project, but I isolated the culprit for the error as being this specific snippet and adapted it so it would run by itself (including having the value for number predefined).

#include <stdio.h>

int main() {
    unsigned number = 4;
    int array[] = {};
    for (int j = 0; j < number; j++) {
        for (int i = number; i > j; i--) {
            array[j] = i;
        }
        printf("%d ", array[j]);
    }
    return 0;
}

I'm just starting to learn C, so to check if it was a problem with the code itself, and not specific to C, so I adapted it into JavaScript:

var number = 4;
var array = [];
for (var j = 0; j < number; j++){
    for (var i = number; i > j; i--){
            array[j] = i;
        }
        console.log(array[j]);
    }

It ran and gave me the result I expected. What's the problem with the C code that's making me get the error? I tried running the C code, expecting to get the numbers 1, 2, 3 and 4 printed. I got a "stack smashing detected" error message instead.


Solution

  • The problem with your code is that you are declaring an array in c, but not specifying what the size of the array is. c is an ancient language, and arrays in c mean literally a box of memory of that size given to you. You can't do anything fancy like size increasing and adding new elements to the array like in languages such as Python. One way to correct this code and make it "runnable", is to give your array a size of 4:

    unsigned number = 4;
    int array[4];  // <----- here
    for (int j = 0; j < number; j++) { 
        for (int i = number; i > j; i--) {
            array[j] = i;
        }
        printf("%d ", array[j]);
    }
    return 0;
    

    while this is a correct code since you are iterating through the list corresponding to the variable number, one way you might believe to fix it is to do what I've done below:

    unsigned number = 4;
    int array[number];  // <----- here
    for (int j = 0; j < number; j++) { 
        for (int i = number; i > j; i--) {
            array[j] = i;
        }
        printf("%d ", array[j]);
    }
    return 0;
    

    while this will work for some numbers, it will fail for large values. to explain this you will need to know that the size of anything allocated in the "stack" (any variable or value you declare normally) is determined at compile time, in other words before the program actually runs. so if you use the variable number as the size of the array, how should the compiler know what the size of the array is? values of variables are determined after compile time (at run-time). so what does the c compiler do? it will give it a random large size like 80 or 800.

    that is why we use something called heap allocation. using the library <stdlib.h> and the function malloc( size ) you can allocate memory from the heap. memory allocations from the heap are done at run-time, thus getting rid of the problem at hand. you will need to give malloc the size of memory that we want. so that is size of int * size of the array. One thing to keep in mind is to free any array that you allocate with malloc using the free function. not doing that will result in a memory leak which is a whole other story in itself. the final and correct version of the code should be:

    unsigned number = 4;
    int *array = malloc(sizeof(int) * number); // <--- allocate memory from heap at run-time
    for (int j = 0; j < number; j++) {
        for (int i = number; i > j; i--) {
            array[j] = i; 
        }
        printf("%d ", array[j]);
    }
    free(array); // free the allocated memory
    return 0;
    

    edit:

    as Eric Postpischil pointed out, my statement: "Anything allocated in the "stack" (any variable or value you declare normally) is determined at compile time” is not correct. ever since C99, a new kind of array was introduced called VLA(variable length array) which is not only allocated in the stack but its size is determined at run-time. there are still drawbacks that discourage people from using them. please see this link