passing in int* for int[][] C/C++ - c++

Suppose I have the following code
#include <stdio.h>
#include <stdlib.h>
int foo(int bar[3][3]){
return bar[1][1];
}
int main(){
int* bar = (int*) malloc(9 * sizeof(int));
for(int i = 0; i < 9; i++){
bar[i] = i;
}
int test = foo(bar);
printf("%d\n", test);
}
Compiling this with C gives a warning
warning: incompatible pointer types passing 'int *' to parameter of type 'int (*)[3]' [-Wincompatible-pointer-types]
int test = foo(bar);
But still outputs the expected result of 4 (Although I imagine the warning is a sign of UB)
Compiling with g++ gives an error
error: no matching function for call to 'foo'
int test = foo(bar);
note: candidate function not viable: no known conversion from 'int *' to 'int (*)[3]' for 1st argument
int foo(int bar[3][3]){
I cannot change the function signature of bar but would like to just pass in a simple pointer to the array. What is the simplest typecast/change of code that would make this compile with no UB with g++. This is for code that I am generating with a Python script while looking at the function signature of bar so the simpler the solution the better. (This is just an example)

Quick and dirty fix:
foo(reinterpret_cast<int(*)[3]>(bar)); // C++ only
foo((int(*)[3])bar); // C and C++
Replaces the implicit cast present in C language with an explicit one to let the C++ compiler know you are intending to circumvent the type-system.

Without dynamic memory allocation:
int main(void) {
int bar[3][3];
for (int i=0; i<9; ++i) {
bar[i / 3][i % 3] = i;
}
printf("%d\n", foo(bar));
}
With: (C)
int main(void) {
int (*bar)[3] = malloc(3 * sizeof(int[3]));
for (int i=0; i<9; ++i) {
bar[i / 3][i % 3] = i;
}
printf("%d\n", foo(bar));
}

What is the simplest typecast/change of code that would make this compile with no UB with g++
int main(){
int bar[3][3];
for(int i = 0; i < 9; i++){
bar[i / 3][i % 3] = i;
}
int test = foo(bar);
printf("%d\n", test);
}
Works in both C++ and C

Related

Problem with c++ function - error: incompatible types in assignment of ‘int’ to ‘int [n]’

i want to make function in c++ called 'losowanie', this function should random n numbers between 0-n. When i call this function, then i get :
error: incompatible types in assignment of ‘int’ to ‘int [n]’
Here is my code :
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int losowanie (int tab[], int n) {
for(int i = 0;i<n; i++) {
tab[i] = rand() % n + 1;
cout<<tab[i]<<endl;
}
}
int main()
{
int n = -1;
while(n<0 || n>50) {
cout<<"Give number ( 0 - 50)"<<endl;
cin>>n;
}
int tab[n];
tab = losowanie(tab, n); //here is error
return true;
}
For starters variable length arrays like this
int tab[n];
is not a standard C++ feature. Instead use the standard container std::vector.
This while loop
while(n<0 || n>50) {
allows to enter the value 0 for the variable n. However you may not declare a variable length array with 0 elements.
The function losowanie
int losowanie (int tab[], int n) {
for(int i = 0;i<n; i++) {
tab[i] = rand() % n + 1;
cout<<tab[i]<<endl;
}
}
has the return type int but returns nothing.
In this assignment statement
tab = losowanie(tab, n);
the left operand has the type int[n] while the return type of the function int. So the compiler issues an error because this statement does not make a sense. Arrays do not have the assignment operator.
You could change the type of the function from int to void and remove the assignment statement.
Also you should use the standard C function srand to get different sequences of random numbers.
losowanie returns int, but tab is an array.
It is enough to make losowanie to a void function.
void losowanie (int tab[], int n) {
for(int i = 0;i<n; i++) {
tab[i] = rand() % n + 1;
cout<<tab[i]<<endl;
}
And, in main:
int tab[n];
losowanie(tab, n);

C output differ with the same code

#include <stdio.h>
#include <stdlib.h>
int main() {
int* a[10];
int* p = a;
int i = 0;
for (p = &a[0], i = 0; p < &a[10]; p++, i++)
{
*p = i;
}
for (int i = 0; i < 10; i++)
{
printf("%d\n", a[i]);
}
}
the output on GCC using eclipse:
0
2
4
6
8
10
12
14
16
18
the output using visual studio:
0
1
2
3
4
5
6
7
8
9
why ?
% gcc error.c -Wall -Wextra
error.c: In function ‘main’:
error.c:7:14: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
int* p = a;
^
error.c:9:12: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
for (p = &a[0], i = 0; p < &a[10]; p++, i++)
^
error.c:9:30: warning: comparison of distinct pointer types lacks a cast
for (p = &a[0], i = 0; p < &a[10]; p++, i++)
^
error.c:15:18: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d\n", a[i]);
^
Hint:
int a[10]; // notice the lack of star here.
a is declared as an array of 10 pointers to int. a in int* p = a; will decay to int **, but p is of type int *. Compiler will raise a warning about incompatible pointer assignment. You need to change the declaration
int* a[10];
to
int a[10];
This program invokes undefined behavior, so strange things can happen.

How to pass a dynamic 2-D array to a function in C++

I am trying to pass a dynamic 2-D array to a function and it gives an error. I tried explicitly providing the array dimensions and it worked but dynamic is not working, any pointers (pun not intended)
#include <iostream>
#include <vector>
using namespace std;
void print_2d_array(int arr_size, int (*arr)[5]){
for(int i = 0; i < arr_size; ++i){
for(int j = 0; j < arr_size; ++j)
cout << arr[i][j] << "\t";
cout << endl;
}
}
int main(){
vector<int> x{10,15,20,30,40};
int arr[x.size()][x.size()];
for(int i = 0; i < x.size(); ++i)
arr[i][i] = 0;
print_2d_array(5, arr);
return 0;
}
I tried all the three methods that were detailed here Passing 2D array in C
If instead of instantiating the array as shown above, I use something like
arr[5][5];
it works as expected. I am getting the following error
error: cannot convert ‘int (*)[(<anonymous> + 1)]’ to ‘int (*)[5]’ for argument ‘2’
to ‘void print_2d_array(int, int (*)[5])’
print_2d_array(5, arr);
Variable Length Array (VLA) is not part of C++ standard. It is part of C99 standard, and typically implemented as an extension for C++ in various compilers.
It is typically ok to use a VLA in a C++ program when you allocates an array. But you are going to have problems when you need to pass the array around, because there is no argument type that is VLA so that you can pass it as arguments to functions in C++. (That's why when you manually inline the function, the code runs ok, which avoids passing the array into a function.) You have to pass the array as a pointer to the function, and maybe use reinterpret_cast before and inside the function to convert the VLA to a pointer, and convert it back. It is simply terrible code.
When coding in C++, just use the C++ idiomatic way. Since you already use vector, you can just use vector<vector<int>> (vector<vector<int> > if not using C++11, but from the way you initialize x, you are using C++11) as a 2-D array. Your code should be modified as below:
#include <iostream>
#include <vector>
using namespace std;
void print_2d_array(int arr_size, vector<vector<int>> &arr){
for(int i = 0; i < arr_size; ++i){
for(int j = 0; j < arr_size; ++j)
cout << arr[i][j] << "\t";
cout << endl;
}
}
int main(){
vector<int> x{10,15,20,30,40};
vector<vector<int>> arr(x.size(), vector<int>(x.size()));
// No need to use this to initialize:
// for(int i = 0; i < sizeof(x); ++i)
// arr[i][i] = 0;
print_2d_array(5, arr);
return 0;
}
Note that this also fixed your problem that your arr was not properly initialized.
If you are going to use C, then VLA is totally ok, and it will be like this (and not that I didn't fix your initialization, which only initialized the diagonal elements. You have to use a C, not C++ compiler to compile this.):
#include <stdio.h>
void print_2d_array(int arr_size, int arr[][arr_size]){
for(int i = 0; i < arr_size; ++i){
for(int j = 0; j < arr_size; ++j)
printf("%d\t", arr[i][j]);
printf("\n");
}
}
int main(){
int x[] = {10,15,20,30,40};
int arr[sizeof(x)][sizeof(x)];
// bad initialization:
for(int i = 0; i < sizeof(x); ++i)
arr[i][i] = 0;
print_2d_array(5, arr);
return 0;
}
Ok, if you decide to use C++ but don't like vector, the next simplest thing is to use primitive pointers, which is not recommended.
#include <iostream>
#include <vector>
using namespace std;
void print_2d_array(int arr_size, int **arr){
for(int i = 0; i < arr_size; ++i){
for(int j = 0; j < arr_size; ++j)
cout << arr[i][j] << "\t";
cout << endl;
}
}
int main(){
vector<int> x {10,15,20,30,40};
int **arr = new int*[x.size()];
for (int i = 0; i < x.size(); ++i) {
arr[i] = new int[x.size()];
for (int j = 0; j < x.size(); ++j) {
arr[i][j] = 0;
}
}
print_2d_array(5, arr);
for (int i = 0; i < x.size(); ++i) {
delete[] arr[i];
}
return 0;
}
Save your trouble and use containers. You are using modern C++.
(The answer assumes you couldn't determine the size of the array before running. Although this is not the case in your example--the size must be 5 and there is no reason to use VLA.)
First of all,
int arr[x.size()][x.size()];
is not valid C++. The dimensions of array must be known at compile time.
If you use a compiler that supports variable length arrays as an extension, you can use that statement. But then, the type of the variable is not int (*)[5], which is what is expected by print_2d_array.
You can use a nested std::array if you know the dimensions at compile time.
You can use a nested std::vector if need to compute the dimensions at run time.
Update, in response to OP's comment
Take a simplified version of the program.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> x{10,15,20,30,40};
int arr[x.size()][x.size()];
return 0;
}
Command to compile:
g++ -Wall -std=c++11 socc.cc -o socc -pedantic
Errors/warnings:
socc.cc: In function ‘int main()’:
socc.cc:8:31: warning: ISO C++ forbids variable length array ‘arr’ [-Wvla]
int arr[x.size()][x.size()];
^
socc.cc:8:31: warning: ISO C++ forbids variable length array ‘arr’ [-Wvla]
socc.cc:8:9: warning: unused variable ‘arr’ [-Wunused-variable]
int arr[x.size()][x.size()

Issue with variable as dimension to 2-D array in C++

Following code runs fine -
void func(int m[][2])
{
cout<<(m[0][0])<<endl;
}
int main()
{
// int x=2;
int m[2][2];
m[0][0] = m[0][1] = m[1][0] = m[1][1] = 5;
cout<<m[0][0]<<endl;
func(m);
}
But when I change main() as follows -
int main()
{
int x=2;
int m[x][x];
m[0][0] = m[0][1] = m[1][0] = m[1][1] = 5;
cout<<m[0][0]<<endl;
func(m);
}
I get the error message -
try.cpp:16:11: error: cannot convert ‘int (*)[(((long unsigned int)(((long int)x) + -0x00000000000000001)) + 1)]’ to ‘int (*)[2]’ for argument ‘1’ to ‘void func(int (*)[2])’
Also, the following runs fine -
int main()
{
int x=2;
int m[x][x];
m[0][0] = m[0][1] = m[1][0] = m[1][1] = 5;
cout<<m[0][0]<<endl;
//func(m);
}
Can anyone explain the issue here? Thanks.
Variable length arrays are not valid in C++. g++ allows this as an "extension".
int x=2;
int m[x][x]; //Illegal in C++
You should go for Dynamic Memory allocation if you want to dynamically allocate memory to an array.
int x=2;
int *m = new int[x];
It is better if you use STL :
int x = 10;
std::vector<int> m(n);
Or you can use const not a variable when creating it.
const int x=2; //it's a compile time constant
int m[x][x];

Help with type conversion error

When I try to compile my program, I get the following error:
main.cpp: In function ‘int main()’:
main.cpp:67: error: cannot convert ‘int (*)[(((long unsigned int)(((long int)mapSizeY) - 1)) + 1u)]’ to ‘int (*)[10]’ for argument ‘3’ to ‘void initializeMap(int, int, int (*)[10])’
main.cpp:68: error: cannot convert ‘int (*)[(((long unsigned int)(((long int)mapSizeY) - 1)) + 1u)]’ to ‘int (*)[10]’ for argument ‘3’ to ‘void paintMap(int, int, int (*)[10])’
My code looks like this:
#include <iostream>
using namespace std;
void initializeMap(int mapSizeX, int mapSizeY, int map[][10])
{
// Map details:
// 0 = # (wall)
// 1 = space (free space)
// 2 = x (player)
for(int x = 0; x < mapSizeX; x++)
{
map[x][0] = 0;
}
for(int y = 0; y < (mapSizeY - 2); y++)
{
map[0][y] = 0;
for(int x = 0; x < (mapSizeX - 2); x++)
{
map[x][y] = 1;
}
map[mapSizeX][y] = 0;
}
for(int x = 0; x < mapSizeX; x++)
{
map[x][mapSizeY - 1] = 0;
}
}
void paintMap(int mapSizeX, int mapSizeY, int map[][10])
{
for(int y = 0; y < mapSizeY; y++)
{
for(int x = 0; x < mapSizeX; x++)
{
switch(map[x][y])
{
case 0:
cout << "#";
break;
case 1:
cout << " ";
break;
case 2:
cout << "x";
break;
}
cout << map[x][y];
}
cout << endl;
}
}
int main()
{
int mapSizeX = 10;
int mapSizeY = 10;
int map[mapSizeX][mapSizeY];
initializeMap(mapSizeX, mapSizeY, map);
paintMap(mapSizeX, mapSizeY, map);
cout << endl << endl;
return 0;
}
I've spent an hour trying to solve the issue and about twenty minutes searching for a solution. Can any of you help me out?
C++ does not support variable-length arrays, which is what map is in your code. However, some compilers may support it as a non-standard extension. However, it certainly won't be compatible with a function expecting a "standard" array.
If you make mapSizeX and mapSizeY constants, this should work.
Declare mapSizeX and mapSizeY const. Your current code, as is, is basically not wellformed according the C++ language specification which allows only constants as array size specifiers.
The error message is utterly misleading, that's due to the fact that some compiler support this as an extension and the latest C language standard includes it as well.
I tested it here.
Your function calls expect the second dimension to be exactly 10, always. Your code has that dimension in a variable (mapSizeY), which is not guaranteed to be 10, even though you set it a line earlier.
Change mapSizeY to const int so the compiler can optimize it away.
If you make mapSize[X|Y] const in the main method, this should work. Alternatively, as you're passing the dimensions to each of your methods, why not pass the matrix as an int**?
The problem is the variable-length automatic array. One way to fix this is to make the item look the same in main() as it does in initializeMap() and paintMap().
int main()
{
int mapSizeX = 10;
// int mapSizeY = 10;
int map[mapSizeX][10];
initializeMap(mapSizeX, 10, map);
paintMap(mapSizeX, 10, map);
cout << endl << endl;
return 0;
}
One thing I don't suggest is simply declaring MapSize? to be const. Then it looks like the array is variable-length when it really isn't.
You should also be aware that variable-length automatic arrays are a GNU extension to C89 and C++.
Change the definition map[][10] to map[][] or *map in the initializeMap an paintMap functions.