Different ways Asterisk (* operator) is used in C - c

So I know that the * operator is used for multiplication and as a pointer but sometimes I see the * operator and I am not sure what it means. Have a look at this code which defines a matrix
#ifndef MATRIX_H
#define MATRIX_H
/* The data structure representing a matrix */
typedef struct {
int rows; /* number of rows */
int columns; /* nuumber of columns */
int **content; /* matrix elements in a two dimensional array */
} matrix_t;
what does a double asterisk used for here?
I assume ** operator is used for pointers in 2d arrays but I am not sure.

Multiple indirection is a thing - you can have pointers to pointers, pointers to pointers to pointers, pointers to arrays of pointers, arrays of pointers to pointers, pointers to arrays of pointers to pointers to arrays of pointers to functions returning pointers, etc.
As used here, the intent is that you allocate an array of pointers:
matrix_t mat;
mat.content = calloc( 2, sizeof *mat.content );
which gives us
int ** int *
+---+ +---+
mat.content: | | ---> | | mat.content[0]
+---+ +---+
| | mat.content[1]
+---+
and then for each of those pointers, you allocate an array of int:
for ( size_t i = 0; i < rows; i++ )
mat.content[i] = calloc( 2, sizeof *mat.content[i] );
giving us
int ** int * int
+---+ +---+ +---+
mat.content: | | ---> | | mat.content[0] ---> | | mat.content[0][0]
+---+ +---+ +---+
| | mat.content[1] -+ | | mat.content[0][1]
+---+ | +---+
|
|
| +---+
+-> | | mat.content[1][0]
+---+
| | mat.content[1][1]
+---+
The expression mat.content has type int **, so the expression *mat.content has type int *; thus, sizeof *mat.content == sizeof (int *). Similarly, the expression mat.content[i] also has type int * (*p == p[0]), so *mat.content[i] has type int, so sizeof *mat.content[i] == sizeof (int).
Because of how array subscripting works, mat.content[i][j] works exactly the same way as if you had declared mat.content as a regular 2D array of int. It's just instead of all the rows being allocated in a single contiguous chunk, they're allocated piecemeal.
General rules:
T *p; // p is a pointer to T
T *ap[N]; // ap is an array of pointer to T
T (*pa)[N]; // pa is a pointer to an array of T
T *fp(); // fp is a function that returns pointer to T
T (*pf)(); // pf is a pointer to a function that returns T
T **p; // p is a pointer to a pointer to T
T ***p; // p is a pointer to a pointer to a pointer to T
const T *p; // p is a pointer to const T - you can write to p, but not *p
T const *p; // same as above
T * const p; // p is a const pointer to T - you can write to *p, but not to p
When used in an expression, the * "dereferences" the pointer - if you have a declaration like
int x;
int *p = &x;
the expression *p acts as kind of an alias for x:
*p = 10; // does the same thing as x = 10;
The object p stores the location of x, and the type of the expression p is int * (pointer to int). The expression *p is equivalent to the expression x - not only does it yield the value stored in x, you can write a new value to x through *p as shown above.
The declarations above give us this relationship:
p == &x // int * == int *
*p == x // int == int
The array subscript expression a[i] is defined as *(a + i) - given a starting address designated by a, offset i elements (not bytes!) from that address and dereference the result.
*p == *(p + 0) == p[0]
Arrays are not pointers, nor do they store a pointer to their first element. Unless it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted, or "decay", to an expression of type "pointer to T" and the value of the expression will be the address of the first element. This is important - if you declare an array
int a[10];
a does not store an address to its first element; instead, any time the compiler sees the expression a outside of the contexts listed above, it will basically replace it with something equivalent to &a[0].

Related

addressing with pointer in c languagge

