c pointer being passed to a function - arrays

int func(int a[]);
int main()
{
int c = 21;
int *b;
b=&c;
printf("%d",b);
func(b);
return 0;
}
int func(int a[]){
printf("\n%d",(a));
printf("\n%d",*(a));
printf("\n%d",(a[0]));
printf("\n%d",(a[1]));
printf("\n%d",(a[2]));
}
this is something I'm trying to understand how these pointers work with arrays.
this is the output.
-680548828
-680548828
21
21
-680548828
32767
the first two 680548828 and the two 21s I understand. simply printing a would be the first element of array a[]. a[0] is like writing *a. what I dont get is why a[1] would have 680548828 in it. a[1] is the element in the array after the element where the pointer to 21 is stored(a[0])? sorry for the confusion please help. Thank you.

In your code
printf("%d",b);
invokes undefined behaviour, as you;re trying to print a pointer using %d. The correct way would be to use
%p format specifier
cast the argument to void *
The same logic is applicable to the called function also, remember, an array name decays to the pointer to teh first element, basically yields a pointer type, in most of the cases (including this specific usage).
That said, you are trying to access invalid memory in the called function. You passed a pointer to one int, and in the called function, you're trying to access memory outside the memory region, by saying a[1], a[2] etc. You cannot do that. It again invokes undefined behaviour.

Related

Difficulty in understanding the pointers output

Please have a look at code below :
#include <stdio.h>
void main()
{
int a=30;
int *var=&a;
Change(&var);
printf("%d %d",*var,a);
}
int Change(int**ptr)
{
**ptr=40;
}
#include <stdio.h>
void main()
{
int a=30;
int *var=&a;
Change(var);
printf("%d %d",*var,a);
}
int Change( int *ptr)
{
*ptr=40;
}
The output from both programs is 40 40
We are passing the copy of address of var so why it is reflected in actual main function and producing output 40 40?
Why both of these programs are producing same output?
Both programs are equivalent. In first one, you passing pointer to pointer (i.e. address of pointer variable), and then dereferencing it twice. In second one, you are are just passing pointer (i.e. address of actual variable) and dereferencing it once.
It seems to me you need the following illustration to get the answer on your q:
The output is the same because you write 40 via the same pointer to int. In the second case you pass pointer-to-int, which you successfully dereference with * operator and obtain lvalue with type int, to which you then write 40. In the first case you pass pointer-to-pointer-to-int. And then you do double dereferencing: **ptr or the same as *(*ptr). Inner * is applied first and makes the expression with type pointer-to-int inside braces, and that pointer-to-int is the same as was passed to Change() in the second case. And at the end - outer * works just like for the second case.
&var passes the address of var and Change uses double pointer because, var is pointing to address of a. So, Derefrencing single pointer on &var (address of var) will point to the value stored in var i.e., a's address, so again derefrencing it, will point to the value of a i.e., 30.
For single pointer Change, I think, you should figure that out now from the above details.

How does a pointer to the constant pointer of the first element of an array work?

I wanted to test if I could change the constant pointer that points to the first element of an array in C. While testing I got some strange output that I don't understand:
//Constant pointer to pointer to constant value
void test(int const * * const a) {
//printf("%d", **a); //Program crashes (2)
(*a)++;
}
int main()
{
int a[5] = { 1,2,3,4,5 };
test(&a);
printf("%d", *a); //Prints 5 as output (1)
return 0;
}
I expected the compiler to give an error when I try to compile (*a)++ but instead I can run the code, but when I try to print the element I get a strange value (1).
Then I wanted to print out the value (2) of the first element of the array. When I tried this, the program crashes.
By doing &a you are making a pointer to an array (int (*)[]).
Then when this pointer to array is passed to the test function, it's converted to a pointer to a pointer(int **);
Then (*a)++; is UB.
1. So why 5?
On modern implementation of C like GCC, pointer to a array has the same numerical value as the beginning of the array, so is the address value when the array decays to a pointer: they all are the beginning address of the array.
So, in test, int **a points to the beginning of the array, (*a)++ deferences the pointer as int * and increment the pointer by 1 int element, which is usually implemented as adding the sizeof(int) to the numerical value of the pointer.
Then, 1+sizeof(int) gives you 5.
2. Why it crashed in the second case?
Assuming you are using a 32bit x86 machine, or some machine whose pointer type has the same size as int type, then *a equal to 1. Then further dereferencing the pointer at a memory address at 1 usually gives you a segfault.
The program crashes at the printf because test assumes that when it dereferences a the resulting object is a pointer. If it were one and contained a valid address, the second dereferencing would yield an int object. Alas, a contains the address of the array, which is numerically the address of its first element. The 4 or 8 bytes there are considered an address (because test thinks that *a is a pointer) and the code then tries to access the memory at address 1 in order to print the int value assumed at that address. The address is invalid though, so the program crashes.
Now that we have established that the program considers the data at the beginning of the array a pointer to int, we know what (*a)++ does: it increments the value there by sizeof(int) so that the "pointer" point to the next int "element". I guess an int on your machine is 4 bytes long because 1+4=5, which is printed.
This code is illegal in C, you should get a compiler diagnostic. (If not, turn up your warning level). The results of running any executable produced are meaningless.
The code is illegal because int (*)[5] does not implicitly convert to int const **.
the constant pointer that points to the first element of an array in C
There is no such thing. You misunderstand what arrays are. Arrays are a series of contiguous elements. int a[5] is like int a; except that there are 5 ints instead of 1.
int a; and int a[1]; cause identical memory layout. The only difference is the syntax used to access that memory.

