How C manages the memory - arrays

The answer should be 1 and 1. But why the result is 1 and 2. Arr is not a global variable.
#include <stdio.h>
void add (int arr[1])
{
arr[0] = arr[0]+1;
}
int main() {
int arr[1]={1};
printf("%d\n",arr[0]);
add(arr);
printf("%d", arr[0]);
return 0;
}

The answer should be 1 and 1
No, it should be 1 and 2.
void add (int arr[1]) creates a local parameter variable named arr, to which you pass the variable also named arr in the caller.
There are two rules in C informally called "array decay", which means that whenever an array is used in an expression or function parameter declaration, it gets adjusted implicitly by the compiler into a pointer to the first element of the array.
So add(arr); is 100% equivalent to add(&arr[0]);.
And the function defintion void add (int arr[1]) is equivalent to void add (int* arr). This always happens, you can't pass arrays by value in C even though void add (int arr[1]) looks like it does that.
For this reason, the arr in your function points at the arr in the caller. And when you update the contents pointed at, you update the contents of the variable in main.

When an array is declared as a function argument, it becomes a pointer. That's just the way it is. Here is a snippet with corresponding errors ans warnings that proves it:
$ cat main.c
void foo(int arg[10]) {
int arr[10];
float *x;
arg = x;
arr = x;
}
$ gcc -c main.c
main.c: In function ‘foo’:
main.c:5:9: warning: assignment to ‘int *’ from incompatible pointer type ‘float *’ [-Wincompatible-pointer-types]
5 | arg = x;
| ^
main.c:6:9: error: assignment to expression with array type
6 | arr = x;
| ^
So in this case, arr is an array, but arg is not. This means that your add function is equivalent to this:
void add (int *arr)
{
arr[0] = arr[0]+1;
}
And when you pass an array to a function, it will automatically decay to a pointer. So the output 1 and 2 is the expected output.

Related

C - Trouble passing array reference to pointer argument in function