I'm studying pointers in C language with Ted Jensen's "A TUTORIAL ON POINTERS AND ARRAYS IN C" manual. It's a very prickly argument.
Question 1. I have come to program 3.1 and would like a clarification. This is the program:
#include <stdio.h>
char strA[80] = "A string to be used for demonstration purposes";
char strB[80];
int main(void) {
char *pA;
char *pB;
puts(strA);
pA = strA;
puts(pA);
pB = strB;
putchar('\n');
while(*pA != '\0')
{
*pB++ = *pA++;
}
*pB = '\0';
puts(strB);
return 0;
}
Regarding the line pA = strA;, the book says "We then [point] the pointer pA at strA. That is, by means of the assignment statement we copy the address of strA [0] into our variable pA", which is what I don't understand.
To copy the address of strA[0] into our variable pA via the assignment declaration, shouldn't we write pA = & strA?
Question 2. The expression c = * ++ p; increases the value of p or the address of p?
Does the indirection operator (*) not indicate the value of the pointed variable?
To copy the address of strA [0] into our variable pA via the assignment declaration, shouldn't we write pA = & strA?
&strA is the address of strA. &strA[0] is the address of strA[0]. These are the “same” in the sense they point to the same place in memory, but they have different types, and the compiler would complain if we wrote pA = &strA when the type of pA is a pointer to the type of the elements of strA.
When we write pA = strA, the array strA is automatically converted to a pointer to its first element, so pA = strA is equivalent to pA = &strA[0].
Question 2: the expression c = * ++ p; increases the value of p or the address of p?
The C grammar organizes this as c = *(++p);, and ++p increases the value of p. If p is a pointer, it increases the value of that pointer. The * operator uses the increased value.
Be careful about speaking of the address of a pointer. The value of the pointer is an address, but you should not say that is the address of the pointer. The pointer is itself an object in memory, and so it has an address in memory where its value is stored. The address where a pointer is stored is different from the address stored in it. The “address of a pointer” is the address where the pointer is stored, not the value of the pointer.
It's simply because strA, which is char array, is a pointer.
An array's "value" is actually nothing more than the address of the first element of array.
When you assign address of primitive data type(int, char, etc..), you should assign it in the way you described.
int x;
int *pA;
pA = &x;
When you assign address of pointer data type(array, etc..), you should assign it without & operator, since the value is in itself the address.
int x[10];
int* pA;
pA = x;
Original code
#include <stdio.h>
char strA[80] = "A string to be used for demonstration purposes";
char strB[80];
int main(void)
{
char *pA; /* a pointer to type character */
char *pB; /* another pointer to type character */
puts(strA); /* show string A */
pA = strA; /* point pA at string A */
puts(pA); /* show what pA is pointing to */
pB = strB; /* point pB at string B */
putchar('\n'); /* move down one line on the screen */
while(*pA != '\0') /* line A (see text) */
{
*pB++ = *pA++; /* line B (see text) */
}
*pB = '\0'; /* line C (see text) */
puts(strB); /* show strB on screen */
return 0;
}
In C, when you write :
char strA[80];
Memory is allocated for your table. This is an example for you to try and visualize what it looks like.
[0] 1st Element
[1] 2nd Element
[2] 3rd Element
[....] ....
[n] nth Element
0000
0001
0002
0003
n
strA is a pointer to the address where your table starts in the memory (0000 in our example), which is the same as the address of its first element strA[0].
So when you write
pA = strA
you are actually copying the first element's address (0000 in our example) to pA
To copy the address of strA [0] into our variable pA via the assignment declaration, shouldn't we write pA = & strA?
Arrays are weird and don't behave like other types.
The expression strA "decays" from type "N-element array of char" to "pointer to char", and the value of the expression is the address of the first element. This "decay" doesn't happen when the array expression is the operand of the sizeof or unary & operators, so the expression &strA has type "pointer to N-element array of char", or char (*)[N], which is not the same as char *. The address value is the same (the address of an array is the same as the address of its first element), but the types are different.
Assuming the declarations
char str[N]; // for some size N
char *p;
when you write
p = str; // char * = char *
the expression str has type "N-element array of char"; however, since str is not the operand of the sizeof or unary & operators, it "decays" to type char * and evaluates to the address of the first element. It’s equivalent to writing
p = &str[0]; // char * = char *
There is a reason for this - C was derived from an earlier language named B, and in B array types had a dedicated pointer to the first element - when you declared an array in B like
auto a[N];
what you got in memory was
+---+
a: | | -------+
+---+ |
... |
+---+ |
| | a[0] <-+
+---+
| | a[1]
+---+
...
and the array subscript operation a[i] was defined as *(a + i) - given the starting address a, offset i elements from that address and dereference the result.
When he was designing C, Ritchie wanted to keep B's array behavior, but he didn't want to keep the explicit pointer that behavior required. When you declare an array in C like
int a[N];
what you get in memory is
+---+
a: | | a[0]
+---+
| | a[1]
+---+
...
Instead of setting aside space for an explicit pointer to the first element, the compiler replaces any occurrences of the expression a with a pointer to a[0]. So a[i] is still defined as *(a + i). Unfortunately, this means that arrays lose their "array-ness" under most circumstances and most of the time what you're dealing with is a pointer.
Question 2: the expression c = * ++ p; increases the value of p or the address of p?
This gets a little complicated. To answer as asked, it increases the value of p - it sets p to point to the next object in a sequence. This is probably better explained with a concrete example.
Assume the following declarations:
char str[] = "foo";
char *p = str;
then the following are true:
+---+
str: |'f'| str[0] <--- p
+---+
|'o'| str[1] <--- p + 1
+---+
|'o'| str[2] <--- p + 2
+---+
| 0 | str[3] <--- p + 3
+---+
p == &str[0] // char * == char *
*p == str[0] == 'f' // char == char == char
p + 1 == &str[1]
*(p + 1) == str[1] == 'o'
p + 2 == &str[2]
*(p + 2) == str[2] == 'o'
The result of the expression p + 1 is a pointer to str[1], the result of the expression p + 2 is a pointer to str[2], etc.
c = *++p; is roughly equivalent to writing
tmp = p + 1;
c = *tmp;
p = p + 1;
with the caveat that the updates to c and p can happen in any order - they may even be evaluated simultaneously (either interleaved or in parallel).
In this case, it means we assign the value of *(p + 1) ('o') to c, and update p to point to str[1], leaving us with this:
+---+
str: |'f'| str[0]
+---+
|'o'| str[1] <--- p
+---+
|'o'| str[2] <--- p + 1
+---+
| 0 | str[3] <--- p + 2
+---+
p == &str[1]
*p == str[1] == 'o'
p + 1 == &str[2]
*(p + 1) == str[2] == 'o'
p + 2 == &str[3]
*(p + 2) == str[3] == 0

