I am writing a program that passes a 2D char array into a function for printing. However, when I try to access elements in the 2D array for printing, I can't. This problem does not occur when I place the printing loops and statements in the main() function, only if the array is passed.
Can someone help explain?
void disp_array(char* array)
{
for (int i = 0; i < SIZE; i++)
{
for (int j = 0; j < SIZE; j++)
{
printf("%c", array[i][j]);
}
printf("\n");
}
}
Attached is my code: the j in the printf statement is highlighted with an error:
E0142: "expression must have pointer-to-object type but it has type
int"
The function declaration is wrong.
As the parameter has the type char * then the expressions array[i] yields a scalar object of the type char that is promoted to the type int due to the integer promotions to which you may not apply the subscript operator as you are trying to do array[i][j]. So the compiler issues the error message
E0142: "expression must have pointer-to-object type but it has type
int"
The function should be declared like
void disp_array(char array[][SIZE], int n )
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < SIZE; j++)
{
printf("%c", array[i][j]);
}
printf("\n");
}
}
or like
void disp_array(char (*array)[SIZE], int n )
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < SIZE; j++)
{
printf("%c", array[i][j]);
}
printf("\n");
}
}
The parameter having the array type char[SIZE][SIZE] is implicitly adjusted by the compiler to the type char ( * )[SIZE]. That is the function does not know how many elements of the type char ( * )[SIZE] exist. So you need to specify the number of elements explicitly. Try always to define a more general function.
And along with the array you need to pass the number of rows in the array. For example
disp_array( array, SIZE );
If the array contains strings then the function definition will look like
void disp_array(char (*array)[SIZE], int n )
{
for (int i = 0; i < n; i++)
{
puts( array[i] );
}
}
Related
This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 13 days ago.
I wrote this program that is supposed to sort NxN array. It gets compiled but doesn't work because the pointer type is incompatible.
I just need help with the pointers as argument. I get incompatible pointer type warning for both functions swap and dblArraySort. Any idea why is that ?
thanks in advance !
#include <stdio.h>
#include <stdlib.h>
void
swap(int **a, int **b)
{
int temp;
temp = **a;
**a = **b;
**b = temp;
}
void
dblArraySort(int **dblArray, int arrLen)
{
int chkIndex;
int i, j, k;
for (i = 0; i < arrLen; i++) {
if ((i + 1) % 2 == 0) {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex < dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
} else {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex >= dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
}
}
}
int
main()
{
unsigned int arrayLength;
printf("Provide array size: \n");
scanf("%d", &arrayLength);
int doubleArray[arrayLength][arrayLength];
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
scanf("%d", &doubleArray[i][j]);
}
}
dblArraySort(doubleArray, arrayLength);
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
printf("%d ", doubleArray[i][j]);
}
printf("\n");
}
return 0;
}
I tried the code mentioned above
Arrays in C can be confusing. The thing you need to worry about is element type.
The element type of int ** dblArray is int *. In other words, dblArray is an array of int *s.
However, the element type of int doubleArray[arrayLength][arrayLength] is int row_type[arrayLength]. That is not an int *, that is an array, which is a totally different thing.
Moreover, when you use an array⟶pointer conversion, as happens when you say:
dblArraySort(doubleArray, arrayLength); // doubleArray is converted to a pointer
You get a pointer to the array, which in this case is a pointer to the innermost element type, an int — which is also not an int *.
tl;dr: You are trying to pass an array of array of int to a function taking an array of pointer to int. That won’t work.
I would like to comment on your variable naming as well. When you say “double” or “dbl”, as in doubleArray and dblArray the very first thing people will think is that you are handling a linear array of type double, which is also not what the array is.
You have there a two-dimensional array. Not a “double” array. Common naming for such thing would be array2D or matrix.
To make it work you need either C11, which allows you to pass a VLA as:
void sort_array2D( size_t rows, size_t columns, int array[rows][columns] )
{
...
int value = array[i][j];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( Array_Length, Array_Length, array2D );
Or you need to simply assume you must compute the index manually. A little function will help:
size_t index2D( size_t rows, size_t columns, size_t r, size_t c )
{
(void)rows; // (quiet the compiler about not using this argument)
return r * columns + c;
}
Then you can write your function as:
void sort_array2D( int * array, size_t rows, size_t columns )
{
...
int value = array[index2D( rows, columns, i, j )];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( (int *)array2D, Array_Length, Array_Length );
I haven’t bothered to analyze your sort function. It doesn’t look right to me, but honestly, I’ve barely glanced at it. Calling a value from the array chkIndex looks fishy, since the values of the array are not indices per se, at least not in the context of sorting them.
Remember, when messing with arrays in C you need to keep strict care to not mix up the type of the elements. (Or the types of things in general, whether syntactic or conceptual.)
I am trying to create a subtract function using pointers for 2d array but when I run it I get
expression must have pointer-to-object type but it has type "int"C/C++(142)
Can anybody explain why i'm getting this error and what is a better way around this?
this is my code
Function to read array
int *readMatrix(int *arr)
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
printf("row %d, col %d: ", i + 1, j + 1);
scanf("%d", &arr[i * 4 + j]);
}
}
printf("\n");
return arr;
}
Function to subtract 2 2d arrays
int *subM(int *arrA, int*arrB, int *arrC){
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
//printf("row %d, col %d: ", i + 1, j + 1);
&arrC[i][j] = &arrA[i][j] - &arrB[i][j]; //code where I am getting error
}
}
return arrC;
}
Main Function
int main()
{
int arrA[3][4];
int arrB[3][4];
int arrC[3][4];
readMatrix(&arrA[3][4]);
readMatrix(&arrB[3][4]);
subM(&arrA[3][4],&arrB[3][4],&arrC[3][4]);
return 0;
}
I am new to StackOverflow. I'm sorry if I can't express myself that well, but I think I found the solution to your problem.
Let's look at this step-by-step.
When passing an array to a function, you do not need to write the subscripts.
That means that instead of this:
readMatrix(&arrA[3][4]);
Just write this:
readMatrix(arrA);
You can (actually, should) also remove the pointer operator (&) because when only the array name is used, it acts as a pointer automatically.
Let's now take a look at the definition of readMatrix.
int *readMatrix(int *arr)
Using pointers for multi-dimensional arrays is okay, but the compiler would spit out a lot of warnings.
The most standard way is using subscripts in the definition of the function:
int *readMatrixStandard(int arr[3][4])
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
printf("row %d, col %d: ", i + 1, j + 1);
scanf("%d", &arr[i][j]);
}
}
printf("\n");
return arr;
}
The subscripts in subM
For your case, there are two ways to access a multi-dimensional array.
Either tell the compiler that this function takes an multi-dimensional array:
Instead of this:
int *subM(int *arrA, int*arrB, int *arrC)...
Do this:
int *subM(int arrA[3][4], int arrB[3][4], int arrC[3][4])...
The code would then look something like this:
int *subMMultiDimension(int arrA[3][4], int arrB[3][4], int arrC[3][4]){
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
//printf("row %d, col %d: ", i + 1, j + 1);
arrC[i][j] = arrA[i][j] - arrB[i][j]; //code where I am getting error
printf("%5d", arrC[i][j]);
}
puts(""); // for newline
}
return arrC;
}
Or use some pointer magic that is exclusive to C/C++ :) (not to be combined with the solution above)
Instead of this:
int *subM(int *arrA, int*arrB, int *arrC){
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
//printf("row %d, col %d: ", i + 1, j + 1);
&arrC[i][j] = &arrA[i][j] - &arrB[i][j]; //code where I am getting error
}
}
return arrC;
}
Try this:
int *subM(int *arrA, int *arrB, int *arrC){
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
//printf("row %d, col %d: ", i + 1, j + 1);
arrC[i * 4 + j] = arrA[i * 4 + j] - arrB[i * 4 + j]; //code where I am getting error
}
}
return arrC;
}
Use one of the ways, but the first one seems to be more standard because the compiler doesn't throw warnings on the first one.
Return value
You probably see where this is going. I'm just slapping on the code now.
Instead of:
return arr;
return arrC;
I prefer this for less warnings:
return arr[0];
return arrC[0];
The reason is simple. It points pratically to the same address, but it lets the compiler keep the mouth shut.
I think that this was it. The final code would look like this:
#include <stdio.h>
int * readMatrixStandard(int arr[3][4])
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
printf("row %d, col %d: ", i + 1, j + 1);
scanf("%d", &arr[i][j]);
}
}
printf("\n");
return arr[0];
}
int * subMMultiDimension(int arrA[3][4], int arrB[3][4], int arrC[3][4])
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
//printf("row %d, col %d: ", i + 1, j + 1);
arrC[i][j] = arrA[i][j] - arrB[i][j]; //code where I am getting error
printf("%5d", arrC[i][j]);
}
puts(""); // for newline
}
return arrC[0];
}
int main(void) // I recommend to always write void here if you are not using
// an old compiler
{
int arrA[3][4];
int arrB[3][4];
int arrC[3][4];
readMatrixStandard(arrA);
readMatrixStandard(arrB);
subMMultiDimension(arrA,arrB,arrC);
return 0;
}
Compiles nicely without warnings.
These code snippets are just my recommendations. If you want to know the most standard way to do something in C, you will probably have to look it up. A good book is also recommended. For instance, I learnt C with C Primer Plus by Stephen Prata. A great book with a lot of examples and illustrations to help you understand the situation.
Sorry again for my English. Guess there is still a long way to go.
If I missed anything or made a mistake somewhere, please let me know.
Edit: It's Stephen Prata, not Stephan ;)
By definition of the subscript operator [], the expression
A[B]
is equivalent to:
*(A + B)
Therefore,
A[B][C]
is equivalent to:
*( *(A+B) + C )
If you apply this to the line
&arrC[i][j] = &arrA[i][j] - &arrB[i][j];
it is equivalent to:
&*( *(arrC+i) + j ) = &*( *(arrA+i) + j ) - &*( *(arrB+i) + j );
The expression
&*( *(arrC+i) + j ) )
is invalid, for the following reason:
The sub-expression
*(arrC+i)
has type int, because dereferencing an int * yields an int. Therefore, the sub-expression
*(arrC+i) + j
will also evaluate to an int.
After evaluation that sub-expression, you then attempt to dereference that int using the * operator, which is illegal. Only pointer types can be dereferenced.
The sub-expressions
*( *(arrA+i) + j )
and
*( *(arrB+i) + j )
have exactly the same problem. You are also dereferencing an int in both of these expressions.
The actual problem is that you declared the function subM with the following parameters:
int *subM(int *arrA, int *arrB, int *arrC)
In C, arrays are usually passed to functions by passing a (possibly decayed) pointer to the first element of the (outer) array.
The parameter type int * would therefore be correct if you were passing 1D arrays to the function, but it is incorrect for 2D arrays. This is because a pointer to the first element of the outer array of a 2D int array has the type int (*)[4] in your case, i.e. a pointer to a 1D array of 4 int elements. However, you are instead passing a pointer to a single int object (not an array), so you are passing the wrong type of pointer.
Therefore, you should change the parameter types to the following:
int *subM( int (*arrA)[4], int (*arrB)[4], int (*arrC)[4] )
It may be clearer to write this the following way:
int *subM( int arrA[3][4], int arrB[3][4], int arrC[3][4] )
Both lines are equivalent, because arrays decay to pointers when used as function parameters.
Also, you should change the way you are calling the function. You should change the line
subM(&arrA[3][4],&arrB[3][4],&arrC[3][4]);
to:
subM( arrA[3], arrB[3], arrC[3] );
Due to array to pointer decay, this line is equivalent to:
subM( &arrA[3][0], &arrB[3][0], &arrC[3][0] );
Several issues ...
readMatrix uses an int *arr arg [correctly]. But, we want this to be compatible with sumM
sumM uses int * args, but tries to use dereference them using 2D array syntax.
In sumM, using (e.g.) &arr[i][j] is the address of the element and not its value [which is what we want].
In main, we're passing (e.g.) &arr[3][4]. This points past the end of the array, so this is UB (undefined behavior). We want to pass the start address of the array (e.g. arr or &arr[0][0]).
No need to pass back pointers to the resultant arrays because the caller passes in the addresses as args.
Here is the refactored code. It is annotated:
#include <stdio.h>
// Function to read array
#if 0
int *
readMatrix(int *arr)
#else
void
readMatrix(int arr[3][4])
#endif
{
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
printf("row %d, col %d: ", i + 1, j + 1);
#if 0
scanf("%d", &arr[i * 4 + j]);
#else
scanf("%d", &arr[i][j]);
#endif
}
}
printf("\n");
#if 0
return arr;
#endif
}
// Function to subtract 2 2d arrays
#if 0
int *
subM(int *arrA, int *arrB, int *arrC)
#else
void
subM(int arrA[3][4], int arrB[3][4], int arrC[3][4])
#endif
{
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
// printf("row %d, col %d: ", i + 1, j + 1);
// NOTE/BUG: we want to use the _values_ and _not_ the _addresses_ of the
// array elements
#if 0
&arrC[i][j] = &arrA[i][j] - &arrB[i][j];
#else
arrC[i][j] = arrA[i][j] - arrB[i][j];
#endif
}
}
// NOTE/BUG: since caller passed in the array, it knows where it is
#if 0
return arrC;
#endif
}
// Main Function
int
main(void)
{
int arrA[3][4];
int arrB[3][4];
int arrC[3][4];
// NOTE/BUG: doing (e.g.) &arrA[3][4] points past the _end_ of the 2D array
// and, so, is UB (undefined behavior) -- we want to pass the start address
#if 0
readMatrix(&arrA[3][4]);
readMatrix(&arrB[3][4]);
subM(&arrA[3][4], &arrB[3][4], &arrC[3][4]);
#else
readMatrix(arrA);
readMatrix(arrB);
subM(arrA, arrB, arrC);
#endif
return 0;
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
I just started to tinker with pointers in multidimensional arrays and was trying to pass and array into a void function. The compilator just threw an error. I need the array to be passed exactly as a pointer to maybe change it then by reference.
#include <stdio.h>
#include <stdlib.h>
void Func(int** matrix, int sizeFirst, int sizeSecond)
{
for (int i = 0; i < sizeFirst; i++)
{
for (int j = 0; j < sizeSecond; j++)
{
printf("%d\n", matrix[i][j]);
}
}
}
int main()
{
int array[2][3] = {
{5,8,2},
{1,3,6}
};
int sizeMain = sizeof(array)/sizeof(array[0]);
int sizeInner = sizeof(array[0])/sizeof(array[0][0]);
Func(array, sizeMain, sizeInner);
return 0;
}
2D array is not pointer to pointer. Your code is invalid as Func does not know how many columns every row has. Also, use the correct type for sizes & indexes
void Func(size_t sizeFirst, size_t sizeSecond, int (*matrix)[sizeSecond])
{
for (int i = 0; i < sizeFirst; i++)
{
for (int j = 0; j < sizeSecond; j++)
{
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
int main()
{
int array[2][3] = {
{5,8,2},
{1,3,6}
};
size_t sizeMain = sizeof(array)/sizeof(array[0]);
size_t sizeInner = sizeof(array[0])/sizeof(array[0][0]);
Func(sizeMain, sizeInner, array);
return 0;
}
https://godbolt.org/z/Ejfrdd3nK
With pointers to VLAs, you can preserve all of the dimensions in the type of the argument and then let C do the multidimensional scaling for you.
In older versions of C you need to calculate the spot manually, remembering that
the first dimension from the right moves by 1 (scaled by sizeof(type), which C does for you), the second by first dimension from the right,
the third by first dimension from the right multiplied by second dimension from the right and so on.
It's sort of like digits in numbers (units, tens, hundreds, ...) except that the next scaling is the previous scaling multiplied by the previous dimension rather than by a constant radix.
(You could let C convert groups of decimal digits to decimal numbers by letting it subtract some &decdigits[a][b][c] and &decdigits[0][0][0] where decdigits is some decdigits[10][10][10], i.e.:
char decdigits[10][10][10]; printf("%d\n", (int)(&decdigits[1][2][3] - &decdigits[0][0][0])) /*prints 123*/;)
#include <stdio.h>
void Func( int sizeFirst, int sizeSecond, int (*matrix)[sizeFirst][sizeSecond])
{
for (int i = 0; i < sizeof((*matrix))/sizeof((*matrix)[0]) ; i++)
{
for (int j = 0; j < sizeof((*matrix)[0])/sizeof((*matrix)[0][0]) ; j++)
{
printf("%d ", (*matrix)[i][j]);
}
puts("");
}
}
void Func_89( int sizeFirst, int sizeSecond, int *matrix)
{
for (int i = 0; i < sizeFirst; i++)
{
for (int j = 0; j < sizeSecond; j++)
{
printf("%d ", matrix[i*sizeSecond + j]);
}
puts("");
}
}
int main()
{
int array[2][3] = {
{5,8,2},
{1,3,6}
};
int sizeMain = sizeof(array)/sizeof(array[0]);
int sizeInner = sizeof(array[0])/sizeof(array[0][0]);
Func(sizeMain, sizeInner,&array );
puts("===");
Func_89(sizeMain, sizeInner,&array[0][0] );
//char decdigits[10][10][10]; printf("%d\n", (int)(&decdigits[1][2][3] - &decdigits[0][0][0])); //123
return 0;
}
First of you have to understand what int ** represent, it represents pointer to integer pointer, here's an example:
int a = 10;
int *p = &a; // 'p' points to 'a`
int **pp = &p; // 'pp' points to 'p' (pointer to integer)
So because of this, you can't use int ** for an integer array. Now that's out of the way, let's see what can you do instead (solution)
You can simply add a pointer to an integer array in a function definition like this
void Func(int *matrix[], int rows, int cols)
Or you can simply do
void Func(int matrix[rows][cols])
Note: Array of strings or 2D character array (char array[][]) can be represented as char**
I am trying to create a function that changes my 2d array and saves changes to it
The code is working but warnings about pointers appear, and I don't know how to bypass it with my yet basic knowledge of C language
#include <stdio.h>
int size = 0;
void functionName(char (*tab)[size][size]) {
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
(*tab)[i][j] = (*tab)[i][j]-'0';
}
}
}
int main() {
scanf("%d", &size);
char tab[size][size];
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
scanf("%c", &tab[i][j]);
}
}
functionName(tab);
return 0;
}
The error occurs because char tab[][] decays to a char (*)[] when passed as an argument, which doesn't match the type functionName expects. To resolve the inconsistency, either:
pass tab as a char (*)[][] by calling functionName(&tab) instead;
or, change the argument type of functionName to void functionName(char tab[size][size]), and fix the code inside the function to use tab[i][j] instead of (*tab)[i][j].
Problem is as answered by dxiv
C99 with variable length arrays or select later version of C, use:
void functionName(int size, char tab[size][size]) {
...
}
and call with
functionName(size, tab);
Also suspect OP's scanf("%c", &tab[i][j]); should change to scanf(" %c", &tab[i][j]); (Add space)
I have this function :
void foo( char tab[8][8] )
I want this function to edit the values of the tab array, so i tried theses syntax :
void foo( char *(*tab)[8][8] )
void foo( char *(tab)[8][8] )
void foo( char **tab )
And a LOT of others. I always get a fail while compiling, like this one :
error: cannot convert 'char ()[8][8]' to 'char (*)[8][8]' for argument '1' (...)
So, my quesiton is : how to create and pass to a function a pointer to a 2D array ?
Thanks.
This time try to declare your function as
void foo( char (*tab)[8] );
and call it as
foo(point);
Note that in this case you need to pass only array name as it decays to pointer when passed to a function (some exceptions are there). After decay it is of type char (*)[8].
You can do it also by declaring
void foo( char (*tab)[8][8] );
and call it as
foo(&point);
In this case notice that I passed &poinnt, i.e, address of the entire array which is of type char (*)[8][8].
Sample:
void foo(char (*tab)[8][8])
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 68j++)
{
scanf("%d", &(*tab)[i][j]);
}
}
}
With an array, you can always modify the data in the function because what is passed is a pointer (in the absence of const qualifiers, of course). That is, you could write:
void foo(char tab[8][8])
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
tab[i][j] = (x + y) % 2 : 'X' : 'O';
}
}
And call it:
void calling_func(void)
{
char board[8][8];
foo(board);
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
putchar(tab[i][j]);
putchar('\n');
}
}
You can get the error messages you were seeing if you write:
foo(&board);
That passes a pointer to an array to the function. For that to work, you have to rewrite the function as:
void foo(char (*tab)[8][8])
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
(*tab)[i][j] = (x + y) % 2 : 'X' : 'O';
}
}
However, this is seldom the correct way to write the code. Use the first alternative until this is forced upon you (which probably won't be this year — I don't recall having to use a pointer to an array except to answer questions on SO, but maybe it was such a ghastly experience that I have forgotten all about it).