How do I create a C++ Integer Array of constant length? - c++

I am quite an experienced python programmer, attempting to learn C++. I am having an issue with initialising an integer array of a fixed size.
I have read this but creating my integer as a constant has not fixed my issue. What am i missing here?
BTW i am using VS2019 Community, any help would greatly be appreciated!
#include <iostream>
#include <sstream>
int numericStringLength(int input) {
int length = 1;
if (input > 0) {
// we count how many times it can be divided by 10:
// (how many times we can cut off the last digit until we end up with 0)
for (length = 0; input > 0; length++) {
input = input / 10;
}
}
return length;
}
int convertNumericStringtoInt(std::string numericString) {
std::stringstream data(numericString);
int convertedData = 0;
data >> convertedData;
return convertedData;
}
int main() {
std::string numericString;
std::cout << "Enter the string: ";
std::cin >> numericString;
const int length = numericStringLength(convertNumericStringtoInt(numericString));
std::cout << "Length of Numeric string: " << length << "\n";
int storage[length];
}

but creating my integer as a constant has not fixed my issue
It is not sufficient for the array length to be const. It must be compile time constant. const merely means that the object does not change throughout its lifetime - i.e. it implies runtime constness. Since length is not a compile time constant, the program is ill-formed. Examples of values that are compile time constant:
Literals such as 42
Template arguments
Enumerations
constexpr variables
const variables with compile time constant initialiser (this may have some limitations, I'm not sure)
It should be quite clear from the program that the length is calculated from user input, which would be impossible to do when the program is compiled. So since you cannot make it a compile time constant, you cannot use an array variable. You need to allocate the array dynamically. Simplest solution is to use a vector:
std::vector<int> storage(length);

Making the variable const is not enough.
const just means "I won't change this after it's initialised".
It has to be a compile-time constant, as the machinery for a basic C array is baked into the computer instructions that form your executable.
You're calculating it at runtime, so there's no way that is going to work.
You are going to have to use a vector or some other such dynamically-resizable array type.

If you want a fixed size array, you can use std::array, example:
std::array<int, 3> arr { 1,2,3 };
// ^
// fixed size needs to be known at compile time
If you don't know the size at compile time, use std::vector

The problem you have is that length is a run-time constant, whose value is calculated when the program is running. This is opposed to a compile-time constant, whose value is known by the compiler when you build your program.
Arrays needs compile-time constants for their size.
If the size is not known at compile-time but only at run-time, then you should use std::vector.

Related

I can't access a global array in c++

Hello first thing first forgives me if I have mistakes in my English, I am beginner in c++ and I need help with this problem please
//global variables
int RangeOfArray;
int arr[RangeOfArray-1]; // error: array bound is not an integer constant before ']' token
void functionOne(){} // I need to access the array here.
void functionTwo(){} // as well here.
int main (){
cout<<"Type the length number of the array : ";
cin >> RangeOfArray;`
}
As you can see I need the array (arr) everywhere in my program but I can't why? I don't know
An array needs a size that can be known at compile time. RangeOfArray is not known at compile time. Also, you are declaring the array and then trying to assign a size to it, which is not possible. You'll need dynamic arrays for this purpose:
#include <iostream>
int RangeOfArray;
int* arr;
int main() {
std::cout << "Type the length number of the array : ";
std::cin >> RangeOfArray;
arr = new int[RangeOfArray];
}
..or preferably, std::vector:
#include <iostream>
#include <vector>
int main() {
std::cout << "Type the length number of the array : ";
int vec_size; std::cin >> vec_size;
std::vector<int> vec;
vec.resize(vec_size);
}
Any of the 2 options work.
In these declarations
//global variables
int RangeOfArray;
int arr[RangeOfArray-1]; // error: array bound is not an integer constant before ']' token
there is declared the global variable RangeOfArray that is implicitly initialized by zero and then there is declared the variable length array arr with the size -1 that is implicitly converted to the maximum value of the type size_t due to the usual arithmetic conversions because in C++ an expression that specifies a size of an array in its declaration is converted to the type size_t.
For starters variable length arrays is not a standard C++ feature. And moreover you may not declare a variable length array with static storage duration.
And secondly using the expression -1 as the size of an array does not make a sense.
If you need a global variable that simulates an array then use the standard container std::vector<int>.
For example
#include <iostream>
#include <vector>
//global variables
std::vector<int> arr;
void functionOne(){ /* ... */ } // I need to access the array here.
void functionTwo(){ /* ... */ } // as well here.
int main()
{
size_t RangeOfArray;
std::cout<<"Type the length number of the array : ";
std::cin >> RangeOfArray;`
arr.resize( RangeOfArray );
//...
}
The vector provides member function size that reports the current number of elements stored in the vector. So you need not to make the variable RangeOfArray global.
Pay attention to that it is not a good idea to use global variables.
So you could declare the vector in main and pass it by reference to functions where it is required.
why [I cannot use the array]?
The error message that you quoted explains why:
error: array bound is not an integer constant before ']' token
The size of an array must be compile time constant. RangeOfArray-1 is not compile time constant. Hence it cannot be used as the size of an array.
If you want to create an array whose size is determined at runtime, you must use dynamic storage. Simplest solution is to use std::vector from the standard library.
Another issue is that you try to use the variable before it has been assigned a value (although it has been zero-initialised). That approach doesn't work in imperative programming languages such as C++. You must assign a value before you can access it.
Mistake 1
In standard C++, the size of an array must be a compile time constant. So when you wrote:
int RangeOfArray;
int arr[RangeOfArray-1]; //not standard c++
The statement int arr[RangeOfArray-1]; is not standard C++ since RangeOfArray - 1 is not a constant expression.
Mistake 2
From Array declarators documentation:
If the expression is a constant expression, it shall have a value greater than zero.
This means even if RangeOfArray was a constant expression, due to static initialization, RangeOfArray will be initialized with 0 and so the expression RangeOfArray - 1 evaluates to the negative integer -1. And according to the above quoted statement, int[-1]; isn't valid.
Solution
Better would be to use std::vector as shown below:
#include <iostream>
#include<vector>
//global variables
std::vector<int> arr; // empty vector
void functionOne(){
std::cout<<"functionOne called with: "<<arr.size()<<std::endl;
}
void functionTwo(){
std::cout<<"functionTwo called with: "<<arr.size()<<std::endl;
}
int main (){
int RangeOfArray = 0;
std::cout<<"Type the length number of the array : ";
std::cin >> RangeOfArray;
//resize the vector named arr
arr.resize(RangeOfArray);
//call functionOne
functionOne();
//call functionTwo
functionTwo();
}

Compiler returning an error when passing a const variable: template argument is not a constant expression

So I wrote this code ->
#include <iostream>
#include <bitset>
int main(){
int num, temp, digits = 0;
std::cin >> num;
temp = num;
while(temp){
temp /= 10;
++digits;
}
const int size = digits;
std::bitset<size> a(num);
std::cout << a << std::endl;
return 0;
}
The bitset container isnt accepting the const integer size as a parameter and throwing an error -Non-type template argument is not a constant expression. I want to know why this is happening as size has been declared as a constant and it's value isnt gonna change during the run-time of my program ?
A const variable can be interpreted differently, depending on what is assigned to it.
When assigned a compile time constant: it will be a compile time constant. That means that during compilation the constant value can be directly used in-place.
When assigned from another variable (which is not a compile time constant) : the new variable is unmodifilable. In that sense the variable is not a compile time constant. It cannot be modified in that block of code.
A template requires a compile time constant.

Array Creation Problems in C++

I'm a novice programmer trying to get a head start on some classes before the summer semester starts, and I've run into this problem while trying to create a Quick Union algorithm in C++.
I've been trying to figure out why my program creates two identical arrays, despite having two separate for loops designed to create two different arrays. Whenever my program runs to completion and prints id[] and sz[], it always outputs 1 as the element at every index in both arrays.
class quickUnionUF{
private:
int id[];
int sz[];
int root(int);
public:
quickUnionUF(int, int);
bool connected(int, int);
void unionPoint(int, int);
void print();
};
quickUnionUF::quickUnionUF(int n, int b){
id[n];
sz[b];
for(int i=0;i<n;i++){
id[i] = i;
}
for(int j=0;j<b;j++){
sz[j] = 1;
}
}
For example, if I create quickUnionUF(5, 5);
id[] should now contains elements:
0, 1, 2, 3, 4
And sz[] contains elements:
1, 1, 1, 1, 1
However, the program creates an array sz[] AND array id[] with elements:
1, 1, 1, 1, 1
Any thoughts as to why this is happening?
Standard C++ does not have sizeless array members.
Use std::vector<int> as dynamically sized arrays in C++.
#include <vector>
class quickUnionUF{
private:
std::vector<int> id;
std::vector<int> sz;
int root(int);
public:
quickUnionUF(int, int);
bool connected(int, int);
void unionPoint(int, int);
void print();
};
quickUnionUF::quickUnionUF(int n, int b)
: id(n)
, sz(b)
{
for(int i=0;i<n;i++){
id[i] = i;
}
for(int j=0;j<b;j++){
sz[j] = 1;
}
}
Your code hints at a two very important mistakes:
C++ does not work like Java. int id[] is not an reference to an array of arbitrary size on the garbage collected heap. It is instead a member array of undefined size used to implement dynamic arrays (and similar features) in C99. You should never use this syntax unless you know exactly what you are doing, because it is almost guaranteed to be wrong otherwise.
id[n] does not allocate an array at all. Instead it just indexes id and discards the result.
Listen to your compiler!
First, your code should not compile due to the fact, that only the last member of a struct may be a flexible array type. In fact clang howls:
main.cpp:53:9: error: field has incomplete type 'int []'
int id[];
MSVC howls:
1>main.cpp(54): error C2229: class 'quickUnionUF' has an illegal zero-sized array
And g++ only warns (well, g++ is strange in what it accepts sometimes):
main.cpp:53:12: warning: ISO C++ forbids zero-size array ‘id’ [-Werror=pedantic]
int id[];
Note: g++ is wrong in compiling this, even if one allows flexible array members. This is defined in C99 6.7.2.1§16 and C11 6.7.2.1§18 both of which begin with (emphasis is mine):
As a special case, the last element of a structure with more than one named member may
have an incomplete array type; this is called a flexible array member. [...]
What is happening?
Well, assuming you got your code to compile anyway, it basically means the following:
Create an object with the alignment of integers, but NO elements at all. Take a peek at the following test program:
quickUnionUF q;
::std::cout << sizeof(quickUnionUF) << "\n";
::std::cout << &q << "\n" << &q.id[0] << "\n" << &q.sz[0] << "\n";
The only compiler that managed to compile this at all (gcc 4.9.0) gave the following result:
0
0x7fff1bf6274c
0x7fff1bf6274c
0x7fff1bf6274c
So, this is a zero byte object (yes, this is illegal C++, since every C++ object has a size > 0) and the first element of each array is at the same position (OUTSIDE YOUR OBJECT!). Remember, you declared id and sz to have zero elements!
Therefore, you are writing to the same arbitrary position. You can consider this the extreme case of a buffer overflow: By writing 5 integers to a zero size buffer, you are overflowing from the first zero size buffer through the second zero size buffer into memory totally not under your control.
This also explains your observed result: The second loop simply overwrites what the first did (and it still does it by corrupting your stack).
How do I fix this?
Just use a vector. You can tell it how big you want it and you can ask it to tell you when you are indexing to some position that is not yours.

How to create a variable size char array in VC++

const int sizea = 600;
char sz[sizea];
above code works fine. But below code segment cause errors.
I'm working on visual studio 2005 - MFC application
CString strFinal;
.......//strFinal value is dynamically changing . .
const int size = strFinal.GetLength();
char sz[size];
Error 2 error C2057: expected constant expression
Error 5 error C2070: 'char []': illegal sizeof operand
Error 4 error C2133: 'sz' : unknown size Error 3 error C2466: cannot allocate an array of
constant size 0
In the current version of C++, arrays must have a fixed size, specified by a compile-time constant. If you need to use a run-time value, then your options are:
most portably, use a dynamic array class such as std::string or std::vector<char>;
use a compiler that supports C99 variable-length arrays as a non-standard extension;
wait a year for dynamic arrays to (hopefully) be introduced in C++14 (and perhaps wait a bit longer for your compiler vendor to catch up).
Normal use-case is to use new (and delete when you're done) for variable-sized elements. If you must use the stack, you can use alloca.
char *psz = new char[size+1]; // +1 you probably want zero-termination
...
delete [] psz;
you can use vector as a dynamic array. Try this.
#include <vector> // use this header
#include <iostream>
using namespace std; // use this namespace
int main()
{
vector<int> v; //declare dynamic array equivalent
for (int i = 0; i < 10; ++i) {
v.push_back(10 + i);
}
cout << "vector data: " << endl;
print_collection(v);
while (v.begin() != v.end()) {
cout << "v.back(): "; print_elem(v.back()); cout << endl;
v.pop_back();
}
}
It produces an error because GetLength() returns you an arbitrary value, not statically defined.
The proper way is to allocate enough memory to hold your string and, if required, the NULL-terminated symbol either by calling malloc or by using the new operator (if compiling with C++ compiler).
I did something like this long time ago
the Idea is to work with pointers.
so you need to make structure that has (char and nextPointer)
the char represent the current value of the array and the nextPointer represent the next structure of the series
looping all through that pointers u will have your array of whatever you want your structure connected
struct yourStructure {
Char char;
double nextPointer;
} ;
so you create first structure and connect to the second and the tree

convert variable to const

I have an array that i dont know it size till run time. Once the program starts and size is computed, the size won't change.
i tested the following code:
#include <iostream>
#include <boost/array.hpp>
#include <cstdint>
int main()
{
uint32_t num_bits = 12;
const uint32_t num_elements = 1 << num_bits;
boost::array<double, num_elements > myArray; //does not work
return 0;
}
the following code doesn't work since num_elements is computed. I saw that there are "const_cast" option, but i am not sure if it will solve my problem.
I would apprichiate if there is a boost solution, since i would like to use boost::array.
EDIT
num_bits is a parameter which i read from a file, this mean also unknown before run time. I am aware of the solution using std::vector, but access speed is also important, since i access those elements frequently and my simulation takes about 3 days... At the moment i use simply array (new and delete)
Boost array is for arrays whose size is known at compile time. Its arguments have to be constant expressions.
Use std::vector or similar container.
Although your example doesn't need to be calculated at run time:
const uint32_t num_bits = 12; // mark this const too
const uint32_t num_elements = 1 << num_bits;
boost::array<double, num_elements > myArray;
Can't you use std::vector instead of boost::array? The size of a std::vector can be computed at runtime.
The const_cast only converts a variable to/from const at runtime as well, it can't be used to create a constant at compile-time, which boost::array (and the new C++11 std::array) wants.
Argument to any template should be a compile time constant (or type). If you know num_bits at compile time then use it as compile time constant:
boost::array<double, (1 << num_bits)> myArray; //ok
If the size is not known at compile time then use dynamically allocated arrays or std::vector.