Need to understand some pointers in C

Well, i have this simple example that we must use in school but i dont understand why we must use pointers and what they exactly do in same cases.
int **create(int lines, int columns)
{
int **p, i;
p = (int **) malloc(lines * sizeof(int *));
for(i = 0; i < lines; i++)
p[i] = (int *) malloc(columns * sizeof(int));
return p;
}
I google that ** is pointer to pointer. Simply pointer pointing to pointer that has stored address of variable. But WHY I should do that?
And then these two lines of code looks to have totally random pointers
p = (int **) malloc(lines * sizeof(int *));
p[i] = (int *) malloc(columns * sizeof(int));
Basically I understand that pointer is pointing to address of variable or something but don't know what is happening here. Please if can somebody explain it to me. Thanks for your time.
A pointer can also be understood as an array. You allocate some space with malloc, and you can set items with the [] operator, just like as arrays.
int* arr = (int*)malloc(sizeof(int)*3);
arr[1] = 5;
printf("%d", arr[1]); //output is 5
Pointers to pointers can be understood as two-dimensional arrays: You allocate space for the pointers, then allocate each pointer as an array.
int** arr = (int**)malloc(sizeof(int*) * 3);
for (int i = 0; i < 3; i++) {
arr[i] = (int*)malloc(sizeof(int) * 3); // each element is going to be an array of 3 integers
}
arr[2][2] = 4;
printf("%d", arr[2][2]); // 4
This function creates a matrix which is a two dimensional array.
An array is a sequence of elements stored contiguously in memory. With malloc we allocate a memory block that can be used as an array. We then hold a pointer to the block of elements. We can then use the notation a[i] to identify the ith element of the array whose address is stored in a.
The expression malloc(n * sizeof(int)); allocates a memory block with room for n integers. Note that it returns a pointer to an integer : int *.
When we create a two dimensional array, each row is an array allocated with the above instruction. n is replaced by the number of columns.
All the rows are then bundled together with an array of arrays. Remember that an array is of type int *. Thus an array of arrays has int * values as element. It's type is then int **.
The first malloc in your code allocates the array that will hold all the rows array. This is why its type is int **. Its byte size is lines time the byte size of an int *.
In the for loop, each row is instantiated and assigned to the corresponding element of the array p.
The pleasant thing of the returned two dimensional array is that you may then identify on of its elements by the expression a[i][j].
Note that there is a mistake in this code.
The for loop is for(i = 0; i < riadky; i++). riadky is an undefined variable. It's not the right variable name.
Now that you hopefully understand the code, could you find the correct variable name to put there ? You should be able to find it from my explanations.
Some pictures should help.
We start with the object p:
int **
+–––+
p: | |
+–––+
p has type int **, meaning it can store the address of an object of type int *.
For simplicity’s sake, we’ll assume both lines and columns are 2. So we start by dynamically allocating enough space for two objects of type int *, and store the address of the first of those objects into p:
int ** int *
+–––+ +–––+
p: | | ––––––> | |
+–––+ +–––+
| |
+–––+
The array subscript operation a[i] is defined as *(a + i) - given a starting address a, offset i elements (not bytes) from that address1 and dereference the result2. So the expression p[0] refers to the first element and p[1] the second:
int ** int *
+–––+ +–––+
p: | | ––––––> | | p[0]
+–––+ +–––+
| | p[1]
+–––+
Now, for each p[i], we allocate enough space for 2 int objects and assign the address of the first of each set into p[i]:
int ** int * int
+–––+ +–––+ +–––+
p: | | ––––––> | | p[0]-––> | | p[0][0]
+–––+ +–––+ +–––+
| | p[1]–+ | | p[0][1]
+–––+ | +–––+
|
| +–––+
+-> | | p[1][0]
+–––+
| | p[1][1]
+–––+
As for why you need to use multiple levels of indirection (**, ***, etc.)...
For any object E of type T, the expression &E evaluates to the address of that object, and the type of that expression is T * (pointer to T). If we repace T with a pointer type P *, then the type of &E is P **. IOW, the type of an object that holds the address of another object must have one more level of indirection than the pointed-to object.
Pointer arithmetic works in terms of objects, not bytes. If p has type int * and points to an int object, then p+1 points to the next int object immediately following, whether that object is 2, 4, or more bytes away.
”But everyone says arrays are not pointers, how is a an address?” Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type “N-element array of T” will be converted (“decay”) to an expression of type “pointer to T” and the value of the expression will be the address of the first element.

