How to declare a static 2D array within a function in C++? - c++

I need to declare a 2D array within a function and call the function repeatedly but the array should be declared only once at the beginning.
How can I do this? I'm new to this.
thanks in advance

Static Variables inside Functions
Static variables when used inside function are initialized only once, and then they hold there value even through function calls.
These static variables are stored on static storage area, not in stack.
consider the following code:
#include <iostream>
#include <string>
void counter()
{
static int count[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
static int index = 0;
std::cout << count[index / 3][index % 3];
index++;
}
int main()
{
for(int i=0; i < 9; i++)
{
counter();
}
}
Output:
123456789

void func1()
{
static int myArra[10][20];
}

As Razack mentioned. That is the first way.
and the second way is using std::array so you can accomplish like this.
#include <array>
void fun(){
static std::array<std::array<int, 5>,5> matrix;
}

In C++ you can use a std::array of std::arrays to create a 2D array:
#include <array>
std::array<std::array<int, 3>, 3> arr = { {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}} };
This is a 3 x 3 2D array with each element initialised to 0. The syntax for accessing an element is the same as a C-style 2D array: arr[row][col].
It could be declared static within your function, but it could also be declared within an anonymous namespace at the top of your .cpp file like this:
namespace
{
std::array<std::array<int, 3>, 3> arr = { {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}} };
}
This is generally better practice than static variables. The array is initialised only once before the main thread starts and only functions within your translation unit (your .cpp file) have access to it.

void process(int ele, int index) {
static std::vector<std::vector<int>> xx_vec = {{1,2,3}, {11,12}, {}};
// example:
for (int i = 0; i < xx_vec.size(); i++) {
// add
if (index == i) {
xx_vec[i].push_back(ele);
}
// read
for (int j = 0; j < xx_vec[i].size(); j++) {
std::cout << "xx_vec" << "place:" << i << "," << j << ":" << xx_vec[i][j] << std::endl;
}
}
}

Related

A good way to construct a vector of 2d array

What I want to do is
double A[2][2] = {
{4, 7},
{2, 6}
};
std::vector<double[2][2]> B;
for (int i = 1; i <= 5; i++)
{
B.push_back(A);
}
But C++ cannot store an array in std::vector, what is the proper (speed) way to do that? Is A[2][2] faster than std::arraydue to cache coherency?
std::array is probably the best way to go here. It should preform nearly identically to the C style array you've got:
#include <array>
#include <vector>
int main() {
using Array2d = std::array<std::array<double, 2>, 2>;
Array2d A = {{{4, 7}, {2, 6}}};
std::vector<Array2d> B;
for (int i = 1; i <= 5; i++) {
B.push_back(A);
}
}

C++ initialize objects with packed array of integers