I'm having trouble passing an integer array as a reference, and then modifying the original array.
#include <stdio.h>
// sets the 2 element of i to 5
void setToFive(int *i[10]){
*i[2] = 5;
printf("hello\n");
}
int main(){
int i[10];
setToFive(&i);
// confirm i[2] == 5
printf("%d\n", i[2]);
}
Compiler complains about invalid type
[vinessa#komputilo ch1]$ gcc test.c
test.c: In function ‘setToFive’:
test.c:5:5: error: invalid type argument of unary ‘*’ (have ‘int’)
5 | *i[2] = 5;
| ^~~~~
test.c: In function ‘main’:
test.c:11:15: warning: passing argument 1 of ‘setToFive’ from incompatible pointer type [-Wincompatible-pointer-types]
11 | setToFive(&i);
| ^~
| |
| int (*)[10]
test.c:4:21: note: expected ‘int *’ but argument is of type ‘int (*)[10]’
4 | void setToFive(int *i){
| ~~~~~^
segmentation fault
[vinessa#komputilo ch1]$ ./a.out
Segmentation fault (core dumped)
Have been banging head at problem for hours, please help.
Here you are
#include <stdio.h>
// sets the 2 element of i to 5
void setToFive(int *i){
i[2] = 5;
printf("hello\n");
}
int main(){
int i[10];
setToFive(i);
printf("%d\n", i[2]);
}
If you want to change elements of an array then just pass it by value. In this case the array designator is implicitly converted to pointer to its first element. Using the pointer and the pointer arithmetic you can change any element of the array.
In fact in this case you are passing elements of the array by reference indirectly through a pointer to them.
Pay attention to that these function declarations
void setToFive(int i[100]);
void setToFive(int i[10]);
void setToFive(int i[1]);
void setToFive(int i[]);
are equivalent and declare the same one function declaration of which the compiler adjusts to the following declaration
void setToFive(int *i);
That is as a result the function deals with a pointer.
As for the expression used as an argument in this function call
setToFive(&i);
then it has the type int ( * )[10] because the pointed array is declared like
int i[10];
It is not the same as the type of the parameter int *i[10] that as I already wrote is adjusted by the compiler to the type int **.
You are passing an array of pointers to integers, not an array of integers. You can just remove the various * declarations and operators, and just pass a simple array as the argument (the array argument will decay to a pointer):
#include <stdio.h>
// sets the 2 element of i to 5
void setToFive(int i[10])
{
i[2] = 5;
printf("hello\n");
}
int main()
{
int i[10];
setToFive(i);
// confirm i[2] == 5
printf("%d\n", i[2]);
return 0;
}

How do I fix warning: assignment from incompatible pointer type?

I wanted to ask how to get rid of warning that says assignment from incompatible pointer type.
This is the code I use:
#include<stdio.h>
int main()
{
int a2d[2][2]={{1,2},{3,4}};
int **pa;
pa=a2d;
}
And getting this:
7:5: warning: assignment from incompatible pointer type pa=a2d;
When this
pa=a2d;
executes, compiler shoots the warning/error(depends upon whether you are using -Werror or not) as
main.cpp:7:8: error: cannot convert 'int [2][2]' to 'int**' in assignment
7 | pa=a2d;
| ^~~
| |
| int [2][2]
and this error is valid as a2d is two dimensional array, that doesn't mean its of int** type, similar to the concept of array is not pointer.
To make things works pa should be pointer to an array not double pointer int**. For example
int a2d[2][2]={{1,2},{3,4}};
int (*pa)[2] = a2d; /* pa is pointer to an array */
here pa can point to 2 elements at a time i.e pa points to a2d[0] base address and pa+1 will points to a2d[1] base address.
You are probably looking to decay your 2d array to array of pointers to array elements. In this case:
int a2d[2][2] = { { 1,2 },{ 3,4 } };
int (*pa)[2] = a2d;
To access 4:
printf("%d\n", pa[1][1]);
Your assignment is wrong, you can't parse 2d array to pointer to pointer.
Your code should like this:
#include<stdio.h>
int main()
{
int a2d[2][2]={{1,2},{3,4}};
int * pa;
pa=&a2d[0][0];
}
Becasue 2d array isn't double pointer. But this works:
#include<stdio.h>
int main()
{
int ad[2]={4,5};
int * pa;
pa=ad;
}
But it's passing its address. But if you write:
int a2d[2][2]={{1,2},{3,4}};
int ** pa;
pa=a2d;
It passing address of a2d array to double pointer...

Pass a two dimensional array to a function of constant parameter

I learned from C Primer Plus that if you want to protect an array from being accidentally modified by a function, you should add const modifier before the pointer declaration in the header of function definition.
Following this sensible advice, in the following minimal example, I'm trying to pass a non-constant two-dimensional array array to the function Sum2D, one parameter of which is a pointer-to-const-int[2].
#include <stdio.h>
#define ROWS 2
#define COLS 2
int Sum2D(const int ar[][COLS], int rows); //use `const` to protect input array
int main(void)
{
int array[ROWS][COLS]={{1,2},{3,4}}; //the non-constant array
printf( "%d\n", Sum2D(array,ROWS) );
return 0;
}
int Sum2D(const int ar[][COLS], int rows)
{
int total=0;
int i,j;
for( i=0 ; i<rows ; i++ )
{
for( j=0 ; j<COLS ; j++ )
{
total+=ar[i][j];
}
}
return total;
}
However, gcc cannot successfully compile this code without issuing the following warnings:
$gcc -ggdb3 -Wall -Wextra -o test test.c
test.c: In function ‘main’:
test.c:16:2: warning: passing argument 1 of ‘Sum2D’ from incompatible pointer type [enabled by default]
printf( "%d\n", Sum2D(array,4) );
^
test.c:4:5: note: expected ‘const int (*)[4]’ but argument is of type ‘int (*)[4]’
int Sum2D(const int ar[][COLS], int rows);
^
1) Why the warning?
2) How can I eliminate the "noise"?(Apart from adding const to array declaration.)
(If the array and function both use one-dimensional array, there is no warning.)
System information:
Ubuntu 14.04LTS
Compiler: gcc 4.8.2
This is an unfortunate "bug" in C's design; T (*p)[N] does not implicitly convert to T const (*p)[N]. You will have to either use an ugly cast, or have the function parameter not accept const.
At first sight it looks like this conversion should be legal. C11 6.3.2.3/2:
For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type;
However also look at C11 6.7.3/9 (was /8 in C99):
If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type.
This last quote says that int const[4] is not considered to be a const-qualified version of int[4]. Actually it is a non-const-qualified array of 4 const ints. int[4] and int const[4] are arrays of different element types.
So 6.3.2.3/2 does not in fact permit int (*)[4] to be converted to int const (*)[4].
Another weird situation where this issue with const and arrays shows up is when typedefs are in use; for example:
typedef int X[5];
void func1( X const x );
void func1( int const x[5] );
This would cause a compiler error: X const x means that x is const, but it is pointing to an array of non-const ints; whereas int const x[5] means x is not const but it is pointing to an array of const ints!
Further reading here, thanks to #JensGustedt
You can type cast the array while calling the function. It will not automatically convert non-const into const.
You can use this.
Sum2D( (const int (*)[])array, ROWS );

What is the difference between *p and (*p)[3] in the function?

I'm new in programming and learning pointers in array in C. Have a look at the below programmes.
1st program
#include<stdio.h>
int fun();
int main()
{
int num[3][3]={21,325,524,52,0,6514,61,33,85};
fun(num);
printf("%d",*(*(num+1)+1));
*(*(num+1)+1)=0;
printf("%d",*(*(num+1)+1));
return 0;
}
int fun(int **p)
{
*(*(p+1)+1)=2135;
return 0;
}
2nd program
#include<stdio.h>
int fun();
int main()
{
int num[3][3]={21,325,524,52,0,6514,61,33,85};
fun(num);
printf("%d",*(*(num+1)+1));
*(*(num+1)+1)=0;
printf("%d",*(*(num+1)+1));
return 0;
}
int fun(int *p)
{
*((p+1)+1)=2135;
return 0;
}
3rd program
#include<stdio.h>
int fun();
int main()
{
int num[3][3]={21,325,524,52,0,6514,61,33,85};
fun(num);
printf("%d",*(*(num+1)+1));
*(*(num+1)+1)=0;
printf("%d",*(*(num+1)+1));
return 0;
}
int fun(int (*p)[3])
{
*(*(p+1)+1)=2135;
return 0;
}
In the first program **p is used in the fun() function which I think it should be correct and in that function I've written *(*(p+1)+1) to change the first element of first array. But on compiling this program it's showing error: invalid type argument of unary '*' (have 'int'). As far as I know num is a pointer to array and it is holding the address of num[1] which is again holding the address of num[1][0].
On compiling the second program compiler is showing no error. And *((p+1)+1)=0 is changing the value of 2nd element of first array. Why it is changing the value of 2nd element of zeroth array not the value of first element of first array? and How? It should be *(*(p+1)+1)=0.
In the third program the compler is showing no error and it is showing the correct result. How?. What does *(p)[3] mean?
I had searched about this but couldn't found the satisfactory result.
All of your programs are ill-formed. Your compiler must produce warning or error messages, and the output of any executable produced is meaningless.
They are ill-formed because int[3][3] is not compatible with int **, nor with int *, nor with int *[3].
To pass int[3][3] to a function, the function must accept int (*)[3] and nothing else (well, except for void *).
This is because arrays can be converted to a pointer to the first element of the array. (In C syntax, num can be used to mean &num[0]).
In C, there are only truly one-dimensional arrays; an array of type int[3][3] is considered to be an array of 3 elements, each of which is an array of 3 ints.
So a pointer to the first element of num is a pointer to an array of 3 ints, which is written as int (*p)[3]. You could write:
int (*p)[3] = &num[0];
or the shorthand for the same thing:
int (*p)[3] = num;
NB. You continually write *(*(num+1)+1)) which is difficult to read. Instead of this, num[1][1] seems much clearer.
In C, x[y] is always exactly equivalent to *(x+y).
I think you are asking: What's the difference between
int fun(int *p)
and
int fun(int (*p)[3])
The first one expects a pointer to an int. The second one expects a pointer to an array of 3 ints.
You are able to call to both these functions using num since you declared the function as
int fun();
If you declare the functions like they are defined, you will get compiler error/warning for the first version.
Here's an updated version of your code and the resulting compiler warning, using gcc and compiler flag -Wall.
#include <stdio.h>
int fun(int *p);
int main()
{
int num[3][3]={21,325,524,52,0,6514,61,33,85};
fun(num);
return 0;
}
int fun(int *p)
{
*(p+0)=2135;
return 0;
}
test.c: In function ‘main’:
test.c:7:4: warning: missing braces around initializer [-Wmissing-braces]
test.c:7:4: warning: (near initialization for ‘num[0]’) [-Wmissing-braces]
test.c:8:4: warning: passing argument 1 of ‘fun’ from incompatible pointer type [enabled by default]
test.c:3:5: note: expected ‘int *’ but argument is of type ‘int (*)[3]’