What does double pointer mean and malloc of size of pointer date type

int **matrix, i, j;
matrix = malloc(5 * sizeof(int*));
*matrix = malloc(20 * sizeof(int));
I just don't understand the concept of double pointers and how this translates to a two-dimensional array ( that is if it's true )
Thanks in advance.
What is being created here is not technically a 2D array but an array of pointers, each of which would contain the starting address of an array. This can then be indexed as if it were a "real" 2D array.
This line creates an array of 5 pointers to int:
matrix = malloc(5 * sizeof(int*));
The next line creates a single array 20 int:
*matrix = malloc(20 * sizeof(int));
This however is incomplete in terms of a 2D array because only one row was allocated. You need to loop through every element that matrix points to in order to create each row:
int **matrix, i;
matrix = malloc(5 * sizeof(int*));
for (i=0; i<5; i++) {
matrix[i] = malloc(20 * sizeof(int));
}
When you're done using this dynamic 2D array, you'll need to free the memory in the reverse order:
for (i=0; i<5; i++) {
free(matrix[i]);
}
free(matrix);
This differs from a real 2D array in a few ways. First, in a true 2D array all elements are contiguous in memory, where in this case the array of pointers and each row array are not.
The other difference is when being passed to a function you can't pass it the same way you'd pass a real 2D array.
For a simple 1D array, whether allocated at compile time or dynamically:
int a1[5];
int *a2 = malloc(5 * sizeof(int));
Both can be passed to a function like this:
void f(int *a);
But in the case of a 2D array:
int a[5][20];
It would need to be passed to a function like this:
void f(int a[5][20]);
Or equivalently:
void f(int (*a)[20]);
Whereas a dynamic 2D array needs to be passed to a function like this:
void f(int **a);
Some pictures might help.
Let's start with matrix, which is a pointer to pointer to int:
int **
+--------+
| matrix |---???
+--------+
After the first call to malloc, you have the following:
int ** int *
+--------+ +-----------+
| matrix |--->| matrix[0] |
+--------+ +-----------+
| matrix[1] |
+-----------+
| matrix[2] |
+-----------+
| matrix[3] |
+-----------+
| matrix[4] |
+-----------+
You've dynamically allocated space for 5 int * objects, and matrix points to the first one. After the second call to malloc, you have this (the expression *matrix is equivalent to matrix[0] - more on that below):
int ** int * int
+--------+ +-----------+ +---------------+
| matrix |--->| matrix[0] |--->| matrix[0][0] |
+--------+ +-----------+ +---------------+
| matrix[1] | | matrix[0][1] |
+-----------+ +---------------+
| matrix[2] | | matrix[0][2] |
+-----------+ +---------------+
| matrix[3] | ...
+-----------+ +---------------+
| matrix[4] | | matrix[0][19] |
+-----------+ +---------------+
You've dynamically allocated space for 20 int objects, and matrix[0] points to the first one.
So, in short - each matrix[i][j] is an int. Each matrix[i] points to matrix[i][0], so each matrix[i] must be a pointer to int, or int *. matrix points matrix[0], meaning matrix must be a pointer to int *, or int **.
Remember that the array subscript expression a[i] is defined as *(a + i) - given an address a, offset i elements (not bytes!) from that address and deference the result. Thus, *matrix is equivalent to *(matrix + 0), which is equivalent to matrix[0].
Now, what you have here is not a true 2D array - you have a sequence of pointers, each of which may point to the first of a sequence of int objects (or to nothing at all). The "rows" of the array will (most likely) not be adjacent in memory. In a true 2D array, all array elements will be contiguous. Given
int matrix[5][20];
elements will look like this:
+---------------+
| matrix[0][0] |
+---------------+
| matrix[0][1] |
+---------------+
...
+---------------+
| matrix[0][19] |
+---------------+
| matrix[1][0] |
+---------------+
| matrix[1][1] |
+---------------+
...
+---------------+
| matrix[4][19] |
+---------------+
EDIT
Some other key differences between a pointer-to-pointer and a 2D array. First, assume the following definitions:
int **ptr;
int matrix[ROWS][COLS];
The expression ptr has type int **. The expression matrix will "decay" from type int [ROWS][COLS] to type int (*)[COLS] (pointer to COLS-element array of int);
sizeof ptr gives the size of the pointer itself (4, 8, or some other number of bytes). sizeof matrix gives the size of the entire array in bytes (ROW * COLS * sizeof (int)).
The expressions &matrix, matrix, &matrix[0], and &matrix[0][0] will all yield the same value (the address of the first element of the array), although the types of the expressions will be different - int (*)[ROWS][COLS], int (*)[COLS], int (*)[COLS], and int *, respectively. The expressions &ptr, ptr, &ptr[0], and &ptr[0][0] will not all yield the same values - &ptr and &ptr[0][0] will be different values than ptr and &ptr[0], and the types of the expressions will be int ***, int **, int **, and int *.
I think you want the following:
int **matrix, i, j;
matrix = malloc(5 * sizeof(int*));
for (int i=0; i<5; i++)
matrix[i] = malloc(20 * sizeof(int));
Here you first allocate an array of pointers to rows. Then you allocate memory for each row.

