New learner here; I am performing a traverse on any given array but I find I get this error:
exe_3.c:18:27: warning: incompatible pointer types passing 'int *' to parameter of type 'int **' [-Wincompatible-pointer-types]
int result = traverse(&arr[6], &n);
^~~~~~~
exe_3.c:4:25: note: passing argument to parameter 'A' here
const int traverse(int *A[], int *N){
What I have tried:
#include <stdio.h>
#include <stdlib.h>
const int traverse(int *A[], int *N){
int i = 0;
int arr[*N];
while(i < *N){
arr[i] = *A[i];
i += 1;
}
return *arr;
}
int main(){
int arr[6] = {1, 2, 3, 4, 5, 6};
int n = sizeof(arr)/sizeof(arr[0]);
int result = traverse(&arr, &n);
printf("%i\n", result);
return EXIT_SUCCESS;
}
Your call traverse(&arr, &n); passes a pointer to the array arr to the function traverse.
You get the error message, because the correct type definition for a pointer to an array of integers is int(A*)[]. You have that type in the definition of the traverse function incorrect (your line 4).
You will see that this is not enough to compile your code. When accessing the elements of such an array via that pointer you need the expression (*A)[i]. You have that access in the implementation of the traverse function incorrect (your line 8).
See also here for more details: C pointer to array/array of pointers disambiguation
What I find also strange with your traverse function is that the array arr is not used completely. Only the first value is returned. I suppose your code is just not complete.
A basic idea of what I'm talking about is below.
#include <stdio.h>
void someFunction(int arr[], int n)
{
for (int i = 0; i < n; ++i)
arr[i] *= 2;
}
void someFunctionByReference(int *arr, int n)
{
for (int i = 0; i < n; ++i)
arr[i] *= 2;
}
int main()
{
int arr[] = {5, 3, 2, 4, 5, 7, 0};
int n = sizeof(arr) / sizeof(arr[0]);
someFunction(arr, n);
int arr2[] = {5, 3, 2, 4, 5, 7, 0};
int n2 = sizeof(arr2) / sizeof(arr2[0]);
someFunctionByReference(arr2, n2);
return 0;
}
Both of these functions (as I see it) do the same thing. They even contain the same code. However, I would like to understand what the differences between the two are, and if there is a proper and improper way of doing this in certain scenarios.
Both function invocations and definitions are identical. Under most circumstances, an expression of array type will “decay” to an expression of pointer type and the value of the expression will be the address of the first element. In the context of a function parameter declaration, T a[N] and T a[] are interpreted as T *a - the parameter is a pointer, not an array object. This is because when you pass an array expression as a function argument, the function will actually receive a pointer value, not an array.
This behavior is unique to array expressions - other aggregate types like struct and union types do not “decay” in this manner. If you pass a struct type with an array member, the contents of the array member will be copied over.
And this is not an example of “pass by reference”, either. C passes all function parameters by value, no exceptions. Sometimes those values are pointers. This particular quirk is simply fallout from how C treats arrays.
I have a two dimensional array of pointers declared in main as
char* data[3][8]
which I passed into a function
void func(char*** data)
When I did printf("%p\n", data[0]); in main and in the function I got different outputs 0x7ffeabc27640 in main and (nil) in the function. Albeit printing just data outputs the same address with that from inside the main. Why can't I access the array in the function.
If you enable some warnings (which you should always do), you'll get :
main.cpp: In function 'main':
main.cpp:6:10: warning: passing argument 1 of 'func' from incompatible pointer type
func(data);
^
main.cpp:2:6: note: expected 'char ***' but argument is of type 'char * (*)[8]'
void func(char*** data) { (void)data; }
^
Which tells you exactly what's wrong, namely that an array is not a pointer. Dereferencing a pointer that has been converted to the wrong type is undefined behaviour, so you can get anything back.
Have your function take in a char *(*)[8] if you want to give it a char *(*)[8] :
void func(char *(*data)[8]);
Or, if you want to emphasize that data should point to the first element of an array :
void func(char *data[][8]);
The two syntaxes are perfectly equivalent.
Note : the file is named main.cpp but is indeed compiled in C mode.
Passing 2D arrays to a function -
This will help you read-up and better understand how to do this...
http://www.geeksforgeeks.org/pass-2d-array-parameter-c/
The below is a snippet from the web-page - showing one example of how to do this.
#include <stdio.h>
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;
}
Output:
1 2 3 4 5 6 7 8 9
I have a function like this:
void myfunc(int** arr, int n) {
int i, j;
for(i=0; i<n; ++i) {
for(j=0; j<n; ++j) {
printf("%d,", *(arr + i*n + j) ); // Print numbers with commas
}
printf("\n"); // Just breakline
}
}
in other function I have an two-dimensional array like this:
int main() {
int seqs[8][8] = {
{0, 32, 36, 52, 48, 16, 20, 4},
{0, 16, 20, 52, 48, 32, 36, 4},
{0, 32, 36, 44, 40, 8, 12, 4},
{0, 8, 12, 44, 40, 32, 36, 4},
{0, 32, 36, 38, 34, 2, 6, 4},
{0, 2, 6, 38, 34, 32, 36, 4},
{0, 32, 36, 37, 33, 1, 5, 4},
{0, 1, 5, 37, 33, 32, 36, 4}
};
// Call to myfunc
myfunc(seqs, 8); // This is the idea
}
But compiler throw me this error:
lab.c: In function 'main':
lab.c:75:5: warning: passing argument 1 of 'myfunc' from incompatible pointer type [enabled by default]
lab.c:4:6: note: expected 'int **' but argument is of type 'int (*)[8]'
What is the right way to pass this array (seqs) to function (myfunc)?
In C99 or C11, you would do it like this:
void myfunc(int n, int arr[n][n])
{
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
printf("%d,", arr[i][j]);
printf("\n");
}
}
Note that the size precedes, not follows, the array. This function will work correctly with:
int main(void)
{
int seqs[8][8] =
{
{ 0, 32, 36, 52, 48, 16, 20, 4 },
{ 0, 16, 20, 52, 48, 32, 36, 4 },
{ 0, 32, 36, 44, 40, 8, 12, 4 },
{ 0, 8, 12, 44, 40, 32, 36, 4 },
{ 0, 32, 36, 38, 34, 2, 6, 4 },
{ 0, 2, 6, 38, 34, 32, 36, 4 },
{ 0, 32, 36, 37, 33, 1, 5, 4 },
{ 0, 1, 5, 37, 33, 32, 36, 4 },
};
myfunc(8, seqs);
int matrix3x3[3][3] = { { 1, 2, 3 }, { 2, 4, 6 }, { 3, 6, 9 } };
myfunc(3, matrix3x3);
}
I was asked:
Your example does look much better indeed, but is it well-defined? Is n really guaranteed to be evaluated before int arr[n][n]? Wouldn't the order of evaluation of function parameters be unspecified behavior?
The old standard (ISO/IEC 9899:1999) says in §6.7.5.2*Array declarators*:
¶5 If the size is an expression that is not an integer constant expression: if it occurs in a
declaration at function prototype scope, it is treated as if it were replaced by *; otherwise,
each time it is evaluated it shall have a value greater than zero. The size of each instance
of a variable length array type does not change during its lifetime. Where a size
expression is part of the operand of a sizeof operator and changing the value of the
size expression would not affect the result of the operator, it is unspecified whether or not
the size expression is evaluated.
And it gives an example (it is non-normative text because it is an example, but strongly indicative of what is expected):
EXAMPLE 4 All declarations of variably modified (VM) types have to be at either block scope or
function prototype scope. Array objects declared with the static or extern storage-class specifier
cannot have a variable length array (VLA) type. However, an object declared with the static storage class
specifier can have a VM type (that is, a pointer to a VLA type). Finally, all identifiers declared with a
VM type have to be ordinary identifiers and cannot, therefore, be members of structures or unions.
extern int n;
int A[n]; // invalid: file scope VLA
extern int (*p2)[n]; // invalid: file scope VM
int B[100]; // valid: file scope but not VM
void fvla(int m, int C[m][m]); // valid: VLA with prototype scope
void fvla(int m, int C[m][m]) // valid: adjusted to auto pointer to VLA
{
typedef int VLA[m][m]; // valid: block scope typedef VLA
struct tag {
int (*y)[n]; // invalid: y not ordinary identifier
int z[n]; // invalid: z not ordinary identifier
};
int D[m]; // valid: auto VLA
static int E[m]; // invalid: static block scope VLA
extern int F[m]; // invalid: F has linkage and is VLA
int (*s)[m]; // valid: auto pointer to VLA
extern int (*r)[m]; // invalid: r has linkage and points to VLA
static int (*q)[m] = &B; // valid: q is a static block pointer to VLA
}
There are other examples showing variably modified function parameters.
Also, in §6.9.10 Function definitions, it says:
¶10 On entry to the function, the size expressions of each variably modified parameter are
evaluated and the value of each argument expression is converted to the type of the
corresponding parameter as if by assignment. (Array expressions and function
designators as arguments were converted to pointers before the call.)
Arrays and pointers are not the same. Similarly, two-dimensional array and pointer to pointer are not the same thing. The type of seqs mismatches function argument, you can modify the signature of myfunc to:
void myfunc(int arr[][8], int n)
or, you can modify seqs to a real pointer to pointer.
You're declaring the int** as an array with a static size, so its signature is int *[8]. You can get rid of the compiler error by casting the array when you call myfunc.
myfunc((int **)seqs, 8);
In an actual program such an array would most likely be generated dynamically, and you wouldn't have to do this.
The way you're accessing the value from the array in your function, would give you the right element with a simple int * rather than an int **. With *(arr + i*n + j). The i*n gets you to the right row, and the j gets you the column. So change your function header line to:
void myfunc(int* arr, int n) {
...(with one '*'), and pass the address of the first element rather than the bare array name, like this:
myfunc(&seqs[0][0], 8);
..or the first row:
myfunc(seqs[0], 8);
When you define a 2-dimensional array as
int seqs[8][8];
the type of seqs is array of 8 elements where each element is of type array of 8 integers. When you pass seqs to myfunc, seqs is implicitly converted to a pointer to its first element (which is what happens when you pass an array to a function), i.e., to type * element. element is of type int [8]. Hence seqs is implicitly converted to type int *[8] - a pointer to an array of 8 integers.
In your function myfunc, the type of the parameter arr is int ** clearly a different type than what you pass it when you call it in main. They are different types and have different pointer arithmetic. The compiler complains as a result.
You should change the type of arr to int *[8].
void myfunc(int arr[][8], int n);
arr is not an array here but a pointer to an array of 8 integers and you might as well declare myfunc as
void myfunc(int *arr[8], int n);
They are exactly the same.
Edit
Regarding your comment here, you cannot do the following and expect things to work correctly.
// in main
myfunc((int **)seqs, 8);
// the above call is essentially doing this
int **arr = (int **)seqs;
seqs and arr are incompatible types and typecasting seqs suppresses the warning emitted otherwise by the compiler which is worse because typecasting doesn't correct things, and make it seem as if things are alright.
Let us see why. (After the function call.)
seqs (type: array of 8 int[8] type; value: address of the location seqs[0][0])
*seqs (type: int[8] type, value: address of the location seqs[0][0])
arr (type: pointer to a pointer to an int; value: address of the location seqs[0][0])
*arr (type: pointer to an int; value: seqs[0][0])
**arr (type: int; value: value at the address seqs[0][0])
The above assertions can be checked with the assert macro. So we see that when we do **arr what we are actually doing is treating the value seqs[0][0] as a memory address and trying to access the value at that location. This is obviously wrong! It can lead to undefined behaviour or most likely segmentation fault.
There's no way to make the value of seqs (value it evaluates to in the initialization of arr) act like a int ** even by typecasting. This also shows that we should be careful with typecasting values and shouldn't do it unless we know and are sure of what we are doing.
Therefore, you must change your myfunc function signature to do what you want.
Referring to this question and especially the accepted answer of litb, I wonder why the gcc complain about this:
void func(const int (*ip)[3]) {
printf("Value: %d\n", ip[1][1]);
}
int main() {
int i[3][3] = { {0, 1, 2} , {3, 4, 5}, {6, 7, 8} };
func(i);
return 0;
}
If I eliminate the const the compiler keeps still. Did I something misunderstand? I wanted to be sure that func don't modify my array.
EDIT: The same thing happens if I define a data type for my matrix:
typedef int Array[3][3];
void func(const Array *p) {
printf("Value: %d\n", (*p)[1][1]);
}
int main() {
Array a = { {0, 1, 2}, {3, 4, 5}, {6, 7, 8} };
func(&a);
return 0;
}
I accept, this kind of code isn't very C style, more like C++. In C++ indeed there would be no problem if I define Array as a class containing all the matrix behavior.
class Array {...};
I suppose, I didn't understand very well the concept of arrays and arrays of arrays in C and passing them to functions. Any enlightenment?
Thank you in advance.
EDIT2: Meanwhile I chewed a bit on this problem and it seems to converge to the following question: C/C++ implicitly converts a pointer to an int to a pointer to an const int. Thus the following works:
func(const int a[]) // aquivalent: func(const int *a)
{ ... }
int main()
{
int b[10];
func(b);
return 0;
}
But C/C++ don't implicitly converts a pointer to an array of n ints to a pointer to an array of n const ints. Even though an array of n ints is implicitly converted to an array of n const ints. This level of indirection in the implicit conversion isn't supported. The following will be rejected (at least with a warning in C):
func(const int a[][n]) // aquivalent: func(const int (*a)[n])
{ ... }
int main()
{
int b[m][n];
func(b);
return 0;
}
It's similar to the problem that C++ doesn't implicitly convert a template for the type A into a template of type B even if A can be implicitly converted to B. The two templates are of completely different types.
Is this the right answer?
Your i variable is an array with 3 elements.
When you pass it to a function, inside the function, it becomes a pointer to the first element. The compiler can add const either to the pointer or to the thing pointed to: an array of 3 ints. It cannot however change the thing pointed to from an array of 3 ints to an array of 3 constants.
I think you need to do the cast yourself.
#include <stdio.h>
typedef const int array_of_3_constants[3];
void func(int (* const i)[3]) {
++i[0][0];
printf("Value: %d\n", i[1][1]);
}
void gunc(array_of_3_constants *i) {
++i[0][0]; /* error */
printf("Value: %d\n", i[1][1]);
}
int main(void) {
int i[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
func(i);
func((array_of_3_constants*)i); /* warning */
gunc(i); /* warning */
gunc((array_of_3_constants*)i);
return 0;
}
You don't need to eliminate const, just pass a compatible value by casting the argument in the call to func:
func( (void *)i );
If possible, it would be preferrable to declare i as const, but this hack should work.