0

I solved this introduction problem on hackerrank. Here is something strange when I try to solve this problem.

the input is

4  
1 4 3 2

I want to read the numbers into an array.

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() {
    int a; 
    int arr[a];
    scanf("%d",&a);

    for(int i=0; i<=a-1; i++){
        scanf("%d",&arr[i]);
        printf("i = %d, a = %d\n", i, a);
    }

    return 0;
}

I got the output:

i = 0, a = 4
i = 1, a = 4
i = 2, a = 4
i = 3, a = 2

The array is correct. My question is why the value in int a is changed? Why it is changed to 2 instead of 3?

if I rearrange following lines:

    int a; 
    scanf("%d",&a);
    int arr[a];

the value in int a is not changed,

i = 0, a = 4
i = 1, a = 4
i = 2, a = 4
i = 3, a = 4
ERIC
  • 460
  • 6
  • 16
  • 2
    When you write `int arr[a];`, what value do you think `a` has? – molbdnilo Apr 16 '20 at 15:19
  • This looks like you're programming in "C with unused C++ headers" rather than C++. – molbdnilo Apr 16 '20 at 15:22
  • Yes, this part is not clear. But why it still got the value 4 without any warning? – ERIC Apr 16 '20 at 15:22
  • 2
    Also note that `int arr[a];` is illegal in C++ since `a` is not a constant expression. Use a `std::vector` instead. If you are using gcc, add the `-pedantic-errors` compilation flag to the compile command – NathanOliver Apr 16 '20 at 15:22
  • 2
    `int arr[a]` -- That line of code isn't even valid C++. Arrays in C++ must have their sizes denoted by a compile-time constant, not a runtime variable. – PaulMcKenzie Apr 16 '20 at 15:23
  • 1
    As the old saying goes, undefined behaviour is undefined. Anything can happen when you invite undefined behaviour to your party. – molbdnilo Apr 16 '20 at 15:23
  • "without any warning" ? if the first two lines did not trigger a warning you need to consult your compilers manual and crack up the warning level (`-Wall` in gcc for almost all warnings), if a compiler does not warn on that I would consider it as broken – 463035818_is_not_an_ai Apr 16 '20 at 15:45

2 Answers2

4

This is wrong:

int a; 
int arr[a];
scanf("%d",&a);

Two problems: You are using a before you read the value from the user. Using a unitinitalized is undefined behavior. The output of your code could be anything or nothing. Then you cannot have a static array with a run-time size. Some compilers support variable length arrays as an extension, but they are not standard c++ (see here).

If you want to write C++, then you should actually use C++. Dynamically sized arrays are std::vector. Your code could look like this:

#include <vector>
#include <iostream>


int main() {
    int a; 
    std::cin >> a;   // read user input before you use the value

    std::vector<int> x(a); // create vector with a elements

    for (size_t i=0; i < x.size(); ++i) {
        std::cin >> x[i];
        std::cout << "i = " << i << " a = " << a << "\n";
    }
}

My question is why the value in int a is changed? Why it is changed to 2 instead of 3?

Undefined behavior means just that, the behavior of your program is undefined. Compilers are not made to compile invalid code. If you do compile invalid code then strange things can happen. Accessing arr[i] is accessing some completely bogus memory address and it can happen that writing to that overwrites the value of a. However, it is important to note that what happens here has little to do with C++, but rather your compiler and the output of the compiler. If you really want to understand the details you need to look at the assembly, but that wont tell you anything about how C++ "works". You can do that with https://godbolt.org/, but maybe the better would be to pay attention to your compilers warnings and try to write correct code.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
1
    int a; 
    int arr[a];
    scanf("%d",&a);

This means:

  1. Declare an uninitialised a, with some unspecified value that is not permitted to be used
  2. Declare an array with runtime bounds a (which doesn't exist), which is not permitted
  3. Read user input into a.

Even if these steps were performed in the correct order, you cannot have runtime bounds in C++. Some compilers permit it as an extension, though I've found these to work haphazardly, and it's certainly going to result in strange effects when you use an uninitialised value to do it!

In this case, in practice, you probably have all sorts of weirdness going on in your stack, since you're accessing "non-existent" elements of arr, overwriting the variables on the stack that are "below" it, such as a. Though I caution that trying to analyse the results of undefined behaviour is kind of pointlesss, as they can change at any time for various black-boxed reasons.

Make a nice vector instead.

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35