Weird output when passing array of pointers - C - c

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

Related

Incompatible pointer type for array

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.

How to pass matrix to function by reference in C?

I'm defining a matrix, A, and I just want to print it out:
#include <stdio.h>
#define N 4
double A[N][N]= {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
void print_matrix(double **A) {
int i, j;
for(i = 0; i < N; i++) {
for(j = 0; j < N; j++) {
printf("%f ", A[i][j]);
}
printf("\n");
}
}
int main() {
print_matrix(A);
}
But on compile I get the error: expected 'double **' but argument is of type 'double (*)[4]'
I tried in the main function to pass the matrix like print_matrix(&A); but then the error was expected 'double **' but argument is of type 'double (*)[4][4]'
Pointer-to-pointer has nothing to do with multi-dimensional arrays. Simply declare the function as void print_matrix(double A[N][N]).
Thanks to "array decay", this passes the array by reference, since double A[N][N] when part of a parameter list, gets implicitly "adjusted" into a pointer to the first element, double (*A)[N].
There are multiple ways of defining a multidimensional array in C - and they have different exact semantics and behaviors w.r.t. passing to functions.
The approach you chose actually defines a single contiguous sequence of elements, which the double-bracketed access simply calculates an index into; it doesn't actually go through an array of pointers.
But you could also create an array of pointers and a large purely-unidimensional array for the entire data. See C FAQ 6.16.

Why can't int (*p)[] be used as an argument for C function?

#include <stdio.h>
void print(int (*p)[3]);
int main(void)
{
int a[3] = {1, 2, 3};
print(&a);
return 0;
}
void print(int (*p)[3])
{
for (int i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
I have written a C function. See above.
It can print all the elements in an array.
There is one thing which is not so perfect : The number of array elements seems to be known in advance.
So I made some modification in hopes of making the function universal :
#include <stdio.h>
void print(int (*p)[]);
int main(void)
{
int a[3] = {1, 2, 3};
print(&a);
return 0;
}
void print(int (*p)[])
{
for (int i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
In the function, p is pointer pointing to the entire array.
However, it fails to be compiled.
Why can't int (*p)[] be used as an argument for C function?
int (*p)[] can be used as an argument for the function. The part of your code that gives the error is sizeof *p which is obviously not possible, because the type of *p is int[] which is an incomplete type and hence has no known size.
For the function to know the length of the array, you must design a way for the function to receive this information. Options include:
what you did in the original code.
passing the length as another argument.
including the length as an array element.
having a sentinel value on the end of the array.
The most common idiom would be to pass int *p, size_t n, you do not really gain anything by using pointer-to-array without the dimension being given.
The problem is that int [] is an incomplete type as the array has no defined size and therefore its sizeof cannot be taken.
In "modern C" (i.e. for almost 2 decades) you could have used variable-length arrays for this - you can pass the size as an argument and then the array:
#include <stdio.h>
#include <stdlib.h>
void print(size_t n, int (*p)[*]);
int main(void) {
int a[3] = {1, 2, 3};
print(3, &a);
}
void print(size_t n, int (*p)[n]) {
for (size_t i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
Of course this gains you nothing, since sizeof *p / sizeof **pp will be ... n. Therefore we might as well have used
void print(size_t n, int p[n]) {
for (size_t i = 0; i < p; i++)
printf("%d\n", p[i]);
}
which is less typing.
Short answer: int (*p)[] can't be used as an argument and have the function magically know the array size, because the standard says so.
Longer answer:
int (*p)[] is a pointer to an array, but the array has no defined size. So by looking at the array, it is impossible to do pointer arithmetic, calculate size of the thing p is pointing at, etc..
You don't have array of arrays so you don't need int (*p)[]. You have an array of int, so int *p or int p[] should be enough. This does not solve the problem of knowing the size of your array in print. To do this you basically have 3 options
Hardcode the value in the function
Put a sentinel value in your array to mark the end
Pass the size as a separate parameter like this:
void print(int n, int p[n])
Just remember that whatever method you use, parameter passing of arrays will always use pointers behind the scenes, so you CAN NOT use sizeof(p) to calculate the size of the array. sizeof will always return the size of a pointer in those situations

Passing of arrays to function in c

If I only pass an element of an integer array (not the whole array) to a function , is it passed by value or by reference by default ?
for example-
arr[]={2,3,4,5,6}
ans=fun(arr[2])
and fun is some function which multiplies any value by 2 , then will i get the ans as 8 or 4 if i print arr[2] in the main function afterwards? Any help would be appreciated.
C has no references.
int fun(int a) {
a = 0;
}
int main() {
int arr[5] = {2, 3, 4, 5, 6};
fun(arr[2]);
printf("%d\n", arr[2]); //prints 4
return 0;
}
You can pass a pointer (still passes to the function by value, but that value is the address of the value you are interested in).
int fun(int *a) {
*a = 0;
}
int main() {
int arr[5] = {2, 3, 4, 5, 6};
fun(&arr[2]);
printf("%d\n", arr[2]); //prints 0
return 0;
}
I have a suspicion you meant C++. In that case, the function's signature determines whether it is passed by reference.
int fun(int &a) { //by reference, because of &
*a = 0;
}
int main() {
int arr[5] = {2, 3, 4, 5, 6};
fun(arr[2]);
printf("%d\n", arr[2]); //prints 0
return 0;
}
You question is tagged with c so I will answer in that context:
In the C language, there is no pass-by-reference. We can achieve a similar result as pass-by-reference by passing pointers.
That being said, if you're not passing a pointer to a function, then you're not changing the value within the calling scope.
void func(int a)
{
a = a * 2; // value of a within the calling scope does not change (pass-by-value)
}
void func2(int *a)
{
*a = (*a) * 2; // value pointed to by a is changed within the calling scope
}
In C arrays are passed as a pointer to the first element. They are the only element that is not really passed by value (the pointer is passed by value, but the array is not copied).
That allows the called function to modify the contents.
When we pass any array as an argument what matters is how we are handling it in the called function. If you are getting the address of the passed value(*val) then it will behave as Pass by reference and if you are getting the value directly in a variable as (val) then it will behave like a pass by value.

Passing a constant matrix

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.

Resources