Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
first file. now we are in "Position.h"
struct Position{
int digit;
int possible[9];
int logicalSize;
bool isPermanent;
Position* next;
Position* last;
};
typedef Position* Positionptr;
next file. now we are in "Board.h"
#include "Position.h"
class Board{
private:
//maybe use an array of structures
Position elements[81];
bool membership(int arr[], int digit);
public:
void print();
Board(int input[]);
int* getRow(int row);
int* getColumn(int col);
//make private
void makePossibleList(int row, int col);
void solve();
};
next file. now we are in "Board.cpp"
#include "Board.h"
#include <iostream>
using namespace std;
Board::Board(int input[]){
for(int i = 0; i < 81; i++){
Position temp;
temp.digit = input[i];
//possible is already initialized
if(input[i] == 0){
temp.isPermanent = false;
}
else{
//this position is set and cannot be changed
temp.isPermanent = true;
}
elements[i] = temp;
}
}
void Board::print(){
for(int i = 0; i < 9; i++){
int* arr = getRow(i);
for(int j = 0; j < 9; j++){
cout << arr[j] << " ";
}
cout << endl;
}
//confirmed that it can print backwards
}
bool Board::membership(int arr[], int digit){
for(int i = 0; i < 9; i++){
if(arr[i] == digit) return true;
}
return false;
}
void Board::makePossibleList(int row, int col){
Position temp = elements[row*9 + col];
int* tempRow = getRow(row);
int* tempColumn = getColumn(col);
for(int i = 0; i < 9; i++){
if(membership(tempRow, i)){
continue;
}
else if(membership(tempColumn, i)){
continue;
}
else{
temp.possible[temp.logicalSize] = i;
temp.logicalSize++;
}
}
//find the possible values for this position
}
int* Board::getRow(int row){
int* temp = new int[9];
for(int i = (row*9); i < (9*(row+1)); i++){
temp[i-row*9] = elements[i].digit;
}
return temp;
}
int* Board::getColumn(int col){
int* temp = new int[9];
for(int i = 0; i < 81; i+= 9){
temp[((i+1)/9)] = elements[(i+col)].digit;
}
return temp;
}
void Board::solve(){
cout << "here";
for(int i = 0; i < 81; i++){
Position temp = elements[i];
if(temp.isPermanent){
continue;
}
///*
else{
int row = i/9;
int col = i%9;
makePossibleList(row, col);
if(temp.logicalSize == 0){
break; //something messed up
}
else{
for(int i = 0; i < 9; i++){
cout << temp.possible[i] << " ";
}
cout << endl;
//use the end of possible list value
temp.digit = temp.possible[temp.logicalSize-1];
temp.digit = *(temp.possible + temp.logicalSize-1);
temp.logicalSize--;
//logicalSize will equal 0 if we use up the last one!!
}
}
//*/
}
cout << "here";
//either the loop broke because something is wrong
// or the loop finished and the puzzle is solved
print();
}
//In the main.cpp file I run the driver code
//everything from above comes from the Board.h file
next file. we are now in main.cpp
#include <iostream>
#include "Board.h"
using namespace std;
int main() {
cout << "Hello World!\n";
int puzzle[] = {0, 2, 0, 0, 9, 0, 0, 6, 0,
0, 0, 9, 0, 5, 0, 3, 0, 2,
0, 8, 0, 7, 0, 0, 0, 5, 0,
0, 6, 0, 0, 1, 0, 0, 0, 3,
0, 7, 0, 0, 3, 0, 0, 9, 0,
9, 0, 0, 0, 6, 2, 0, 7, 0,
0, 3, 0, 0, 0, 1, 0, 2, 0,
8, 0, 2, 0, 7, 0, 4, 0, 0,
0, 9, 0, 0, 8, 0, 0, 3, 0};
Board x = Board(puzzle);
//x.print();
cout << "here";
x.solve();
}
I cannot understand why my code segment does not run properly ALL the time. It will run once, ill hit run one more time, and then it wont run. I am using the repl.it compiler. I have an inkling that the solve() method is the root of the problem as I tested other parts of the program before I wrote the solve() method. Is there anything wrong with my memory allocation? Thanks!
C++ code that sometimes works, is a strong indication for Undefined Behavior.
So, as a first step I ran this through UBSan
Here is the result on Godbolt: https://godbolt.org/z/jqpubW
example.cpp:60:12: runtime error: member call on address 0x00000044a300 which does not point to an object of type 'std::basic_ostream<char>'
0x00000044a300: note: object has invalid vptr
<memory cannot be printed>
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior example.cpp:60:12 in
example.cpp:62:10: runtime error: member call on address 0x00000044a300 which does not point to an object of type 'std::basic_ostream<char>'
0x00000044a300: note: object has invalid vptr
<memory cannot be printed>
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior example.cpp:62:10 in
These are the highlighted lines:
int* arr = getRow(i);
for(int j = 0; j < 9; j++){
cout << arr[j] << " ";
}
cout << endl;
The row returned has not been initialized.
Memory Sanitizer
You have to fix this, in order to see if more issues exist.
Afterwards, also run this through Address Sanitizer.
Let's run it through Memory Sanitizer first (as someone wrote a comment that there's uninitialized memory).
This is on a GCP micro-us-1 instance running "debian-10-buster-v20200210", in case you don't have a Linux machine handy. Just spin up an instance and install sudo apt install clang.
user#micro-us-1:~$ clang++ -fsanitize=memory -g q61003206.cc && ./a.out
Hello World!
==6314==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x4991d4 in Board::makePossibleList(int, int) /home/user/q61003206.cc:89:39
#1 0x499789 in Board::solve() /home/user/q61003206.cc:125:7
#2 0x499ce4 in main /home/user/q61003206.cc:164:5
#3 0x7fcc3fd3609a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)
#4 0x41f379 in _start (/home/user/a.out+0x41f379)
SUMMARY: MemorySanitizer: use-of-uninitialized-value /home/user/q61003206.cc:89:39 in Board::makePossibleList(int, int)
Exiting
This is pointing at temp.possible which is not initialized because the default constructor for Position does not initialize the possible field. The right way to fix this, is to make possible a std::array<int, 9> possible;. Also, default initialize Position::logicalSize.
void Board::makePossibleList(int row, int col) {
Position temp = elements[row * 9 + col];
int *tempRow = getRow(row);
int *tempColumn = getColumn(col);
for (int i = 0; i < 9; i++) {
if (membership(tempRow, i)) {
continue;
} else if (membership(tempColumn, i)) {
continue;
} else {
// This is the problematic line as highlighted by MSAN
temp.possible[temp.logicalSize] = i;
temp.logicalSize++;
}
}
// find the possible values for this position
}
Fix
This is how the Position struct looks like afterwards for me:
struct Position {
int digit;
std::array<int, 9> possible ; // This should be a vector
int logicalSize {0};
bool isPermanent;
Position *next;
Position *last;
};
This is enough to fix the issue, but you should really do it this way. Default initialize all members, and remove unused members, and use the right container for something which is variable sized (vector).
struct Position {
int digit {-1};
// logicalSize and possible get combined into one vector that can grow and shrink.
std::vector<int> possible;
bool isPermanent {false};
// These two are unused!
// Position *next;
// Position *last;
};
Side note, you'll also have to fix this block like so:
// use the end of possible list value
temp.digit = temp.possible[temp.logicalSize - 1];
// temp.digit = *(temp.possible + temp.logicalSize - 1);
temp.digit = temp.possible.at(temp.logicalSize - 1);
temp.logicalSize--;
Code Review
I suggest that you post this on Code Review SE.
Some items of note, but not exclusive:
Comment your data structures. For example, what is the meaning of the int possible[9] field in Position.
Use modern C++.
Use containers as provided by the STL. In your case this means a lot of std::array.
Many fewer raw pointers, and definitely no using of new.
Do not use using namespace std.
Was trying to write a program which converts the value`s from one assigned array to another unassigned one. The code i wrote:
#include "stdafx.h";
#include <iostream>;
using namespace std;
int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int j[10];
int copy_array(int *p1, int n);
int *p2, *p2;
int main() {
for (int l = 0; l < 10; l++) {
cout << a[l] << endl;
}
copy_array(a, 10);
for (int i = 0; i < 10; i++) {
j[i] = &p2;
cout << j[i] << endl;
}
system("PAUSE");
return 0;
}
int copy_array(int *p1, int n) {
while (n-- > 0) {
*p1 = *p2;
*p1++;
*p2++;
}
}
Im using the Microsoft visual studio platform and the error i got was "There is no context in which this conversion is possible". Why i cant use this int convert path? how can i fix and connect the 2 arrays using int type conversion(if its possible)?
What i tried was manipulating the local function copy_array so it makes the conversion using the addresses of the j[10] array integers, but this gave me another error. Any support and advice would be appreciated.
These are some notes on your code:
you have redundant p2 declaration:int *p2, *p2;. Also you need to initialize it. so make it: int *p2 = j; (in fact, you don't actually need to use this global variable - you can achieve the same effect by passing j as necessary).
Inside your copy function, your assignment should be in reverse:
*p2 = *p1; not *p1 = *p2; - the right-hand side is assigned to the left hand side.
When printing j, you do not need j[i] = &p2; which alters j's contents.
It is better to define the arrays inside the function not in the general scope.
Correct them and your code should work fine.
However, You do not need pointers to do this at all.
Consider the following code and compare it to yours:
#include <iostream>
using namespace std;
void copy_array(int [], int [], int);
void print_array(int [], int);
int main() {
int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int j[10];
print_array(a,10);
copy_array(a, j, 10);
print_array(j,10);
return 0;
}
void copy_array(int s[], int d[], int n) {
for (int i = 0; i < n; i++)
d[i] = s[i];
} // s for source & d for destination
void print_array(int arr[], int n) {
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << "\n\n";
}
You don't need p2 to be global.
Just add parameter to copy_array.
like this:
void copy_array(int *p1, int *p2, int n) {
while (n-- > 0) {
*p1 = *p2;
p1++;
p2++;
}
}
and call like this:
copy_array(j, a, 10);
Also: to print the copy you just do:
for (int i = 0; i < 10; i++) {
cout << j[i] << endl;
}
I want to build on #Shadi's answer, which you should upvote, and make the code more C++-idiomatic.
In C++, we don't need to explicitly return 0; from main; it is implied, if you haven't returned anything else.
It's better to use names in a similar scheme for similar variables. Specifically, i and j are common variable names for integer scalars, e.g. counters - not arrays. I'd suggest you use a and b for the arrays, or values and copy_of_values etc.
The C++ standard library has an array-like container class named std::vector. It's not exactly the same as an array; for example, it uses dynamically-allocated memory, and can grow or shrink in size. The reason you might want to use it is that it allows you to perform plain assignment, and use other standard library facilities with it.
Thus Shadi's program becomes:
#include <iostream>
#include <vector>
void print_vector(const std::vector<int>& vec);
int main() {
std::vector<int> a { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::vector<int> b;
print_vector(a);
b = a;
print_vector(b);
}
void print_vector(const std::vector<int>& vec) {
// this next line uses syntax from the 2011 version of
// the C++ language standard ("C++11").
for(int x : vec) {
std::cout << x << " ";
}
std::cout << "\n\n";
}
You can also avoid the loop in print_vector entirely, using std::for_each or std::for_each_n, but that would require some knowledge of iterators and lambda functions, which may be a bit advanced for a beginner, so I won't go into that. But better yet, you could define a out-streaming operator for std::vector's, as seen here, with which you could write std::cout << a; and have that work.
I have a function which I want to take, as a parameter, a 2D array of variable size.
So far I have this:
void myFunction(double** myArray){
myArray[x][y] = 5;
etc...
}
And I have declared an array elsewhere in my code:
double anArray[10][10];
However, calling myFunction(anArray) gives me an error.
I do not want to copy the array when I pass it in. Any changes made in myFunction should alter the state of anArray. If I understand correctly, I only want to pass in as an argument a pointer to a 2D array. The function needs to accept arrays of different sizes also. So for example, [10][10] and [5][5]. How can I do this?
There are three ways to pass a 2D array to a function:
The parameter is a 2D array
int array[10][10];
void passFunc(int a[][10])
{
// ...
}
passFunc(array);
The parameter is an array containing pointers
int *array[10];
for(int i = 0; i < 10; i++)
array[i] = new int[10];
void passFunc(int *a[10]) //Array containing pointers
{
// ...
}
passFunc(array);
The parameter is a pointer to a pointer
int **array;
array = new int *[10];
for(int i = 0; i <10; i++)
array[i] = new int[10];
void passFunc(int **a)
{
// ...
}
passFunc(array);
Fixed Size
1. Pass by reference
template <size_t rows, size_t cols>
void process_2d_array_template(int (&array)[rows][cols])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
In C++ passing the array by reference without losing the dimension information is probably the safest, since one needn't worry about the caller passing an incorrect dimension (compiler flags when mismatching). However, this isn't possible with dynamic (freestore) arrays; it works for automatic (usually stack-living) arrays only i.e. the dimensionality should be known at compile time.
2. Pass by pointer
void process_2d_array_pointer(int (*array)[5][10])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < 5; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << (*array)[i][j] << '\t';
std::cout << std::endl;
}
}
The C equivalent of the previous method is passing the array by pointer. This should not be confused with passing by the array's decayed pointer type (3), which is the common, popular method, albeit less safe than this one but more flexible. Like (1), use this method when all the dimensions of the array is fixed and known at compile-time. Note that when calling the function the array's address should be passed process_2d_array_pointer(&a) and not the address of the first element by decay process_2d_array_pointer(a).
Variable Size
These are inherited from C but are less safe, the compiler has no way of checking, guaranteeing that the caller is passing the required dimensions. The function only banks on what the caller passes in as the dimension(s). These are more flexible than the above ones since arrays of different lengths can be passed to them invariably.
It is to be remembered that there's no such thing as passing an array directly to a function in C [while in C++ they can be passed as a reference (1)]; (2) is passing a pointer to the array and not the array itself. Always passing an array as-is becomes a pointer-copy operation which is facilitated by array's nature of decaying into a pointer.
3. Pass by (value) a pointer to the decayed type
// int array[][10] is just fancy notation for the same thing
void process_2d_array(int (*array)[10], size_t rows)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
Although int array[][10] is allowed, I'd not recommend it over the above syntax since the above syntax makes it clear that the identifier array is a single pointer to an array of 10 integers, while this syntax looks like it's a 2D array but is the same pointer to an array of 10 integers. Here we know the number of elements in a single row (i.e. the column size, 10 here) but the number of rows is unknown and hence to be passed as an argument. In this case there's some safety since the compiler can flag when a pointer to an array with second dimension not equal to 10 is passed. The first dimension is the varying part and can be omitted. See here for the rationale on why only the first dimension is allowed to be omitted.
4. Pass by pointer to a pointer
// int *array[10] is just fancy notation for the same thing
void process_pointer_2_pointer(int **array, size_t rows, size_t cols)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
Again there's an alternative syntax of int *array[10] which is the same as int **array. In this syntax the [10] is ignored as it decays into a pointer thereby becoming int **array. Perhaps it is just a cue to the caller that the passed array should have at least 10 columns, even then row count is required. In any case the compiler doesn't flag for any length/size violations (it only checks if the type passed is a pointer to pointer), hence requiring both row and column counts as parameter makes sense here.
Note: (4) is the least safest option since it hardly has any type check and the most inconvenient. One cannot legitimately pass a 2D array to this function; C-FAQ condemns the usual workaround of doing int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10); as it may potentially lead to undefined behaviour due to array flattening. The right way of passing an array in this method brings us to the inconvenient part i.e. we need an additional (surrogate) array of pointers with each of its element pointing to the respective row of the actual, to-be-passed array; this surrogate is then passed to the function (see below); all this for getting the same job done as the above methods which are more safer, cleaner and perhaps faster.
Here's a driver program to test the above functions:
#include <iostream>
// copy above functions here
int main()
{
int a[5][10] = { { } };
process_2d_array_template(a);
process_2d_array_pointer(&a); // <-- notice the unusual usage of addressof (&) operator on an array
process_2d_array(a, 5);
// works since a's first dimension decays into a pointer thereby becoming int (*)[10]
int *b[5]; // surrogate
for (size_t i = 0; i < 5; ++i)
{
b[i] = a[i];
}
// another popular way to define b: here the 2D arrays dims may be non-const, runtime var
// int **b = new int*[5];
// for (size_t i = 0; i < 5; ++i) b[i] = new int[10];
process_pointer_2_pointer(b, 5, 10);
// process_2d_array(b, 5);
// doesn't work since b's first dimension decays into a pointer thereby becoming int**
}
A modification to shengy's first suggestion, you can use templates to make the function accept a multi-dimensional array variable (instead of storing an array of pointers that have to be managed and deleted):
template <size_t size_x, size_t size_y>
void func(double (&arr)[size_x][size_y])
{
printf("%p\n", &arr);
}
int main()
{
double a1[10][10];
double a2[5][5];
printf("%p\n%p\n\n", &a1, &a2);
func(a1);
func(a2);
return 0;
}
The print statements are there to show that the arrays are getting passed by reference (by displaying the variables' addresses)
Surprised that no one mentioned this yet, but you can simply template on anything 2D supporting [][] semantics.
template <typename TwoD>
void myFunction(TwoD& myArray){
myArray[x][y] = 5;
etc...
}
// call with
double anArray[10][10];
myFunction(anArray);
It works with any 2D "array-like" datastructure, such as std::vector<std::vector<T>>, or a user defined type to maximize code reuse.
You can create a function template like this:
template<int R, int C>
void myFunction(double (&myArray)[R][C])
{
myArray[x][y] = 5;
etc...
}
Then you have both dimension sizes via R and C. A different function will be created for each array size, so if your function is large and you call it with a variety of different array sizes, this may be costly. You could use it as a wrapper over a function like this though:
void myFunction(double * arr, int R, int C)
{
arr[x * C + y] = 5;
etc...
}
It treats the array as one dimensional, and uses arithmetic to figure out the offsets of the indexes. In this case, you would define the template like this:
template<int C, int R>
void myFunction(double (&myArray)[R][C])
{
myFunction(*myArray, R, C);
}
anArray[10][10] is not a pointer to a pointer, it is a contiguous chunk of memory suitable for storing 100 values of type double, which compiler knows how to address because you specified the dimensions. You need to pass it to a function as an array. You can omit the size of the initial dimension, as follows:
void f(double p[][10]) {
}
However, this will not let you pass arrays with the last dimension other than ten.
The best solution in C++ is to use std::vector<std::vector<double> >: it is nearly as efficient, and significantly more convenient.
Here is a vector of vectors matrix example
#include <iostream>
#include <vector>
using namespace std;
typedef vector< vector<int> > Matrix;
void print(Matrix& m)
{
int M=m.size();
int N=m[0].size();
for(int i=0; i<M; i++) {
for(int j=0; j<N; j++)
cout << m[i][j] << " ";
cout << endl;
}
cout << endl;
}
int main()
{
Matrix m = { {1,2,3,4},
{5,6,7,8},
{9,1,2,3} };
print(m);
//To initialize a 3 x 4 matrix with 0:
Matrix n( 3,vector<int>(4,0));
print(n);
return 0;
}
output:
1 2 3 4
5 6 7 8
9 1 2 3
0 0 0 0
0 0 0 0
0 0 0 0
Single dimensional array decays to a pointer pointer pointing to the first element in the array. While a 2D array decays to a pointer pointing to first row. So, the function prototype should be -
void myFunction(double (*myArray) [10]);
I would prefer std::vector over raw arrays.
We can use several ways to pass a 2D array to a function:
Using single pointer we have to typecast the 2D array.
#include<bits/stdc++.h>
using namespace std;
void func(int *arr, int m, int n)
{
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
{
cout<<*((arr+i*n) + j)<<" ";
}
cout<<endl;
}
}
int main()
{
int m = 3, n = 3;
int arr[m][n] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
func((int *)arr, m, n);
return 0;
}
Using double pointer In this way, we also typecast the 2d array
#include<bits/stdc++.h>
using namespace std;
void func(int **arr, int row, int col)
{
for (int i=0; i<row; i++)
{
for(int j=0 ; j<col; j++)
{
cout<<arr[i][j]<<" ";
}
printf("\n");
}
}
int main()
{
int row, colum;
cin>>row>>colum;
int** arr = new int*[row];
for(int i=0; i<row; i++)
{
arr[i] = new int[colum];
}
for(int i=0; i<row; i++)
{
for(int j=0; j<colum; j++)
{
cin>>arr[i][j];
}
}
func(arr, row, colum);
return 0;
}
You can do something like this...
#include<iostream>
using namespace std;
//for changing values in 2D array
void myFunc(double *a,int rows,int cols){
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
*(a+ i*rows + j)+=10.0;
}
}
}
//for printing 2D array,similar to myFunc
void printArray(double *a,int rows,int cols){
cout<<"Printing your array...\n";
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
cout<<*(a+ i*rows + j)<<" ";
}
cout<<"\n";
}
}
int main(){
//declare and initialize your array
double a[2][2]={{1.5 , 2.5},{3.5 , 4.5}};
//the 1st argument is the address of the first row i.e
//the first 1D array
//the 2nd argument is the no of rows of your array
//the 3rd argument is the no of columns of your array
myFunc(a[0],2,2);
//same way as myFunc
printArray(a[0],2,2);
return 0;
}
Your output will be as follows...
11.5 12.5
13.5 14.5
One important thing for passing multidimensional arrays is:
First array dimension need not be specified.
Second(any any further)dimension must be specified.
1.When only second dimension is available globally (either as a macro or as a global constant)
const int N = 3;
void print(int arr[][N], int m)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < N; j++)
printf("%d ", arr[i][j]);
}
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
print(arr, 3);
return 0;
}
2.Using a single pointer:
In this method,we must typecast the 2D array when passing to function.
void print(int *arr, int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("%d ", *((arr+i*n) + j));
}
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int m = 3, n = 3;
// We can also use "print(&arr[0][0], m, n);"
print((int *)arr, m, n);
return 0;
}
#include <iostream>
/**
* Prints out the elements of a 2D array row by row.
*
* #param arr The 2D array whose elements will be printed.
*/
template <typename T, size_t rows, size_t cols>
void Print2DArray(T (&arr)[rows][cols]) {
std::cout << '\n';
for (size_t row = 0; row < rows; row++) {
for (size_t col = 0; col < cols; col++) {
std::cout << arr[row][col] << ' ';
}
std::cout << '\n';
}
}
int main()
{
int i[2][5] = { {0, 1, 2, 3, 4},
{5, 6, 7, 8, 9} };
char c[3][9] = { {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'},
{'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R'},
{'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '&'} };
std::string s[4][4] = { {"Amelia", "Edward", "Israel", "Maddox"},
{"Brandi", "Fabian", "Jordan", "Norman"},
{"Carmen", "George", "Kelvin", "Oliver"},
{"Deanna", "Harvey", "Ludwig", "Philip"} };
Print2DArray(i);
Print2DArray(c);
Print2DArray(s);
std::cout <<'\n';
}
In the case you want to pass a dynamic sized 2-d array to a function, using some pointers could work for you.
void func1(int *arr, int n, int m){
...
int i_j_the_element = arr[i * m + j]; // use the idiom of i * m + j for arr[i][j]
...
}
void func2(){
...
int arr[n][m];
...
func1(&(arr[0][0]), n, m);
}
You can use template facility in C++ to do this. I did something like this :
template<typename T, size_t col>
T process(T a[][col], size_t row) {
...
}
the problem with this approach is that for every value of col which you provide, the a new function definition is instantiated using the template.
so,
int some_mat[3][3], another_mat[4,5];
process(some_mat, 3);
process(another_mat, 4);
instantiates the template twice to produce 2 function definitions (one where col = 3 and one where col = 5).
If you want to pass int a[2][3] to void func(int** pp) you need auxiliary steps as follows.
int a[2][3];
int* p[2] = {a[0],a[1]};
int** pp = p;
func(pp);
As the first [2] can be implicitly specified, it can be simplified further as.
int a[][3];
int* p[] = {a[0],a[1]};
int** pp = p;
func(pp);
You are allowed to omit the leftmost dimension and so you end up with two options:
void f1(double a[][2][3]) { ... }
void f2(double (*a)[2][3]) { ... }
double a[1][2][3];
f1(a); // ok
f2(a); // ok
This is the same with pointers:
// compilation error: cannot convert ‘double (*)[2][3]’ to ‘double***’
// double ***p1 = a;
// compilation error: cannot convert ‘double (*)[2][3]’ to ‘double (**)[3]’
// double (**p2)[3] = a;
double (*p3)[2][3] = a; // ok
// compilation error: array of pointers != pointer to array
// double *p4[2][3] = a;
double (*p5)[3] = a[0]; // ok
double *p6 = a[0][1]; // ok
The decay of an N dimensional array to a pointer to N-1 dimensional array is allowed by C++ standard, since you can lose the leftmost dimension and still being able to correctly access array elements with N-1 dimension information.
Details in here
Though, arrays and pointers are not the same: an array can decay into a pointer, but a pointer doesn't carry state about the size/configuration of the data to which it points.
A char ** is a pointer to a memory block containing character pointers, which themselves point to memory blocks of characters. A char [][] is a single memory block which contains characters. This has an impact on how the compiler translate the code and how the final performance will be.
Source
Despite appearances, the data structure implied by double** is fundamentally incompatible with that of a fixed c-array (double[][]).
The problem is that both are popular (although) misguided ways to deal with arrays in C (or C++).
See https://www.fftw.org/fftw3_doc/Dynamic-Arrays-in-C_002dThe-Wrong-Way.html
If you can't control either part of the code you need a translation layer (called adapt here), as explained here: https://c-faq.com/aryptr/dynmuldimary.html
You need to generate an auxiliary array of pointers, pointing to each row of the c-array.
#include<algorithm>
#include<cassert>
#include<vector>
void myFunction(double** myArray) {
myArray[2][3] = 5;
}
template<std::size_t N, std::size_t M>
auto adapt(double(&Carr2D)[N][M]) {
std::array<double*, N> ret;
std::transform(
std::begin(Carr2D), std::end(Carr2D),
ret.begin(),
[](auto&& row) { return &row[0];}
);
return ret;
}
int main() {
double anArray[10][10];
myFunction( adapt(anArray).data() );
assert(anArray[2][3] == 5);
}
(see working code here: https://godbolt.org/z/7M7KPzbWY)
If it looks like a recipe for disaster is because it is, as I said the two data structures are fundamentally incompatible.
If you can control both ends of the code, these days, you are better off using a modern (or semimodern) array library, like Boost.MultiArray, Boost.uBLAS, Eigen or Multi.
If the arrays are going to be small, you have "tiny" arrays libraries, for example inside Eigen or if you can't afford any dependency you might try simply with std::array<std::array<double, N>, M>.
With Multi, you can simply do this:
#include<multi/array.hpp>
#include<cassert>
namespace multi = boost::multi;
template<class Array2D>
void myFunction(Array2D&& myArray) {
myArray[2][3] = 5;
}
int main() {
multi::array<double, 2> anArray({10, 10});
myFunction(anArray);
assert(anArray[2][3] == 5);
}
(working code: https://godbolt.org/z/7M7KPzbWY)
You could take arrays of an arbitrary number of dimensions by reference and peel off one layer at a time recursively.
Here's an example of a print function for demonstrational purposes:
#include <cstddef>
#include <iostream>
#include <iterator>
#include <string>
#include <type_traits>
template <class T, std::size_t N>
void print(const T (&arr)[N], unsigned indent = 0) {
if constexpr (std::rank_v<T> == 0) {
// inner layer - print the values:
std::cout << std::string(indent, ' ') << '{';
auto it = std::begin(arr);
std::cout << *it;
for (++it; it != std::end(arr); ++it) {
std::cout << ", " << *it;
}
std::cout << '}';
} else {
// still more layers to peel off:
std::cout << std::string(indent, ' ') << "{\n";
auto it = std::begin(arr);
print(*it, indent + 1);
for (++it; it != std::end(arr); ++it) {
std::cout << ",\n";
print(*it, indent + 1);
}
std::cout << '\n' << std::string(indent, ' ') << '}';
}
}
Here's a usage example with a 3 dimensional array:
int main() {
int array[2][3][5]
{
{
{1, 2, 9, -5, 3},
{6, 7, 8, -45, -7},
{11, 12, 13, 14, 25}
},
{
{4, 5, 0, 33, 34},
{8, 9, 99, 54, 44},
{14, 15, 16, 19, 20}
}
};
print(array);
}
... which will produce this output:
{
{
{1, 2, 9, -5, 3},
{6, 7, 8, -45, -7},
{11, 12, 13, 14, 25}
},
{
{4, 5, 0, 33, 34},
{8, 9, 99, 54, 44},
{14, 15, 16, 19, 20}
}
}
I'm playing around with arrays in C++. I defined a 2d array called matrix and am going to extract the negative values and assign it to the array called array.
Is there a way to initialize an array to zero quickly rather than enumerating all the elements? I looked through other postings and lines such as: int array[10] = {} or
int array[10] = {0} do not work on my compiler. I get the error message error: variable-sized object ‘array’ may not be initialized if I try using those statements.
My text book said that all arrays are initialized to zero when declared, but I tested this on my compiler and this was not true; I had to force it to zero by using a for-loop. Is there a correct way of doing this?
Oh by the way, I have a mac and use g++ to compile. When I do man g++ it says its a symbolic link to llvm-gcc compiler.
#include<iostream>
const int NROWS = 4, NCOLS = 5;
int matrix[][NCOLS] = { 16, 22, 99, 4, 18,
-258, 4, 101, 5, 98,
105, 6, 15, 2, 45,
33, 88, 72, 16, 3};
int main()
{
int SIZE = 10;
int array[SIZE];
int count=0;
// Values of array before initalized
for(int i = 0; i < SIZE; i++)
{
std::cout << array[i] << " ";
}
std::cout << std::endl;
//Initialize array to zero
for(int i = 0; i < SIZE; i++)
{
array[i]=0;
std::cout << array[i] << " ";
}
std::cout << std::endl;
// Extract negative numbers and assign to array
for(int i = 0; i < NROWS; i++)
{
for(int j = 0; j < NCOLS; j++)
{
printf("matrix[%i,%i]=%5i\n",i,j,matrix[i][j]);
if(matrix[i][j] < 0)
{
array[count] = matrix[i][j];
printf("\tarray[%d]= %4d",count, matrix[i][j]);
printf("\tcount=%d\n", count);
count++;
}
}
}
// Values of array
for(int i = 0; i < SIZE; i++)
{
std::cout << array[i] << " ";
}
std::cout << std::endl;
return 0;
}
I'm taking a guess here.
int array[10] = {0};
is perfectly legal and should work on any compiler, but I think you tried
int SIZE = 10;
int array[SIZE] = {0};
which is entirely different, and not legal. Array bounds must be constants, not variables.
Some compilers accept variable bounds, but that doesn't make it legal.
Change int SIZE = 10; to const int SIZE=10; or enum{SIZE=10};, and your {} based initialization should work.
You have accidentally used a gcc extension allowing for variable sized arrays.
What you need to do is up at the top where you have:
int array[SIZE];
replace it with:
int array[SIZE] = {};
if you were trying to do:
array[SIZE] = {};
later on, it wouldn't work the same.
in that case, it would fail (accessing [10] when there's only [0]-[9]).
You could also use a static array.
See:
How to initialize all members of an array to the same value?
Or if you want to use the STL Array type,, you can look at:
http://www.cplusplus.com/reference/array/array/?kw=array
you might even need to just make the SIZE var const.
This should work, and will zero-initialize the 9 remaining elements.
int array[10] = {0};
See: Array initialization in C++
If array size is variable-dependent you must: loop through or
int array[x];
memset(array, 0, x);
If array size is hardcoded you can:
int array[10] = {0};