Passing a constant matrix - c

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.

Related

Should I pass an int array to a function by reference?

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.

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

What syntax should I use in the header of a function taking a two dimensional array as an argument in C

I want to create a function that takes in the pointer to a two dimensional array that will modify the elements of this array.
When I want to do the same thing with a one dimensional array, the thing is simple - I simply use the name of this array
void foo(int *array) {
//CODE
}
int main() {
int test[5] = {0, 1, 2, 3, 4};
foo(test);
return 0;
}
But what can I do in terms of two dimensional arrays? I tried to use this syntax:
#include <stdio.h>
void foo(int array[][]) {
printf("%d", array[0][0]);
}
int main(void) {
int array[2][2];
array[0][0] = 3;
foo(array);
}
but it did not work. Why is it not possible ot use this? How are two dimensional arrays treated in C?
First you have to realize that void foo(int array[x]) and void foo(int* array) are 100% equivalent, because when you use the array syntax as part of a function parameter, it gets silently adjusted by the C compiler into a pointer to the first element. This is the reason why your original code works.
When using 2D arrays, there's no difference: you would write void foo(int array[x][y]). This too gets adjusted to a pointer to the first element. As it turns out, C does not actually support 2D arrays - what we have here is an array of arrays of int. The first element of an array of arrays of int, is an array of int.
How do we write a pointer to an array of int then? With the array pointer syntax: int(*)[y]. You can think of it as if this pointer points at "the whole array".
And this is the reason why we get away with writing things like void foo(int array[][y]); - the inner-most dimension doesn't matter, since the parameter will get adjusted to an array pointer anyway.
C is deliberately designed this way to make functions match the rule of "array decay", which means that whenever an array name is used in an expression, it "decays" into a pointer to the first element. And this also makes it impossible to pass an array by value.
Example:
void foo(int array[2][5]) {
//CODE
}
int main() {
int test[2][5] =
{
{0, 1, 2, 3, 4},
{0, 1, 2, 3, 4}
};
foo(test);
return 0;
}
Where all of these
void foo(int array[2][5])
void foo(int array[][5])
void foo(int array[666][5])
get silently adjusted by the compiler to be the same as
void foo(int (*array)[5])
You can pass two dimensional array (actually a pointer to an array of arrays) to a function by declaring any of function prototypes
void foo1(int arr[][10]);
void foo2(int (*arr)[10]);
For C99 and latter these will also work
void foo3(int n, int arr[][n]);
void foo4(int n, int (*arr)[n]);
Then call your function
int arr[5][10] = { /*...*/ };
// code ...
foo1(arr);
foo3(10, arr);
// code ...

Failed to initialize a pointer array in C

int array[2] = {1, 1};
int (*pointer_array)[2] = {NULL, NULL};
The first line can be correctly compiled but not the second one? Why?
GCC compiler will pop up a warning, excess elements in scalar initializer.
How to initialize a pointer array in C?
EDITED
I declared a pointer array in a wrong way.
It should be like this:
int *pointer_array[2] = {NULL, NULL};
It should be
int (*pointer_array)[2]=(int[]){1,2};
This is pointer to array of int .I don't know you want pointer to array of int or array of pointers.
To declare as array of pointer you need to do this -
int *pointer_array[2];
Suppose you have an array of int of length 5 e.g.
int x[5];
Then you can do a = &x;
int x[5] = {1};
int (*a)[5] = &x;
To access elements of array you: (*a)[i] (== (*(&x))[i]== (*&x)[i] == x[i]) parenthesis needed because precedence of [] operator is higher then *. (one common mistake can be doing *a[i] to access elements of array).
Understand what you asked in question is a compilation time error:
int (*a)[3] = {11, 2, 3, 5, 6};
It is not correct and a type mismatch too, because {11,2,3,5,6} can be assigned to int a[5]; and you are assigning to int (*a)[3].
Additionally,
You can do something like for one dimensional:
int *why = (int[2]) {1,2};
Similarly, for two dimensional try this(thanks #caf):
int (*a)[5] = (int [][5]){ { 1, 2, 3, 4, 5 } , { 6, 7, 8, 9, 10 } };

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.

Resources