Pointer to pointer assigned to a two-dimensional array, points to wrong address

I'm new to C and although I thought I pretty much got the whole logic concerning pointers and arrays I've come across an issue that doesn't make any sense to me.
Consider a 2D array, say
double arr[][3] = { {1,2,3}, {4,5,6} };
and a pointer to a pointer
double ** ptrptr;
Now, let's say printing the address that arr and arr[0] point to, respectively, i.e.
printf( "%ld \n", (long) arr);
printf( "%ld \n", (long) *arr);
yields something like
140734902565640
140734902565640
since the first element of arr(array of arrays) and the first element of *arr(array of doubles) have the same location. So far so good. Now to my problem:
I do this:
ptrptr = (double **) arr;
printf( "%ld \n", (long) ptrptr);
printf( "%ld \n", (long) *ptrptr);
and I would expect the same output as before, but instead I get something like
140734902565640
4607182418800017408
So it seems that ptrptr and arr both evaluate to a pointer to the same location - as expected - but *ptrptr and *arr do not. Why?
Also, if I dereference once more, i.e. **ptrptr, I get a segmentation fault.
My logic went sth. like this, loosely speaking:
ptrptr == arr == &arr[0] should point to
*ptrptr == *arr == arr[0] == &arr[0][0] which in turn should point to
**ptrptr == *arr[0] == arr[0][0].
Although I found a workaround that will serve my purpose, I would still really like to understand why this doesn't work.
Let's talk about expressions and types.
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" is converted ("decays") to an expression of type "pointer to T", and the value of the expression is the address of the first element of the array.
The expression arr has type "2-element array of 3-element array of double". In the line
printf( "%ld \n", (long) arr);
arr is not the operand of the & or sizeof operators, so it is converted to an expression of type "pointer to 3-element array of double", and its value is the address of the first element, or &arr[0].
In the line
printf( "%ld \n", (long) *arr);
since the expression arr has type "pointer to 3-element array of double", the expression *arr (which is equivalent to the expression arr[0]) has type "3-element array of double". Since this expression isn't the operand of the sizeof or unary & operators, it is converted to an expression of type "pointer to double", and its value is the address of the first element, or &arr[0][0].
In C, the address of the array is the same as the address of the first element of the array (no separate storage is set aside for a pointer to the first element; it is computed from the array expression itself). The array is laid out in memory as
+---+
arr: | 1 | 0x0x7fffe59a6ae0
+---+
| 2 | 0x0x7fffe59a6ae8
+---+
| 3 | 0x0x7fffe59a6aec
+---+
| 4 | 0x0x7fffe59a6af0
+---+
| 5 | 0x0x7fffe59a6af8
+---+
| 6 | 0x0x7fffe59a6afc
+---+
So the following expressions will all yield the same value, but the types will be different:
Expression Type Decays to
---------- ---- ---------
arr double [2][3] double (*)[3]
&arr double (*)[2][3] n/a
*arr double [3] double *
arr[i] double [3] double *
&arr[i] double (*)[3] n/a
*arr[i] and arr[i][j] both yield a double value.
So now let's look at ptrptr:
double **ptrptr = (double **) arr;
printf( "%ld \n", (long) ptrptr);
printf( "%ld \n", (long) *ptrptr);
The first thing that we notice is that ptrptr is not an array expression, so the conversion rule above doesn't apply. We assign it to point to the first element of arr, but after that it behaves like any other pointer, so the expressions ptrptr and *ptrptr will have different values. Since ptrptr points to the first element of the array (&arr[0][0]), *ptrptr yields the value stored at the first element, which is 1.00. Just so happens that when you interpret the bit pattern for 1.00 as a long integer on this particular platform, it comes out as 4607182418800017408.
Here's some code that may make the above a little more clear:
#include <stdio.h>
int main( void )
{
double arr[][3] = {{1,2,3},{4,5,6}};
double **ptrptr = (double **) arr;
printf( " arr: %p\n", (void *) arr );
printf( " &arr: %p\n", (void *) &arr );
printf( " *arr: %p\n", (void *) *arr );
printf( " arr[0]: %p\n", (void *) arr[0] );
printf( "&arr[0]: %p\n", (void *) &arr[0] );
printf( " ptrptr: %p\n", (void *) ptrptr );
printf( "*ptrptr: %p (%f %ld)\n", (void *) *ptrptr,
*(double *) ptrptr, *(long int *) ptrptr );
return 0;
}
And here's the output:
arr: 0x7fffe59a6ae0
&arr: 0x7fffe59a6ae0
*arr: 0x7fffe59a6ae0
arr[0]: 0x7fffe59a6ae0
&arr[0]: 0x7fffe59a6ae0
ptrptr: 0x7fffe59a6ae0
*ptrptr: 0x3ff0000000000000 (1.000000 4607182418800017408)
Again, *ptrptr gives us the value at the first element of the array, which is 1.0, but we're interpreting that bit pattern as a pointer value (0x3ff0000000000000) and a long integer (4607182418800017408).
The difference is most clearly illustrated with a diagram.
This is a normal 2D array in C, double[4][3].
+---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
This is a double pointer in C, double **. It is pointing to the head of a double *[4], each of which points to the head of a double[3].
+----------+ +---+ +---+---+---+
| +---->| +------>| | | |
+----------+ +---+ +---+---+---+
| +-----+
+---+ | +---+---+---+
| +---+ +>| | | |
+---+ | +---+---+---+
| +-+ |
+---+ | | +---+---+---+
| +-->| | | |
| +---+---+---+
|
| +---+---+---+
+---->| | | |
+---+---+---+
Notice that the syntax for accessing elements is the same.
double arr[4][3];
arr[1][2] = 6.28;
double **ptr = ...;
ptr[1][2] = 6.28;
However, what is actually happening is quite different. So you cannot simply cast one type to the other.
With the double[4][3], you find an element by doing a little bit of math to calculate the offset.
With the double **, you find an element by following a chain of pointers.
An array can be seen as a "label":
Unlike a pointer, it doesn't have an lvalue, and you cannot set it to a different value after declaring it.
Try arr = ptrptr or arr = (double**)0x80000000, and you'll get a compilation error.
That is why, for any type of array arr, the following is always true: arr == &arr.
In addition, please note the memory-map differences:
double arr[3][3]; // A consecutive piece of 9 `double` units.
double** ptrptr // 1 pointer unit.
ptrptr = new double*[3]; // A consecutive piece of 3 pointer units.
for (int i=0; i<3; i++)
ptrptr[i] = new double[3]; // 3 separate pieces of 3 consecutive `double` units.
So not only does ptrptr consume an additional amount of 4 pointer units in comparison with arr, but it also has the 9 double units allocated in 3 separate sections in memory.
Hence arr = &arr = &arr[0] = &arr[0][0], but ptrptr != *ptrptr != **ptrptr.

