IMHO user463035818s answer is sufficient, but for all that OP asked me
how to fix this compiler issue.
The recommended fix would be by design i.e. like shown in user463035818s answer.
So, I want to elaborate how to fix the sample code of OP (with "minimal" changes). That might make obvious why user463035818s answer is the better one. (I repeated the link three times – it should be clear to everybody that I consider this as the better solution.)
The actual compiler error (or warning or feature accepted by compiler extension):
OP used int ar[]
a C array as class member without denoting the size.
This is called Flexible array member but it is a C99 feature (not supported by the C++ standard).
The linked Wikipedia article provides a nice example:
struct vectord {
size_t len;
double arr[]; // the flexible array member must be last
};
To be clear, flexible array members don't provide automatic allocation. They just represent an array of arbitrary length. The programmer is responsible to grant sufficient storage for that array. Hence even in C, and with the resp. syntax adjustments, this code would have been broken.
Some C++ compilers adopt features from C as (proprietary) extension. That's the reason that OP got responses ranging from "On my side, it works."1 to "This is a compiler error." However, I would consider usage of such extensions as bad style in general. With different compiler settings or a different compiler, this might not work anymore.
1 This is not the only issue of OPs code. "It works" might be merely bad luck. OPs code has Undefined Behavior. One kind of Undefined Behavior is "It works" which is not the best one because programmer might believe that the code is fine.
A lot of higher level languages (Java, C#, Python) tries to cover memory allocation and storage management "under the hood" completely because it's not quite easy to make this always correct and consider every edge case sufficiently. This might cause an additional performance impact for the administration of memory. In C and C++, the programmer has ful control over memory allocation. It's both a blessing and a curse.
The standard library of C++ provides a variety of tools to make programmers allocation life easier.
For dynamic arrays, the tool of choice is the template class std::vector
. It provides an overloaded operator[]
which allows that it can be accessed just like an array. It provides methods like reserve()
and resize()
. The storage is internally managed.
I would strongly recommend to use std::vector
but there is also the possibility to do it using new[]
and delete[]
.
For this, the class array
might look as follows:
class array {
int *ar; // a raw pointer for storage
int n; // the current size of array
public:
int display();
int*
and int
are plain old data types → implicit construction leaving them uninitialized. So, there really should be defined at least a default constructor.
array(): ar(nullptr), n(0) { }
The input()
method has to ensure proper storage.
void input()
{
// release old memory (if there is one)
delete[] ar; ar = nullptr; n = 0;
// input
std::cout << "Enter item size: ";
std::cin >> n;
if (n <= 0) return;
ar = new int[n];
for (int i = 0; i < n; ++i) {
std::cout << "Enter value at index " << i << ": ";
std::cin >> ar[i];
}
}
When an instance of class array
is deleted it should release the internal storage. Otherwise, the allocated memory pointed by ar
will be orphaned and lost until process is terminated by OS. Such lost memory is called memory leak.
~array() { delete[] ar; }
Please, note that calling delete[]
(or delete
) with a nullptr
is valid. Hence, no extra if (ar)
is needed.
Finally, we have to obey the Rule of three. The compiler generates implicitly copy constructor and copy assignment operator which will copy the class array
members by value. Copying a pointer by value does not mean that the contents (it points to) is copied. It just means copy the pointer (address value). Hence, an (accidental, unintended) copy of class array
could result in two instances of class array
which members ar
point to the same memory. Once, one of them deletes that memory, the ar
of the other becomes dangling i.e. points to released memory. (Bad!) If the other instance is destroyed also it will delete[] ar
again. This is double deleting which is prohibited. (Bad again!)
One option could be to define copy constructor and copy assignment to handle this appropriately by making a deep copy of ar
contents (with another new[]
). However, if copy is not intended, an alternative is to just explixitly prohibit copy for class array
:
array(const array&) = delete;
array& operator=(const array&) = delete;
};
Putting this althogether in array.cc
:
#include <iostream>
class array {
int *ar; // a raw pointer for storage
int n; // the current size of array
public:
array(): ar(nullptr), n(0) { }
~array() { delete[] ar; }
array(const array&) = delete;
array& operator=(const array&) = delete;
void input();
void display();
};
void array::input()
{
// release old memory (if there is one)
delete[] ar; ar = nullptr; n = 0;
// input
std::cout << "Enter item size: ";
std::cin >> n;
if (n <= 0) return;
ar = new int[n];
for (int i = 0; i < n; ++i) {
std::cout << "Enter value at index " << i << ": ";
std::cin >> ar[i];
}
}
void array::display()
{
std::cout << "You Entered: ";
for (int i = 0; i < n; ++i) {
std::cout << ar[i];
}
std::cout << '\n';
}
int main()
{
array obj;
obj.input();
obj.display();
return 0;
}
Compiled and tested:
$ g++ -std=c++11 -Wall -pedantic array.cc && ./a.out
Enter item size: 1↲
Enter value at index 0: 2↲
You Entered: 2
$
Live Demo on coliru
The last sentence in OPs question is a bit unclear for me (although I assume it's just bad worded):
In the sample run, I entered 1 and 2 and I am expected to get 1 and 2.
Either input is 2 1 2
then output is 1 2
.
Or input is 1 2
then output is 2
.
Please note that array::input()
expects first input of array::n
but array::display()
doesn't output array::n
.