Why is my code running even though I'm assigning 4 values on a 3 sized array?

88 Views Asked by At

Btw, im fairly new to coding :)

Basically I'm trying to do a program which asks the student how many grades he has (div), and calculates the overall grade (nota=grade, im portuguese). Note that in every try I always input '3' and the value for div and that I'm only showing part of the code

As for the [CORRECT VERSION], everything looks normal to me and runs fine.

**[CORRECT VERSION]**

    short unsigned int div, i;
    printf("Pretende fazer a media de quantas notas?(Máximo é 10): ");
    scanf("%hd", &div);
    float nota[div], media, soma = 0;
    for(i = 0; i < div; i++) { //duvida linhas 25-26
        pergunta:
        printf("A %dª nota foi: ", i+1);
        scanf("%f", &nota[i]);
       if((nota[i] < 0) || (nota[i] >20)) {
        printf("\n(Erro: Por favor insira valores de 0 a 20\n");
        goto pergunta;

My doubt is related to the ["NON-SENSE" VERSION], in the for loop. I understand that me making i++, the loop's first run will assume i as being 0, but inside the for loop, i will be 1. Since the array_size=3, the 3rd grade (nota) would not have a slot to be assigned (because nota[0] would be skipped, which makes it 0 right?, leaving only 2 slots left), but the loop still runs 3 times, asks for the 3 grades and gives me the overall.

**["NON-SENSE VERSION]**

    short unsigned int div, i;
    printf("Pretende fazer a media de quantas notas?(Máximo é 10): ");
    scanf("%hd", &div);
    float nota[div], media, soma = 0;
    for(i = 0; i++ < div;) { //duvida linhas 25-26
        pergunta:
        printf("A %dª nota foi: ", i);
        scanf("%f", &nota[i]);
       if((nota[i] < 0) || (nota[i] >20)) {
        printf("\n(Erro: Por favor insira valores de 0 a 20\n");
        goto pergunta;

However, replacing div for 3, even though it is the same value that div assumed on the previous version, I'm getting a segmentation fault (and on some other experiments bus error)

[VERSION WITHOUT div GIVING A NORMAL ERROR]
    short unsigned int div, i;
    //printf("Pretende fazer a media de quantas notas?(Máximo é 10): ");
    //scanf("%hd", &div);
    float nota[3], media, soma = 0;
    for(i = 0; i++ < 3;) { //duvida linhas 25-26
        pergunta:
        printf("A %dª nota foi: ", i);
        scanf("%f", &nota[i]);
       if((nota[i] < 0) || (nota[i] >20)) {
        printf("\n(Erro: Por favor insira valores de 0 a 20\n");
        goto pergunta;

Could you explain me what I'm missing and why does even the ["NON-SENSE" VERSION] runs, even though it's pretty much the same as the last one?

1

There are 1 best solutions below

1
On BEST ANSWER

A lot to unpack here, but let's do it in order.

First of all, don't do this:

unsigned div;
scanf("%hd", &div);
float nota[div], media, soma = 0;

You should either predefine a MAX_SIZE if you know the max amount of grades the student can enter or use dynamic allocation. More info about this can be found in this StackOverflow question. What you are doing is creating a VLA - Variable Length Array. This was added in the C99 standard, but using this can and will reduce portability, as not all compilers adhere to that standard.

Secondly, you are using a non-idiomatic for loop. An idiom in programming is the de-facto standard of doing certain things. We use idioms because it reduces the chance of making errors, and makes it easier for others to read and maintain our code. That's why we stick to the

for(int i = 0, i < n; i++){}

I presume you are aware of this point (as you called it non-sense), but I'm just putting it out there for anyone who might try to use code that looks like this for(i = 0; i++ < 3;) - this will leave you with nasty errors and behaviour you did not intend.

With both of these together we can see what's going on here: In your non-sense example, you are using a VLA. The way this works depends on the compiler, but I'm guessing that in this case the compiler looks at the type of your variable div - as it is an unsigned short, it knows that the value is in the range of (0 - 65,535)*, so the value is relatively small. Because it is a small value, it allocates enough memory ON THE STACK to house an array which is at most ~65k long. This means you can "safely" read and write to that memory without a stack overflow, because the OS has given your program permission to write to 65k element spots in memory.

In the other case, you say to the compiler that your array will be 3 elements long, and so your program requests only 3 elements worth of space from the OS. The OS then doesn't like you trying to read and write from memory it didn't give you, and so you end up with the error.

Final note: Please do not use goto.

*Assuming that unsigned short is 16b long, which is the minimum - it can be longer depending on system.