I'm trying to make 2d array, pass it to function and then update the modified array in main

The compiler shows:
Warning: passing argument 1 of 'fun' from incompatible
pointer type; note: expected 'int ()[5]' but argument
is of type 'int (*)[5][5]'
Code:
#include<stdio.h>
void fun(int * b[][5])
{
int x=11,y=90;
printf("here");
*b[1][3] = x;
*b[3][1] = y;
*b[2][2] = x + ++y;
}
int main()
{
int a[5][5];
a[1][3] = 12;
a[3][1] = 145;
fun(&a);
printf("%d %d %d",a[1][3],a[3][1],a[2][2]);
}
You do not need the asterisk in your function parameters, and you don't need to dereference the array b in your function. Arrays are passed by reference (so get rid of the ampersand in foo(&a) as well), because C treats them as pointers to the first element in the sequence.
Multidimensional arrays are treated as arrays of pointers to the start of smaller sub-arrays, i.e. arrays-of-arrays. Same explanation as above applies.
Your code should look like this in the end:
void fun(int b[][5]) // can also be (int (*b)[5]), i.e. array of 5 pointers
{
int x=11,y=90;
b[1][3] = x;
b[3][1] = y;
b[2][2] = x + ++y;
}
int main()
{ // ...
fun(a);
// ...
}
int a[5][5]; //is an 2d int array
When arrays are passed to a function, what really gets passed is a pointer to the arrays first element.
So calling the fun() function with fun(a) will actually pass the pointer to the a first element, in this case an int array of size 5. The function fun() will receive a pointer to an int array of size 5, that is to say int (*b)[5]. Note that int *b[5] is not the same and is an array of size 5 containing int pointers.
Your fun function can either have:
void fun(int b[][5])
or
void fun(int (*b)[5])
The first way to do it says that the function will receive a 2d array of ints, but since we know that what actually will be sent to the function is a pointer to the first element of the array a, the compiler will quietly compile the function as if the parameter were a pointer, since it's a pointer that it will receive.
The second way to do it explicitly shows what type it will receive, a pointer to an array of size 5.

Resources