Difference between pointer to pointer and pointer to 2d array - c

If I have a 2d array B defined as :
int B[2][3] = {{1,3,5},{2,4,6}};
Is int **p = B same as int (*p)[3] = B ?
int **f = B; printf("%d ",*f+1);
gives 5 as output while printf("%d ",*f) gives 1 as answer. Why
is that happening?
printf("%d ",**f);
returns a segmentation fault! Why?

No. int **p = B; is an error. (Both a compilation error, and a logical error). An int ** must point to an int *. However, there are no int * stored in B. B is a group of contiguous ints with no pointers involved.
int **f = B; must give a compilation error. The behaviour of any executable generated as a result is completely undefined.
See 2.
To explain why you might be seeing 1 and 5. (The C standard does not define this, but your compiler bulls on ahead anyway). Probably your compiler treats the line as
int **f = (int **)B;
Then the expression *f will read bytes from the storage of B (which actually hold ints) and pretend that those are the bytes that make up a pointer representation. This is further undefined behaviour (violation of strict-aliasing rules). Probably the result of this is that *f is a pointer to address 0x00000001.
Then you print a pointer by using %d, causing further undefined behaviour. You see 1 because your system uses the same method for passing int to printf as it does to pass int *.
When you add 1 to (int *)0x00000001, you get (int *)0x00000005, because incrementing a pointer means to point to the next element of that type.
When you dereference this pointer, it causes a segfault because that address is outside of your valid address space.

1) Is int **p = b same as int (*p)[3] = b ? - No. int **p = b is an error.
Because here int **p is a pointer to pointer to an integer, but int (*p)[3] is pointer to an array of 3 integers!
2) int **f = B; It is an error, May results in Undefined behavior!
3) printf("%d ",**f); - It is same as (2). int **f = B; is error, so Undefined behavior!
NOTE: To avoid this type of error enable some warning flags in compiler option and try!

Related

Reason for Segmentation fault vs returning random values with the following C code

Please explain (reason for the output) what happens as a result of running the two segments of code. Please explain their difference too. There are two versions of setArr(int, int) as explained below...
#include <stdio.h>
void setArr(int, int);
int *arr[10]; // array of 10 int pointers
int main(int argc, char *argv[]) {
int i;
setArr(0, 0);
setArr(1, 100);
setArr(2, 200);
setArr(3, 300);
setArr(4, 400);
for (i = 0; i < 5; i++)
printf("arr[%d]: %d\n", i, *arr[i]); /* should be 0,100, 200,300,400 */
return 0;
}
Versions of setArr
Version A
void setArr(int index, int v) {
int i = v;
*arr[index] = i;
}
Output: Segmentation fault (core dumped)
Version B
void setArr(int index, int v) {
int i = v;
arr[index] = &i;
}
Output:
arr[0]: 400
arr[1]: 32748
arr[2]: 32748
arr[3]: 32748
arr[4]: 32748
I presume the values from running Version B are just random values.
I am fairly new to pointers I have knowledge in Java, so please explain it as beginner friendly as you can :)
You are hitting a lot of undefined behavior scenarios, but I will explain what is likely happening.
arr is an array of 10 pointers to integers.
int * arr[10]; // array of 10 int pointers
And when declared as a global variable, all of those pointers are going to be zero-initialized - so hence, it's an array of 10 NULL pointers.
So this line in version A, is dereferencing the address at arr[index]:
* arr[index] = i;
Is effectively saying this:
*(NULL) = i;
And that will certainly crash consistently.
In Version B, you have it as:
int i = v;
arr[index] = &i;
So now you are correctly assigning a pointer to a slot in the array. However that address getting assigned is to a local stack variable, i, which goes out of scope as soon as the function returns. So when you print the value at that address, it's most certainly been clobbered from other calls writing on top of the stack. (Or technically this "undefined behavior" of accessing a memory address of a stack variable that has gone out of scope.)
Better:
void setArr (int index, int v){
arr[index] = malloc(sizeof(int));
*arr[index] = v;
}
The above allocates memory for the address that you want to copy that value into. You're on your own for how to free that memory.
Alternatively:
Just declare arr as an array of integers instead of pointers:
int arr[10];
void setArr (int index, int v){
arr[index] = v;
}
And then print normally without the * deference thing on arr.
printf("arr[%d]: %d\n", i, arr[i]);
Version A says "the contents of an undefined pointer equals i" - undefined behavior = crash. Basically you are trying to write to some unknown location in memory.
Version B says "Some pointer = some address" - still undefined behavior as &i goes out of scope, but it is still an address and so it "kind of works". Here you are writing to "good" memory locations, but reading from bad ones.
in first case, you have defined the "array of pointers" to integer. They are not integer pointers. Either you will have to allocate memory (preferably using melloc/calloc functions) before storing any value to them OR you can define the array of integer like this:
int (*a)[10]
The following link may show you some idea about it: Difference between *ptr[10] and (*ptr)[10]
In second case, you are saving the address of integer into integer pointer, which is ok, but int i is local variable to function setArr(). This will therefore, the value of int i will be dereferenced every time the function setArr() exits. Therefore you are getting undefined behavior for 2nd case. Either you can use static int i OR use global variable (not preferred) OR use pointer to integer assignment.