Why does this code using pointers not retrieve the value of x using b?

#include <stdio.h>
int main (){
int x=10,*a=&x;
int *b=(int *)&a;
printf("%d %d %d %d %d %d ",x,a,*a,b,*b,**b);
return 0;
}
In this little program variable x is assigned value 10 and then address of x is assigned to pointer variable a. Now proper way is int **b=&a because b should be a pointer to pointer. But I thought it's ultimately the address which gets stored. So to store address of a to an int pointer b, I use typecasting int *b=(int *)&a. Now address of a got stored in b. So if I use *b, it give identical result as a.
But when I extend this further to **b it doesn't give the same result as *a which I expected. In fact it gives an error. *b and a are same so when i ask to retrieve from this value like **b and *a this doesn't work. For this I assumed a concept that *b and a are same in value but they are different in type. The value given by a is pointer and value given by *b is an integer so **b is not possible like *a.
But I still think that it should work.
I am using Dev C++ 4.9.9.2 which is a 32 bit compiler. The memory allocated to an int and int * is the same, that is 4 bytes. And *b and a have same bit representation also. So when I write *(*b) I used same value as in *(a). But what is the preventing factor? The format is like *(some bit representation) and the bit representation is identical in case of *b and a. So the value of x should be retrieved. Please explain the preventing factor.
It seems to work fine for me, once your variable declarations are cleaned up a bit:
int main (){
int x = 10;
int* a = &x;
int** b = &a;
printf("%d %d %d %d %d %d ",x,a,*a,b,*b,**b);
return 0;
}
I'd suggest that the problem is that you declared b with the wrong type (and then cast &a into that type). It is not an int*, it is an int**, i.e. a pointer to a pointer to an integer. You could of course cast *b to the desired type in your printf() statement, but why not just declare it correctly in the first place?
Here's an ideone example: http://ideone.com/idwfd
int x= 10;
int *a = &x; //address of x is 0x33
Int * b = (int *) &a; //address of a is 0x34
So from the above we have that:
x = 10 a = 33
*a = 10 b = 34
*b = 33
* (int *) *b = 10
**b would result in a compilation error
*b is an integer, and you're not allowed to apply the unary * to an integer. (How would the compiler know whether you expected the bit pattern to point to an int, char, short, or whatever?) You can cast the integer back to a pointer and then deference it: *(int*)*b, which should do what you expect.
Let's look at what happens here. a is a pointer to int. We take the address of a, which is a pointer to pointer to int, cast that to a pointer to int, and assign it to b.
Then we dereference b twice. b is a pointer to int, so *b is an int. Then we dereference an int. Wait, you can't dereference an int - it's not a pointer. And so we enter the twilight zone of undefined behavior.
**b would point to the correct block of memory, but the compiler doesn't have the proper type information. #Henning says, dereferencing b once is an int value according to the compiler, and there's no dereference operator for type int. That's specifically why the int** and its ilk exist: to tell the compiler how many dereferences are possible/necessary.
Out of curiosity is there a reason int* b = a; doesn't work, if you do want the value of x after one dereference?
+----------+ +----------+ +----------+
| 10 | | addr_x | | addr_a |
+----------+ +----------+ +----------+
| x | | a | | b |
+----------+ +----------+ +----------+
| addr_x | | addr_a | | addr_b |
+----------+ +----+-----+ +----+-----+
^ ^ | ^ |
| +----(*a)-------+ +----(*b)---+
| |
+----------------(**b)-------------+
The access is like above.
You have told the compiler that the pointer b is a pointer to an integer. When you do *b it dereferences to an int and another indirection is not possible on type of int and therefore when you accessbit as a pointer to a pointer to an integer in (**b). It is not allowed. To do so you need to typecast the value ofb` to the correct type and use it.
You want to use the value of *b as an address and fetch the int value stored at the address location *b. Therefore You want *b to be an int * which makes b an (int **) . Therefore it is best to declare b as int **b; . In your case before applying the double indirection typecast b to be int ** and then use double indirection.
printf ("%x", **((int **)b));
This will interpret the value stored in b as a pointer to a pointer to an integer and then fetch the value of x as you want.

Resources