2

File extension: .cpp

I have the following code:

int main() {
    int N; cin >> N;
    int myArray[N];
    return 0;
}

I get an error when I'm trying to run that program if I input N as 1,000,000. However, when I set myArray[N] to myArray[1000000], it doesn't. Why does this happen?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Richard
  • 7,037
  • 2
  • 23
  • 76

5 Answers5

6

int myArray[N]; is not valid in C++. This behavior was introduced in C99 but never in C++, possibly because it causes a lot of ugly stuff to happen behind the scenes in order to make it work, and it would make the generated code less efficient as a result. In fact this feature was even reversed in C11 where its support is merely optional and not mandatory anymore. Use std::vector<int> instead, or any similar standard container of your choice.

Cyber
  • 857
  • 5
  • 10
  • I see. However, when I input the value of N = 75, it runs perfectly. Any reason why? – Richard Nov 08 '18 at 13:13
  • @WealthyPlayer some compilers still allow it as an unofficial extension. You may be using g++, which allows it, but if you compile with `-Wpedantic` you'll get this: `warning: ISO C++ forbids variable length array 'myArray' [-Wvla]`. As to why it crashes with 1000000 and not 75, this is because the program is running out of stack to store the array. I'm using `g++ (x86_64-posix-seh-rev1, Built by MinGW-W64 project)` on Windows, and by compiling with `-Wl,--stack,4194304` to increase the stack to 4MB the program does not crash anymore with an input of 1000000. – Cyber Nov 08 '18 at 13:26
  • I absolutely have no idea what that was about, I guess I'll stick to std::vector for C++ when I'm trying to initialise a dynamic array? Sounds good? And yes, I'm using CodeBlocks with the GCC/GNU Compiler. – Richard Nov 08 '18 at 15:16
  • @WealthyPlayer when you need a dynamic array yes you should use `std::vector`. There are other types of container available, but that's good enough for most applications. Check [here](https://en.cppreference.com/w/cpp/container) to know more about other containers and what they're useful for. – Cyber Nov 08 '18 at 15:26
  • @WealthyPlayer also since I'm here I'd like to add that there's always the manual alternative with the `new` and `delete` keywords, but then you have to worry about managing the memory yourself and avoid memory leaks or invalid pointers. Or you know, there's always the good old `std::malloc` and `std::free` from ``. In general, stick with standard containers unless you have a reason not to i.e. you profile your program and you notice a performance bottleneck. Always profile your program before you try to optimize it, some things are just fast enough that they don't even matter. – Cyber Nov 08 '18 at 15:38
  • I see. Thank you for the in-depth explanation, I'll stick to `std::vector` for dynamic containers :-D Guess I gotta learn its function and how it works now. – Richard Nov 10 '18 at 09:39
4

First of all VLA (variable length arrays) is an extension to C++. Compilers are supporting that since usually they support also C which has this functionality in standard.

Second problem this array is allocated on stack. Stack has very limited size. So when your N has very big value application may crash since stack will overflow.

In this case you should use std::vector which will allocate data on heap.