How to assign a value from an address to a pointer on the go?

Causes a segmentation fault:
int n;
int *variable = scanf("%d",&n);
printf("Printing :%d",*variable);
No problem:
int n;
scanf("%d",&n);
int *variable = &n;
printf("Printing :%d",*variable);
How to achieve the first one without the segmentation fault?
Assuming scanf was successful, it returns 1 (in general it returns the number of variables that were set).
In your second snippet you discard that (useful) information, and you are setting a pointer varaible to the address of n, which is perfectly valid. (If scanf returned 0 then n would be uninitialised, and the behaviour of your printf call undefined.)
In the first snippet you set a pointer to the int constant 0 or 1 depending on the return value of scanf. That's fine too, but the behaviour on dereferencing that pointer with
*variable
is undefined.
If you want to be flashy, and have a robust conversation with your code reviewer, you could use the expression separator operator and write
int n;
int *variable = (scanf("%d",&n), &n);
but that's naughty since, again, you discard the return value of scanf, and n could be uninitialised.
scanf("%d",&n); returns integer not pointer to integer. Below is the prototype of scanf.
int scanf(const char *format, ...);
When you point like below you are actually pointing to invalid address and it will lead to undefined behavior.
int *variable = scanf("%d",&n);
When you declare and initialize the pointer you assign the value to the pointer itself. The * is needed to show the compiler that you are declaring the pointer to the object of some type not the object itself
When you use the * later in the code you dereference that pointer.
void foo(void)
{
int a;
int *b = &a; //you assign the pointer `b` itself - no dereferencing
*b = 5; //you dereference the pointer and asssign the the referenced object
}
The "fresh" declared pointer (unless initialized with the reference to the valid object) does not point to the valid object and its dereferencing invokes the Undefined Behavior
void foo(void)
{
int a;
int *b = &a; //b is pointing to the valid object -> the variable `a`
int *c; //c is not pointing to valid object
int *d; //d is not pointing to valid object
c = malloc(sizeof(*c)); //now c is pointing to the valid object (if malloc has not failed of course)
*c = 5 // correct no UB
*d = 5; // incorrect - UB
*b = 5; //correct no UB
}
the syntax is similar (the * before the pointer name) but it does something completely different. I have noticed that it is a bit confusing for the beginners

Pointer with different type than the referenced variable

I am currently learning how to program in C. Today I started with pointers, and I encountered the following situation. When I compile the program
#include<stdio.h>
int main() {
int a;
double * p;
p = &a;
*p = 12.34;
printf("%d\n",a);
* (int *) p = 12.34;
printf("%d\n",a);
return 0;
}
it says
$ gcc zeigertypen.c
zeigertypen.c: In function ‘main’:
zeigertypen.c:7:7: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
and upon execution, I get the output
2061584302
Speicherzugriffsfehler (Speicherabzug geschrieben)
The error message is German for something like
memory access error (core dumped)
However, if I comment out the line *p = 12.34; the error disappears and the output is
0
12
The purpose of the code is to demonstrate the problem with pointers of different type than the variable they are referencing. According to the textbook I'm using to learn C++, the output should be
2061584302
12
The behaviour of p = &a; is actually undefined.
Neither C nor C++ allow you to re-interpret the type of &a (which is a pointer to int) as a pointer to a double.
(int*)p is similarly problematic, although by then the damage has been done.
You are allowed to cast to void*, and back to the original type from void*: for now, regard these as being the only cases where you can cast the type of a pointer to a different type.
Explaination with code: (Acc to your Textbook)
#include<stdio.h>
int main() {
int a; // size let say (2 byte or 4 )
double * p; // it will point to continous memory of 8 byte
p = &a; // Now because of this ,starting from first byte of a it will derefer 8 bytes (but Undefined behaviour acc to C standards)
*p = 12.34; // assigned to those 8 bytes
printf("%d\n",a); // first (2 or 4 ) bytes of that value in *p assignment as it starts from a
* (int *) p = 12.34; // now you type casted it to derefer 2 bytes so store 12 in those (2 or 4) bytes as int
printf("%d\n",a); // first (2 or 4) bytes of that value in *p assignment
return 0;
}
if you need more explaination comment and ask me . Thank you.