I have a class like this:
#define MYNUM 4
class myClass {
private:
char myData[MYNUM];
public:
myClass(char myArr[MYNUM]) {
for (int i = 0; i < MYNUM; i++) myData[i] = myArr[i];
}
};
I want to initialize an array of myClass objects like so:
static myClass obj_arr[5] = { {1, 1, 1, 1}, {2, 2, 2, 2}, {3, 3, 3, 3}, {4, 4, 4, 4}, {5, 5, 5, 5} };
But I am getting error: too many initializers. Is there a way that I can initialize the obj_arr array in the way that I want?
First, in your existing constructor, the char myArr[MYNUM] parameter is the same as passing char myArr[] which is the same as char *myArr. IOW, the constructor takes a simple pointer as input, so it does not actually ensure the input array is really MYNUM elements. To do that, you need to pass the array by reference instead of by pointer.
As for the kind of initialization that you want, add a constructor that takes a std::initializer_list as input.
Try this:
#include <initializer_list>
class myClass {
private:
char myData[MYNUM];
public:
myClass(char (&myArr)[MYNUM]) {
for (size_t i = 0; i < MYNUM; ++i) myData[i] = myArr[i];
}
myClass(std::initializer_list<char> myList) {
for (size_t i = 0; (i < myList.size()) && (i < MYNUM); ++i) myData[i] = myList.begin()[i];
for (size_t i = myList.size(); i < MYNUM; ++i) myData[i] = 0;
}
};
Live Demo
You cannot pass an array as a function parameter like that. You do have a few options to get the initialization syntax you want though:
Make myClass an aggregate by making myData public:
constexpr size_t MYNUM = 4;
class myClass {
public:
char myData[MYNUM];
};
Live Demo
C++ allows the members of aggregate classes to be initialized directly using brace-initialization. This is the path that the standard library's std::array template uses. This obviously won't work if your class has other data members that you want to keep private.
Use a std::initializer_list<char>
constexpr size_t MYNUM = 4;
class myClass {
private:
char myData[MYNUM];
public:
myClass(std::initializer_list<char> myList)
{
// Initialize first elements of myData with the parameters passed
for (size_t i = 0; i < std::min(myList.size(), MYNUM); ++i) {
myData[i] = myList.begin()[i];
}
// Fill out any missing elements with 0
for (size_t i = myList.size(); i < MYNUM; ++i) {
myData[i] = 0;
}
}
};
Live Demo
This will work to initialize a private class member, and it supports brace-initialization. It even zero-fills trailing elements if not provided like the default way C++ treats brace-initializing arrays. Its only drawback is that it won't produce an error if more elements are given than myClass wants.
Templates
constexpr size_t MYNUM = 4;
class myClass {
private:
char myData[MYNUM];
public:
template <typename... Ts>
myClass(Ts... args)
: myData{static_cast<char>(args)...}
{
}
};
Live Demo
This is the closest you can get to the aggregate initialization approach with a private class member. Instead of accepting a container to use to initialize myData, myClass's constructor accepts a variable number of parameters, and uses them to directly initialize myData. This will zero-initialize trailing elements if less than MYNUM parameters are provided and will produce a compile-time error if more than MYNUM parameters are provided.
Utilized nested for loop to assign elements of array (which was passed by const. ref.) to member variable.
#include <iostream>
#define MYNUM 4
class myClass {
private:
int myData[MYNUM][MYNUM];
public:
myClass();
myClass(const int (&myArr)[MYNUM][MYNUM]){
for(int i = 0; i < MYNUM; i++){
for(int j = 0; j < MYNUM; j++){
myData[i][j] = myArr[i][j];
}
}
}
void printmyData(){
for(int i = 0; i < MYNUM; i++){
std::cout << "{";
for(int j = 0; j < MYNUM; j++){
std::cout << myData[i][j];
}
if (i < MYNUM){
std::cout << "}";
if (i < MYNUM-1){
std::cout << ",";
std::cout << " ";
}
}
}
std::cout << std::endl;
}
};
int main () {
int mainArr[MYNUM][MYNUM] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {4, 3, 2, 1}, {8, 7, 6, 5}};
myClass obj = myClass(mainArr);
obj.printmyData();
return 0;
}

set multiple array variables at the same time (c++)