Question is why array with static array size do not crash? There can be couple reasons.

  1. Compiler notices that array is not used and based on "As if" rule removes array.
  2. Compiler knows size of the array at compile time, so required stack size is know. This information may be propagated to linker and application is build with bigger stack size then default value (in case of one suorce code application it may be possible). Disclaimer: this is my guessing, I didn't verified this in any form (by testing, or compiler documentation), but I've found this SO answer which confirms my suspicions.
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • I see. But what difference does it make when I use myArray[1000000] explicitly and not inserting the 1 million value from the variable N? Aren't they both supposed to return an error if they're both allocated on stack? Or does it only allocate VLA on stack and the compile-time array on heap? – Richard Nov 08 '18 at 13:09
  • @WealthyPlayer that's because just creating an array does almost nothing. To see why large arrays on the stack are bad, try actually using the array (say, set all elements to some value). – n. m. could be an AI Nov 08 '18 at 13:11
  • @n.m. Sorry, but I'm not catching your point in regard to my questions. Could you please elaborate more? I'm still learning. – Richard Nov 08 '18 at 13:14
  • @WealthyPlayer Did you actually try to use the array? What were the results? – n. m. could be an AI Nov 08 '18 at 13:39
  • It's enough to [look at the disassembly](https://godbolt.org/z/wzVpFm) to see why this program won't crash as is. – n. m. could be an AI Nov 08 '18 at 13:40
  • @n.m. assembly is not enough since you are unable to see stack size. But [this gives nice hint why it doesn't crash](https://stackoverflow.com/a/40042637/1387438). – Marek R Nov 08 '18 at 13:46
  • @MarekR The disassembly shows that between `push rbp` and `pop` the program doesn't touch the memory at all. It only flips some registers. So the amount of memory it needs is one register worth. I hope any system has stack size at least that large. – n. m. could be an AI Nov 08 '18 at 13:54
  • this is most important `sub rsp, 3999880`. AFAIK this will raise stack overflow if stack is to small. Torching memory is unimportant here. Note that in question when size of the array is not know at compile time it ends with crash (stack overflow) and he do not touch array there too. – Marek R Nov 08 '18 at 14:16
  • @MarekR no, `rsp` is just a register like any other. It can take any value without raising an error. Only an actual memory access through the register will trigger an error. Try it and see. When the size of the array is not known and must be read from `cin`, the generated assembly becomes **way** more complicated, with memory accesses all over the place (try it and see!) – n. m. could be an AI Nov 08 '18 at 14:36
  • @MarekR well in fact this program doesn't crash on my machine so I cannot point out any specific reason why it crashes for OP (like invalid memory access at a certain address). – n. m. could be an AI Nov 08 '18 at 14:50
  • @WealthyPlayer don't be. Bottom line, don't use large arrays and don't use variable size arrays. Use `std::vector` instead. – n. m. could be an AI Nov 08 '18 at 17:00
2

The size of static arrays array[N] must be known at compile time.

Use std::vector for dynamic arrays:

// Example program
#include <iostream>
#include <string>
#include <vector>

int main()
{
    int N; std::cin >> N;
    std::cout << N << std::endl;
    std::vector<int> myArray(N);
    std::cout << myArray.size() << std::endl;
    return 0;
}
Peter
  • 1,591
  • 6
  • 19
2

That happens because size of static arrays must be known at compile time.

It is strongly recommended to use std::vector instead of arrays for more flexibility, and safety (this is always the answer: Use a vector if possible). You may use std::vector::reserve to request capacity be at least the length you want it to be. Use std::vector::capacity to see the current capacity.

#include <iostream>
#include <vector>

int main () {
  std::vector<int> ivec;
  ivec.reserve(100);
  std::cout << ivec.capacity() << std::endl;
  return 0;
}

Output:

100

Only if you have a very good reason to prefer arrays over vectors, you may dynamically allocate an array. Using std::shared_ptr makes this process much safer and convenient. Here's how it's done the way you want:

#include <iostream>
#include <memory>

int main () {
  int N;
  std::cin >> N;
  std::shared_ptr<int> arr_ptr (new int[N],  std::default_delete<int[]>());
  for (int i = 0; i != N; ++i) {
    arr_ptr.get()[i] = i * 2;
  }

  for (int i = 0; i != N; ++i) {
    std::cout << arr_ptr.get()[i] << std::endl;
  }
  return 0;
} 

Input:

10

Output:

0
2
4
6
8
10
12
14
16
18
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • When I input the N as a much smaller size, e.g. 75, it runs perfectly, though. Why does that happen? – Richard Nov 08 '18 at 13:14
  • See [this](https://stackoverflow.com/questions/10675399/why-cant-the-size-of-a-static-array-be-made-variable) answer for more on the topic.Tl;dr what you are using is a Variable Length Array (not a static one), which is a part of the C99 Standard, and Variable Length Arrays have some limitations. Besides, having a very large array at stack is not a good idea, use heap instead, which is what i did in this answer. – Aykhan Hagverdili Nov 08 '18 at 13:23
1

That happens because, in C++, the size of static arrays declared with array[N] must be known at compile time and thus your error is propably your compiler which tells you that he must know the size inbeforehand. As stated use std::vector when you need dynamic arrays.

Yastanub
  • 1,227
  • 8
  • 19