Variable initialization and pointer segfault

I was thinking about pointer initialization and tried the following two cases:
#include <stdio.h>
int main(int argc, char **argv)
{
int *d;
int f;
int p;
*d = 6;
printf("%d %d %d\n", *d, f, p);
return 0;
}
This code segfaults at the line (seen in gdb):
*d = 6;
Which makes sense because I am trying store a value at a random address.
I then tried the following:
#include <stdio.h>
int main(int argc, char **argv)
{
int *d;
int f = 10;
int p = 9;
*d = 6;
printf("%d %d %d\n", *d, f, p);
return 0;
}
This runs to completion with the output:
6 10 9
If only f is initialized to 10 (p is not initialized) or vice versa, the program still completes with output
6 10 0
or
6 0 9
(p initialized). I do not understand why this works. My initial guess is that the initialization of either f or p makes space or orients memory to allow for the safe initialization of d. I also thought about stack allocations, but am still unsure.
Your first problem is in *d = 6; as you're trying to to dereference an invalid pointer.
d is not initialized (allocated memory) and it points to an invalid memory location. Any attempt to dereference that will lead to undefined behavior.
FWIW, the second code also produces UB for the same reason.
Additionally, in the first code snippet, by writing
printf("%d %d %d\n", *d, f, p);
where f and p are uninitialized automatic local variable, you're trying to read indeterminate values, which again, produces UB. This is avoided in the second snippet by explicit initialization.
In your program -
*d = 6; // writing to an invalid memory location
You leave the pointer with uninitialized value. So when you dereference it (*d), you access unauthorized location in memory, resulting in a segmentation fault.
you also try to print uninitialized local variables-
printf("%d %d %d\n", *d, f, p); // where f and p are indeterminate
Therefore , your code invokes undefined behaviour and your program give output which literally can be anything.
This code segfaults at the line (seen in gdb):
*d = 6;
Which makes sense because I am trying to give random address to a
value.
It does make sense that that segfaults, but your explanation is grossly incorrect. You are not in any way giving / or assigning an address to a value. Rather, you are attempting to store a value at an unspecified address.
It is critically important to understand the difference between d and *d. The former (as you have declared it) is a pointer that is expected to hold the address of an int. The latter is the int that d points to. If d has not, in fact, been initialized to point to an int, then evaluating the expression *d produces undefined behavior.
Undefined behavior is exactly that -- undefined. You cannot expect a similar source of undefined behavior to produce the same actual behavior in other circumstances, and you cannot even rely on the behavior to manifest an obvious indication of brokenness. Anything can happen, including, in principle, what the programmer wanted to happen.
Declaring a pointer variable does not automatically cause any storage to be allocated. There are any number of ways you could initialize d, but one would be
d = &f;
You need to Allocate your memory with malloc()
this work:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int *d;
int f = 10;
int p = 9;
d = /*(int *)*/malloc(sizeof(int) * 1);
if (!d)
exit(-1);
*d = 6;
printf("%d %d %d\n", *d, f, p);
free(d);
return 0;
}

Pointer to array not functioning as expected

I am expanding my knowledge of arcane C usage, especially with strange pointer types. I found a site with some examples and I've been trying them out. However, after playing with some of these examples, I found some strange behaviour relating to a pointer to an array. Here is the code:
int test = 45;
int *testp = &test;
int (*p)[1];
p = &testp;
printf("%d\n", **p);
This code outputs 2686744 (which I can make no sense of). My logic is as follows: an array is just a glorified pointer. I can make a pointer and call it an array of 1 if I like. So when I create the pointer testp, I expect it to function as an array of 1 int. Furthermore, I would expect the line int (*p)[1]; to create an int** variable. However, there is something even worse about the whole thing. Here is a modified version of the above code:
int test[1] = {45};
int (*p)[1];
p = &test;
printf("%d\n", **p);
This outputs 45, as expected. So, my question is, what is the difference between these two snippets that causes the first to output garbage?
Thanks
This code snippet is invalid and shall not be compiled
int test = 45;
int *testp = &test;
int (*p)[1];
p = &testp;
printf("%d\n", **p);
The type of expression &testp is int ** while in the left side of the assignment there is an object of type int (*)[1]. There is no implicit conversion from one type to enother.
Nevertheless dereferencing p in the function call
printf("%d\n", **p);
that is *p will give array of type int[1] However the value stored in *p is the value of testp. Thus the only element of the array is the value stored in testp that is the address of test (provided that sizeof( int * ) is equal to sizeof( int ).
So the output of the function is the address of test.
The second code snippet is valid. *p is an array with one element and **P gives the value of the first element of the aray.

Resources