I'm trying to make an ASCII art using C++, and having some problems in arrays.
Is there any way to set multiple array variables at the same time?
Let me be more specific.
When you initialize an array, you can do this way.
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
By the way shown above, you can set 10 array variables at the same time.
However, I want to (re) set some of the array variables like this?
a[1] = 3;
a[4] = 2;
a[5] = 2;
a[7] = 2;
Since there is NO rule in the variables, I can't do
for(int i=0; i<10; i++) a[i] = i+1;
fill(n);
I can't use an for statement or the fill, fill_n function, since there is no regularity.
To sum up,
Is there any way to set more than 1 array variables at the same time? (Like the second code snipplet above?
Given a index-value mapping list, and assign it one by one.
template<typename T, size_t N>
void Update(T(&arr)[N], const std::vector<std::pair<size_t, T>>& mappings)
{
for (const auto& mapping : mappings)
if(mapping.first < N)
arr[mapping.first] = arr[mapping.second];
}
int main()
{
int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Update(arr, { {1, 3}, {4, 2}, {5, 2}, {7, 2} });
return 0;
}
As far as I'm aware without a pattern a control structure is kind of redundant, you might be better served reading from a file.
// for user input
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
for (int i = 0; i < 10; i++) {
cout << "Please input your value for array index " << i << endl;
cin >> arr[i];
}
// for manual input in initalization
int arr[10] = { 0, 3, 2, 2, 2, 5, 6, 7, 8, 9 };
However a better approach might be to read it from a file, http://www.cplusplus.com/forum/general/58945/ Read "TheMassiveChipmunk"'s post there for exactly how to do it.
Assuming you know which indices you will be changing upfront you can use a separate index array:
int ind[4]= {1,4,5,7};
..and an accompanying array with values
int new_val[4] = {3,2,2,2};
The you can use the following for loop to assign the values:
for (int i=0; i<4; i++)
arr[ind[i]] = new_val[i];
You should also use some variable signifying the number of indices to be changed like int val_num = 4 instead of plain number 4.
Changes that are defined in runtime to an array can be easily implemented by using a list to save tuples that represent the changes you want to make. As an example, we can write:
#include <tuple>
#include <list>
#include <iostream>
using namespace std;
typedef tuple <int, int> Change;
int main() {
int a[5] = {1,2,3,4,5};
list<Change> changes;
//represents changing the 2-th entry to 8.
Change change(2,8);
changes.push_back(change);
for(auto current_change: changes)
a[get<0>(current_change)] = get<1>(current_change);
cout << a[2] << '\n';
}
Prints 8.

How do I stop my array from printing address?

I have a header, cpp and main class.
//Arr.h
class Arr
{
public:
void setArr();
void printArr();
private:
int x[5];
};
//Arr.cpp
#include "Arr.h"
#include <iostream>
using namespace std;
void Arr::setArr()
{
int x[5] = { 2, 3, 5, 7, 11 };
}
void Arr::printArr()
{
for (int i = 0; i < 5; i++)
{
cout << x[i] << "\n";
}
}
//main.cpp
int main()
{
Arr a;
a.setArr();
a.printArr();
}
However, when I run the code, a.printArr() prints out array address and not the values contained in the array. Is there a way to fix this?
Your code will print not address but some indeterminate value generated via default-initializing. Initialize the member array instead of the local array to throw away.
void Arr::setArr()
{
x[0] = 2;
x[1] = 3;
x[2] = 5;
x[3] = 7;
x[4] = 11;
}
Your problem is here:
void Arr::setArr()
{
int x[5] = { 2, 3, 5, 7, 11 };
}
the declaration int x[5] defines a new array of 5 elements which will be destroyed on exiting that function; and the name x hides the data member Arr::x.
One way you can do it is this:
void Arr::setArr()
{
/*static*/ auto arr = { 2, 3, 5, 7, 11 };
std::copy(arr.begin(), arr.end(), x);
}
Full code:
#include <iostream>
#include <algorithm>
class Arr
{
public:
void setArr();
void printArr();
private:
int x[5];
};
using namespace std;
void Arr::setArr()
{
/*static*/ auto arr = { 2, 3, 5, 7, 11 };
std::copy(arr.begin(), arr.end(), x);
}
void Arr::printArr()
{
for (int i = 0; i < 5; i++)
{
cout << x[i] << "\n";
}
}
//main.cpp
int main()
{
Arr a;
a.setArr();
a.printArr();
}
Your code is not printing array address. Maybe you saw some unexpected numbers and assumed it was an address, but in fact it is undefined behaviour caused by outputting uninitialized variables.
Your code int x[5] = .... failed because this declares a new local variable x, it doesn't modify the class member x.
Perhaps you tried:
x = { 2, 3, 5, 7, 11 };
and got compilation errors. This is because C-style arrays may not be assigned. This annoying rule is a hangover from C++'s past. To avoid this problem and many others, you can try to avoid using C-style arrays. In this case use a C++ array:
private:
std::array<int, 5> x;
Then the suggested assignment will work.
As WhiZTiM has already pointed out, your problem is at the setArr function in your class. The reason for this is because in C++ you cannot assign values to the array in the "normal fashion" i.e. using x = {blah, blah, blah}; (unless you use std::array<int, ARRAYSIZE>). In setArr you are creating another array named x and then this array is deleted once it is out of scope, and in printArr you are printing an array with no values in it yet.
Each value in the array must be set individually in C styled arrays (as shown in MikeCAT's answer).
One solution to this is to create a temporary array with the values you want and assigning the values to your class array through a for loop, i.e.:
void Arr::setArr() {
const int ARRAYSIZE = 5;
int tmp[ARRAYSIZE] = {2, 3, 5, 7, 11};
for (int i = 0; i < ARRAYSIZE; ++i) {
x[i] = tmp[i];
}
}
As M.M also pointed out, can simply change int x[5] in your private variables in Arr to std::array<int, 5> x and then in setArr simply have the statement: x = {2, 3, 5, 7, 11}; which is the better option in my opinion and easier to read, but it's also good to know how to use C arrays 😊

How to return 2 dimension array in C++

I have a segmentationfault at the line :
cout << b[0][0];
Could someone tell me what should I do to fix my code?
#include <iostream>
using namespace std;
int** gettab(int tab[][2]){
return (int**)tab;
}
int main() {
int a[4][2] = {{0, 0}, {1, 0}, {2, 0}, {2, 1}};
int ** b = gettab(a);
cout << b[0][0];
return 0;
}
A 2-dimensional array is not the same thing as an array of pointers, which is how int** is interpreted. Change the return type of gettab.
int* gettab(int tab[][2]){
return &tab[0][0];
}
int main() {
int a[4][2] = {{0, 0}, {1, 0}, {2, 0}, {2, 1}};
int* b = gettab(a);
cout << b[0]; // b[row_index * num_cols + col_index]
cout << b[1 * 2 + 0]; // the 1 from {1, 0}
}
Or:
int (*gettab(int tab[][2]))[2] {
return tab;
}
// or:
template<class T> struct identity { typedef T type; };
identity<int(*)[2]>::type gettab(int tab[][2]) {
return tab;
}
int main() {
int a[4][2] = {{0, 0}, {1, 0}, {2, 0}, {2, 1}};
int (*b)[2] = gettab(a);
cout << b[0][0];
}
Being c++, rather than c, there are much better ways of handling arrays of all sorts, and passing them around.
The type of tab without square brackets is not actually int **. It is actually int (*)[2]. When you apply two [] operators to the resulting pointer, you end up dereferencing the first value in your array, 0, as a NULL pointer. Try this instead:
#include <iostream>
using namespace std;
typedef int (*foo)[2];
foo gettab(int tab[][2]){
return tab;
}
int main() {
int a[4][2] = {{0, 0}, {1, 0}, {2, 0}, {2, 1}};
foo b = gettab(a);
cout << b[0][0];
return 0;
}
Your seg fault us because you pass in an "int*" effectively. A 2D array is not a double pointer ...
You are best off using a pointer that is "x*y" in size and addressing it without the 2 dimensions ... the code will end up the same anyway as the compiler will just generate the same code you would have to write more explicitly anyway :)
a 2 diminsional array isn't the same thing as an array of pointers. a 2 dimensional array is just a pointer to a hunk of memory that you have told the compiler to let you access as a 2 dimensional array
int* gettab(int tab[][2]) {
return (int*)tab;
}
int main() {
int a[4][2] = {{0, 0}, {1, 0}, {2, 0}, {2, 1}};
int* b = gettab(a);
cout << b[0 + 2*0];
return 0;
}
will do what you want. But I wonder if you really need to be trying to return a 2 dimensional array from a function in the first place. Perhaps a less made-up example if what you are trying to do would be helpful?
edit: fixed missing *2 in the calculation [0 + (sizeof(int)*2)*0].
edit again: well that was dumb. the multiplication of the column size of 2 by the size of an int is automatic in this case. sizeof(int) removed.