Why it is not an error to increment array "a" in the below function?

#include<stdio.h>
void printd(char []);
int main(void){
char a[100];
a[0]='a';a[1]='b';a[2]='c';a[4]='d';
printd(a);
return 0;
}
void printd(char a[]){
a++;
printf("%c",*a);
a++;
printf("%c",*a);
}
Explanation: I was expecting that it would result in lvalue error.
But it is working with out any error and giving bc as output. Why is this incrementing array "a" is not an error?
If an array is passed to a function it decays to a pointer to the array's first element.
Due to this inside printd() the pointer a can be incremented and decremented, to point to different elements of the array a as defined in main().
Please note that when declaring/defining a function's parameter list for any type T the expression T[] is equivaltent to T*.
In question's specific case
void printd(char a[]);
is the same as
void printd(char * a);
The code below shows equivalent behaviour as the OP's code, with pa behaving like a in side printd():
#include <stdio.h>
int main(void)
{
char a[100];
a[0]='a';a[1]='b';a[2]='c';a[4]='d';
{
char * pa = a;
pa++;
printf("%c", *pa);
pa++;
printf("%c", *pa);
}
return 0;
`}
In C language array declaration in function parameter list and array declaration outside of function parameter list mean completely different things, even though they look similar (or the same) on the surface.
When you use array declaration in function parameter list (as is the case with void printd(char a[]) in your code), you are not declaring an array. The top-level [] syntax in function parameter list is just an alternative form of pointer declaration. This means that your a parameter is actually declared as char *a. It is not an array at all, it is an ordinary pointer. There's nothing unusual in being able to increment such a, and this is why you are not getting any "lvalue errors" from it.
Meanwhile, your a in main is a true array.
An array is passed to a function as a pointer, which can be incremented.
So, in your example, it is not possible to increment a within the main() function, since a is an array and cannot be incremented.
However, not withstanding the syntax, the a within the printd() function is a pointer, so can be incremented. Incrementing a inside printd() does not affect the array a inside main() - although they have the same names, they are different entities within different scopes.
Why is this incrementing array "a" is not an error?
In C arrays are passed as a pointer to any function. Thats why you get no error.
The function calls in main() pass the name of the array, a, as an argument because the name of an array in an expression evaluates to a pointer to the array. In other words, the expression, a, is a pointer to (the first element of) the array, a[]. Its type is, therefore, char *, and a called function uses this pointer (passed as an argument) to indirectly access the elements of the array.
Now as you receive the address of the first element of a, a++ means ahead the array's initial address by 1. That's why the first printf prints b, the second element of array a.
a also works as a pointer. It is a pointer to the first element of the array. The a++ increments that pointer. That is, after a++ the a[0] or *a now gives you what a[1] gave you prior to the increment, that is 'b'.
Note that you do not increment the value of a[0] from 'a' to 'b'. Check that if you use different values in your array, like 'a, 'd', 'h', 'x'.

Pass and modify single row of a 2D array in C [duplicate]

This question already has answers here:
Create a pointer to two-dimensional array
(10 answers)
Closed 9 years ago.
First of all I'm not confident with C, but I have a 2D array of int and I want a function to write all the values of a single line of this array.
For example:
int main(int argc, char *argv[])
{
int a[2][2];
a[0][0] = 1;
a[0][1] = 2;
a[1][0] = 3;
a[1][1] = 4;
change_array(&a[0]);
}
void change_array(int* array[])
{
(*array)[0] = -1;
(*array)[1] = -1;
}
The program crash immediately. I tried to change the change_array function to array[0] = -1 and... it works! Values are changed correctly (and I don't know why because it should be totally wrong), but if I use this function in other part of the program the values of array remain unchanged.
How it could be possible? Any suggestion to successfully change the values of my array?
Thank you very much!
You can try to do it like this:
#include <stdio.h>
void change_array(int array[2][2])
{
array[0][0] = -1;
array[0][1] = -1;
}
int main(int argc, char *argv[])
{
int a[2][2];
a[0][0] = 1;
a[0][1] = 2;
a[1][0] = 3;
a[1][1] = 4;
printf("%d %d\n%d %d\n\n", a[0][0], a[0][1], a[1][0], a[1][1]);
change_array(a);
printf("%d %d\n%d %d\n\n", a[0][0], a[0][1], a[1][0], a[1][1]);
}
It depends on your needs, but in some cases I have found that it is better to use a single-diemensional array and build a getter/setter for 2 diemensions. Such solution can be found in this answer: Correct way to allocate and free arrays of pointers to arrays
Your code passes something to change_array that is different from the parameter declared for change_array.
In the code change_array(&a[0]), a is an array of two arrays of two int. So a[0] is the first array of two int. So &a[0] is the address of the first array of two int. Compare this with the declaration of change_array. In void change_array(int* array[]), array is an array of pointers to int. So that is a different type.
Instead, you could declare change_array with void change_array(int (*array)[]). Then array is a pointer to an array of int, and your code would work (using (*array)[0] = -1).
Note: You should compile with warnings enabled, and preferably with strict or pedantic language semantics. Then the compiler should have warned you that change_array is used in main without a prior declaration. You should have a prior declaration, so that the compiler knows the full type of change_array before it is used. With that, the compiler would have seen that the wrong type was passed, and it would warn you.
Although the above would correct your code, most people would use a different solution. They would declare change_array with void change_array(int *array), and they would call it with change_array(a[0]).
In change_array(a[0]), a[0] is the first array of two int. However, there is a rule in the C language that an array expression is converted to a pointer to its first element. So a[0] automatically becomes &a[0][0]. (This conversion occurs whenever the array is not the operand of &, sizeof, or _Alignof and is not a string literal used to initialize an array.) So the call is passing a pointer to int, which matches the parameter that is a pointer to int. Then the parameter array can be used as array[i] to access array elements, so you can use the simpler syntax array[0] = -1 instead of (*array)[0] = -1.
In C, an array variable decays into a pointer to the memory address that contains the first element of the array, when it is passed as a parameter to a function. That is joined to the fact that all it's elements are placed in contigous memory. So C only needs to save the first position of the array (no matter how many dimensions it has) and will then be able to calculate, based on the indexes, what offset of the pointed memory it should access.
So, on your particular piece of code variable a points to the first element, which is a[0][0]. So, basically doing this:
change_array(&a[0]);
Is roughly (but not exactly) the same as doing:
change_array(a);
Now, knowing how arrays are passed in C, you should be able to deduce that, indeed, two dimensional arrays, when passed as parameters, actually contain on the access to their first coordinate a pointer to where the first element of the second coordinate is. So, when you do array[0] you're passing a pointer to the first element of the array under the first coordinate. and then when you do *(array[0]) you're actually accessing the first element of the second coordinate.
Here it is also important to add then that; since array variables decay into pointers, then all arrays in C are passed by reference, because you are passing a pointer. So all function calls that modify an array passed to them will do actual modifications.
Knowing this, then your function should be:
void change_array(int *array)
{
array[0] = -1;
array[1] = -1;
}
And then you can perform a call such as:
change_array(a[0]);
In order to modify the elements of the first array of a.
Now, as good practice in C, and in order to avoid segmentation faults, one would pass to the function along with the pointer, an integer saying the size of the array:
void change_array(int *array, int size);
And then always perform the access checking this bound.

Experimenting with pointers of arrays in C

I have an array a whose values I wish to modify through another function. This is the code that I have:
#include "stdlib.h"
#include "stdio.h"
void myfunc(int* );
int main() {
int *a, i;
a = (int*) calloc(10,sizeof(int));
myfunc(&a);
for (i=0; i<10; i++) printf("%d\n", a[i]);
return 0;
}
void myfunc(int* a) {
int i;
for (i=0; i<10; i++) *a[i] = i;
}
Obviously something is wrong with my syntax and I Was wondering if someone could lend me a hand :)
Thanks!
In the main function, you've got a pointer to an integer, a. Then you pass the address of this pointer to myfunc, but myfunc is expecting a pointer to an int, not a pointer to a pointer to an int. You need to change your call to myfunc to this:
myfunc(a);
But, you've also got a problem inside myfunc. You don't need to dereference a[i] since that indexes into an array a. These are (effectively) the same thing:
a[i]
and
*(a+i)
(This isn't 100%, I think, because in C pointers and arrays are not completely the same thing, so some expert C programmer can correct me)
You're probably just get a bit confused by the collection of syntax around pointers and arrays:
&a
*a
a[i]
*(a+i)
The first one is the address of a, the second dereferences a as a pointer, the third is an index into an array and the fourth is dereferencing a as a pointer with an offset.
You would only want to do this *(a[i]) if you had an array of pointers, not a pointer to an int.
you already declare "a" as a pointer when you say its type is "int*". Therefore, when you try and call your function "myfunc" you don't need to take the address of "a". This will make it a pointer to pointer or "int**". If you want to change the location of where a pointer is pointing, you might use that, but in your case where you just want to change the data it is pointing at, your myfunc is declared fine and you should just change the call of your function from:
myfunc(&a);
to
myfunc(a);
Also inside your function the "a" variable is already a pointer so to access an element in the array it is pointing to, you don't need to dereference it first. You should just use a[i] instead of *a[i].
It is enought to call myfunc(a) instead of myfunc(&a), then inside the function you use a[i] directly. By declaring myfunc(&a) you are passing an int ** that allow you to allocate the array from *inside the function and returning to the caller to use it.
You don't need *a[i] = i; you can just put a[i] = i; (and modify your function call as Felice pointed out).
Since a is int* , &a will be int**. So you should change your function signature to void myfunc(int** a);

Resources