C assigning the address of a 2D array to a pointer - c

I was reading through some lecture notes that in order for a pointer to reference a 2D array, it has to be given the address of the first element.
int a[10][10];
int *p = &a[0][0];
I've never tried this, so I was curious why isn't it enough to assign the array itself to the pointer, just as we do in a 1D case.
int a[10][10];
int *p = a;
The array is kept in an uninterrupted 'line' of memory anyway, and 2D arrays only have a different type, but the same structure as 1D arrays.
By doing this
int *p = &a[0][0];
I don't see how we give the pointer any more information than by doing this
int *p = a;
Or maybe all arrays regardless of their number of dimensions have the same type, the only difference being that multidimensional arrays store their extra dimensions before their first element and we need to jump over those memory spaces which remember sizes of an array's dimensions?

First, some background:
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" 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 of the array.
Given the declaration
int a[10][10];
the expression a has type "10-element array of 10-element array of int". Unless this expression is the operand of the sizeof or unary & operators, it will be converted to an expression of type "pointer to 10-element array of int", or int (*)[10].
Given that declaration, all of the following are true:
Expression Type Decays to
---------- ---- ---------
a int [10][10] int (*)[10]
&a int (*)[10][10]
*a int [10] int *
a[i] int [10] int *
&a[i] int (*)[10]
*a[i] int
a[i][j] int
&a[i][j] int *
Also,
sizeof a == sizeof (int) * 10 * 10
sizeof &a == sizeof (int (*)[10][10])
sizeof *a == sizeof (int) * 10
sizeof a[i] == sizeof (int) * 10
sizeof &a[i] == sizeof (int (*)[10] )
sizeof *a[i] == sizeif (int)
sizeof a[i][j] == sizeof (int)
sizeof &a[i][j] == sizeof (int *)
Note that the different pointer types int (*)[10][10], int (*)[10], and int * don't have to be the same size or have the same representation, although on the platforms I'm familiar with they do.
The address of the first element of the array is the same as the address of the array itself; thus, all of a, &a, a[0], &a[0], and &a[0][0] will yield the same value, but the types will be different (as shown in the table above).
So, assume we add the following declarations:
int *p0 = &a[0][0]; // equivalent to int *p0 = a[0];
int (*p1)[10] = &a[0]; // equivalent to int (*p1)[10] = a;
int (*p2)[10][10] = &a;
All of p0, p1, and p2 initially have the same value, which is the address of the first element in a; however, because of the different pointer types, the results operations involving pointer arithmetic will be different. The expression p0 + 1 will yield the address of the next int object (&a[0][1]). The expression p1 + 1 will yield the address of the next 10-element array of int (&a[1][0]). And finally, the expression p2 + 1 will yield the address of the next 10-element array of 10-element array of int (effectively, &a[11][0]).
Note the types of p1 and p2; neither is a simple int *, because the expressions being used to initialize them are not that type (refer to the first table).
Note the pattern; for an array type, the simpler the expression, the more complicated the corresponding type will be. The expression a does not refer to a single int object; it refers to a 10x10 array of int objects, so when it appears in an expression, it is treated as a pointer to an array of integers, not a pointer to a single integer.

The compiler knows that "a" is a pointer to ten integers. If you don't declare the dimensions, then the compiler sees the new pointer as a pointer to an unknown number of integers. This will work in your case, but it will generate a compiler warning because the compiler sees them as incompatible pointers. The syntax for what you are trying to do (without generating a compiler warning) is:
int a[10][10];
int *p1 = &a[0][0];
int (*p2)[10] = a;
printf("p1: %p p2: %p\n", p1, p2);
One reason this is important is pointer arithmetic:
p1++; //move forward sizeof(int) bytes
p2++; //move forward sizeof(int) * 10 bytes

You understanding is close, the difference is the type information. Pointer does has its type. For example int* p, the pointer type is int*, as int a[10][10], the corresponding pointer type is int *[10][10].
In your example, p and a do point to the same address, but they're different type, which matters when perform arithmetic operation on them.
Here's an example from this URL
Suppose now that we define three pointers :
char *mychar;
short *myshort;
long *mylong;
and that we know that they point to the memory locations 1000, 2000, and 3000, respectively.
Therefore, if we write:
++mychar;
++myshort;
++mylong;
mychar, as one would expect, would contain the value 1001. But not so obviously, myshort would contain the value 2002, and mylong would contain 3004, even though they have each been incremented only once. The reason is that, when adding one to a pointer, the pointer is made to point to the following element of the same type, and, therefore, the size in bytes of the type it points to is added to the pointer.

You are right, you can assign the array itself to the pointer:
int a[10][10] = {[0][0]=6,[0][1]=1,[1][0]=10,[1][1]=11};
int b[10][10][10] = {[0][0][0]=8,[0][0][1]=1,[0][1][0]=10,[1][0][0]=100};
int *p, *q, *r, *s;
p = &a[0][0];
q = a; // what you are saying
r = &b[0][0][0];
s = b; // what you are saying
printf("p= %p,*p= %d\n",p,*p);
printf("q= %p,*q= %d\n",q,*q);
printf("r= %p,*r= %d\n",r,*r);
printf("s= %p,*s= %d\n",s,*s);
And the output is:
p= 0xbfdd2eb0,*p= 6
q= 0xbfdd2eb0,*q= 6
r= 0xbfdd3040,*r= 8
s= 0xbfdd3040,*s= 8
They point to the same address, regardless of the dimension of the matrix. So, what you are saying is right.

Well in 2D array, the outcome of *a and a is the same, they all point to the first address of this 2D array!
But if you want to define a pointer to point to this array, you could use int (*ptr)[10] for example.
You are right, 1D and 2D share the same structure, but 2D has some additional manipulation on pointers like above.
So all in all, in 2D array, a, *a and &a[0][0] prints the same address, but their usages may vary.
Like this:
#include<stdio.h>
int main() {
int a[10][10];
int *pa1 = &a[0][0];
int *pa2 = *a;
printf("pa1 is %p\n", pa1);
printf("pa2 is %p\n", pa2);
printf("Address of a is %p\n", a);
// pointer to array
int (*pa3)[10];
pa3 = a;
printf("pa3 is %p\n", pa3);
return 0;
}
They print the same address.

Related

the size of distance between two pointers

void main() {
int a = 2;
int *p = &a;
int *q = p++;
printf("%d %d\n", p, q);
int b = p - q;
printf("%d", b);
}
Why does it print 1? I've tried with other pointers but didn't succeed. I thought it would print the size of int because the distance between them is 1 * sizeof(int) but it prints 1.
why it prints 1?
Because C specifies pointer subtraction as the difference in the indexes (subscript) of the array, not the difference in address values.
1 past the object is like the an array element after the int a;
For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type. C17dr § 6.5.6 7
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. § 6.5.6 8
Subscript 1 - subcript 0 --> 1.
The result is 1 even if int a was char a or long double a.
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
To output pointers you have to write
printf("%p %p\n", ( void * )p, ( void * )q);
In the initializer of the pointer q
int* q = p++;
there is used an expression with the postfix increment operator. Its value is the value of the operand before incrementing.
So the pointer q is initialized by the address of the variable a and as a side effect the pointer p is incremented and points to the memory after the object a. That is between the addresses (in the extent of memory bounded by these addresses) stored in the pointers p and q there is stored only one object a. So according to the pointer arithmetic the result of the expression p - q is 1.
On the other hand, the difference between the addresses stored in the pointers p and q is equal to the value of sizeof( int ) that is to the value of sizeof( a ).
If you will write for example
int b = ( char * )p - ( char * )q;
then the value of b will be equal to sizeof( a ) because in this case the memory occupied by the variable a is interpreted as a character array and sizeof( char ) is always equal to 1.
There are a few errors in this code:
The return type of main() should be int instead of void.
The printf() statement has two integer format specifiers, but the arguments passed are pointers, which are not guaranteed to have the same size as integers. Therefore, using the %d format specifier to print pointers is not correct. You can use the %p format specifier to print pointers.
The variables p and q are pointers to int, so the difference between them (i.e., p - q) should be divided by the size of int to get the number of elements between them.
Here is the corrected code:
#include <stdio.h>
int main() {
int a = 2;
int* p = &a;
int* q = p++;
printf("%p %p\n", p, q);
int b = (p - q) / sizeof(int);
printf("%d", b);
return 0;
}
This code will print the memory addresses of p and q, followed by the difference between them in terms of the number of int elements.

How is `int (*arr1)[10]` different from `int arr2[10]`?

As I was going though some code examples, I encountered this way of declaration:
int (*arr1)[10]
I am aware of another way of array declaration in C:
int arr2[10]
Is int (*arr1)[10] doing the same as int arr2[10]?
The differences are as follows:
int (*arr1)[10]; // arr1 is a pointer to a 10-element array of int
int *arr2[10]; // arr2 is a 10-element array of pointer to int
This is important - despite the [10] at the end, arr1 is not an array; it only stores a single pointer value, which is the address of some 10-element array of int.
Pointers to arrays crop up in two main circumstances - when an N-dimensional array expression "decays" to a pointer expression, and when we're allocating memory for an N-dimensional array.
First, the decay rule - except when it is the operand of the sizeof or the 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 of the array. You've probably seen this before with code like:
int arr[10];
int *p = arr; // arr "decays" to a pointer to its first element
The expression arr "decays" from type "10-element array of int" to type "pointer to int".
The exact same thing happens with 2D arrays:
int arr[5][10];
int (*p)[10] = arr;
The expression arr "decays" from type "5-element array of 10-element array of int" to type "pointer to 10-element array of int".
You can also obtain a pointer to a 1D array directly with the unary & operator:
int arr[10];
int (*p)[10] = &arr; // note presence of & operator here
but that's not very common.
Another use for pointers to arrays is when we want to dynamically allocate a contiguous 2D (or higher-dimensioned) array:
int (*p)[10] = malloc( sizeof *p * 5 ); // allocates space for a 5x10 array of int
The type of the expression *p is "10-element array of int", or int [10], so sizeof *p is equivalent to sizeof (int [10]), so the malloc call sets aside enough space for 5 10-element arrays of int. You would index into this array like any other 2D array: p[i][j] = some_value();. The rows of this array are contiguous in memory and all the same length, and it only requires a single call to free to deallocate.
You've probably seen code that dynamically allocates 2D arrays in multiple steps - first you allocate an array of pointers, then for each of those pointers you allocate an array of the target type, like so:
int **p = malloc( sizeof *p * R ); // allocates an R-element array of pointer to int
if ( p )
{
for ( size_t i = 0; i < R; i++ )
{
p[i] = malloc( sizeof *p[i] * C ); // allocates a C-element array of int
}
}
The difference here is that in the second case, the rows are not adjacent in memory - it's not a single, continuous block. Also, different rows may be different lengths (what's sometimes called a "jagged" array). You also have to free each row separately before freeing p.
The basic rules of pointer declarations are:
T *p; // p is a pointer to T
T *a[N]; // a is an array of pointer to T
T *f(); // f is a function returning pointer to T
T (*a)[N]; // a is a pointer to an N-element array of T
T (*f)(); // f is a pointer to a function returning T
T const *p; // p is a non-const pointer to const T - you can modify p to point
// to a different object, but you cannot modify the thing p points to
const T *p; // same as above
T * const p; // p is a const pointer to non-const T - you can modify what p
// p points to, but you can't modify p to point to a different object
// (which means p needs to be initialized to a valid pointer value
// when it's declared).
T const * const p; // p is a const pointer to const T - you can't update either
// p or *p
const T * const p; // same as above.
If in this specification
int (*arr1)[10]
you will remove the term in the parentheses you will get int[10]. The term in the parentheses denotes a pointer. So you have a pointer to an array of 10 elements of the type int. For example
int a[10];
int ( *arr )[10] = &a;
Dereferencing the pointer you will get the array (the object of the array type pointed to by the pointer) itself.
Here is a demonstrative program.
#include <stdio.h>
int main(void)
{
enum { N = 10 };
int a[N] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int ( *arr )[N] = &a;
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ", ( *arr )[i] );
}
putchar( '\n' );
return 0;
}
The program output is
0 1 2 3 4 5 6 7 8 9
Instead of these declarations you could use declarations based on a typedef like
enum { N = 10 };
typedef int Array[N];
Array a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Array *arr = &a;

Pointer to an entire array

I stumbled upon "pointer to the entire array" and wrote a test program to clear some things out:
#include <stdio.h>
int main(){
int x[5] = {1, 2, 3, 4, 5};
int *a = x; // points to the 1st array element
int (*b)[5] = &x; // points to the 1st addres of the stream of 5 int elements
int (*c)[5] = x; // points to the 1st addres of the stream of 5 int elements
printf("%p\n%p\n%p\n\n",
(void *)a,
(void *)b,
(void *)c
);
++a;
++b;
++c;
printf("%p\n%p\n%p\n\n",
(void *)a,
(void *)b,
(void *)c
);
return 0;
}
This outputs:
0x7ffed0c20690
0x7ffed0c20690
0x7ffed0c20690
0x7ffed0c20694
0x7ffed0c206a4
0x7ffed0c206a4
To me it looks like lines:
int (*b)[5] = &x;
int (*c)[5] = x;
achieve exact same result, because:
they assign the same addres (in case of *b it is the address of entire array and in case of *c it is the address of the first array member but those two overlap) and
assign same pointer size of 5 · int for *b and *c which leads to the exactly same pointer arithmetics when I increment the values.
Q1: Are there any hidden differences between definitions of *b and *c that I am missing?
Q2: Does pointer arithmetics only depends on the size of the pointer?
After you pointed I noticed that I do get an error:
main.c:9:16: warning: initialization of ‘int (*)[5]’ from incompatible pointer type ‘int *’ [-Wincompatible-pointer-types]
int (*c)[5] = x; // points to the 1st array element
Q1: Are there any hidden differences between definitions of *b and *c that I am
missing?
Pointer arithmetic on these two pointers will remain the same. Because internally array decays into the pointer to the first element in it, i.e. arr[n] will be converted to an expression of type "pointer to arr", and its value will be the address of the first element in the array.
Q2: Does pointer arithmetics only depends on the size of the pointer?
No, it depends on the size of the underlying type pointed to. Even in your provided sample input ++a and ++b are yielding different results. Because ++a offsets pointer by sizeof(int) which is 4. But in case of ++b your pointer is incremented by size of 5 * sizeof(int) by 20 (decimal)

Arrays decaying into pointers

Please help me understand the programs below.
#include<stdio.h>
int main()
{
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
printf("value at memory location %p is %d", &a[1], a[1]);
return 0;
}
&a[1] and &a+1. Are they same or different?
#include <stdio.h>
int main()
{
int v[10];
int **p;
int *a[5];
v[0] = 1234;
v[1] = 5678;
a[0] = v;
a[1] = v+1;
printf("%d\t%d\t%d\t%d\n", *a[0],*a[1],a[0][0],**a);
printf("%d\n", sizeof(v));
return 0;
}
I wanted to know how *a[5] is represented in memory. Is *a a base pointer that points to a[0],a[1],a[2],a[3],a[4]?
#include<stdio.h>
int main()
{
int v[10];
int **p;
int (*a)[10];
a=&v;
printf("%d\n",*a);
return 0;
}
a=v; // gives error why? does v here decay into *v. Then does &v get decayed into (*)[]v? & means const pointer. Here, how is it possible to set a const pointer to a non-const pointer without a typecast?
Where does the array get stored in the memory. Does it get stored onto the data segment of the memory.
#include<stdio.h>
int main()
{
int carray[5]={1,2,3,4,5};
printf("%d\n",carray[0]);
printf("%d\t%d\t%d\n",sizeof(carray),sizeof(&carray),sizeof(&carray[0]));
return 0;
}
EDITED:
I have gone through some of the articles which stated that the only two possible situations where an array name cannot be decyed into pointer is the sizeof and &. But in the above program sizeof(&carray) gives the size as 4. and &carray decays into (*)[]carray as its an rvalue.
Then the statement that array name cannot get decayed into pointers on two conditions sizeof and & becomes false here.
&a[1] and &a+1. Are they same or different?
Different. &a[1] is the same as (a+1). In general, x[y] is by definition equivalent to *(x+y).
I wanted to know how *a[5] is represented in memory. Does *a is a base
pointer that points to a[0],a[1],a[2],a[3],a[4].
In your second example, a is an array of pointers. *a[i] is the value of the object, the address of which is stored as the ith element in your array. *a in this case is the same as a[0], which is the first element in your array (which is a pointer).
a=v //why this gives error
Because a (in your last example) is a pointer to an array. You want to assign to a, then you need to assign the address of the array v (or any other array with correct dimensions);
a = &v;
This is very good that you've commited to understanding things, but nothing will help you better than a good C book.
Hope this helps.
Stuff you are gonna need to know when dealing with pointers is that:
int *a and int a[]
is a declaration of an Array, the only diffrence is that in a[] youre gonna have to declare its constant size, *a gives you flexability, it can point at an array size 1 to infinity
int *a[] and int **a
is a declaration of an Array of Array,sometimes called Matrix, the only diffrence is that in *a[] youre gonna have to declare how many Arrays a[] gonna contain pointers of, **a gives you flexability, it can point at any Array of arrays that you want it to be assigned to.
IN GENERAL:
When adding & to a variable, your adding a * to its Type definition:
int a;
&a -> &(int)=int*
when adding * to a variable, you decrase a * from its Type definition
int *a;
*a -> * (int * )=int
int *a;
&a - the Address given to the pointer a by the system(pointer of pointer = **a)
&a+1 - the Address to the beginning of the array + 1 byte
&a[1] == &(a+1) - the Address to the beginning of the array + 1 size of int
int **a;
*a == a[0] - the Address of the first Array in the array of arrays a
*a[0]==a[0][0] - the first int of first array
int *a, b[5];
*a=*b - ERROR because a points at garbage to begin with
a=b - a points at array b
ask me what else you want to know and ill edit this answer.

In C, what does a variable declaration with two asterisks (**) mean?

I am working with C and I'm a bit rusty. I am aware that * has three uses:
Declaring a pointer.
Dereferencing a pointer.
Multiplication
However, what does it mean when there are two asterisks (**) before a variable declaration:
char **aPointer = ...
Thanks,
Scott
It declares a pointer to a char pointer.
The usage of such a pointer would be to do such things like:
void setCharPointerToX(char ** character) {
*character = "x"; //using the dereference operator (*) to get the value that character points to (in this case a char pointer
}
char *y;
setCharPointerToX(&y); //using the address-of (&) operator here
printf("%s", y); //x
Here's another example:
char *original = "awesomeness";
char **pointer_to_original = &original;
(*pointer_to_original) = "is awesome";
printf("%s", original); //is awesome
Use of ** with arrays:
char** array = malloc(sizeof(*array) * 2); //2 elements
(*array) = "Hey"; //equivalent to array[0]
*(array + 1) = "There"; //array[1]
printf("%s", array[1]); //outputs There
The [] operator on arrays does essentially pointer arithmetic on the front pointer, so, the way array[1] would be evaluated is as follows:
array[1] == *(array + 1);
This is one of the reasons why array indices start from 0, because:
array[0] == *(array + 0) == *(array);
C and C++ allows the use of pointers that point to pointers (say that five times fast). Take a look at the following code:
char a;
char *b;
char **c;
a = 'Z';
b = &a; // read as "address of a"
c = &b; // read as "address of b"
The variable a holds a character. The variable b points to a location in memory that contains a character. The variable c points to a location in memory that contains a pointer that points to a location in memory that contains a character.
Suppose that the variable a stores its data at address 1000 (BEWARE: example memory locations are totally made up). Suppose that the variable b stores its data at address 2000, and that the variable c stores its data at address 3000. Given all of this, we have the following memory layout:
MEMORY LOCATION 1000 (variable a): 'Z'
MEMORY LOCATION 2000 (variable b): 1000 <--- points to memory location 1000
MEMORY LOCATION 3000 (variable c): 2000 <--- points to memory location 2000
It declares aPointer as a pointer to a pointer to char.
Declarations in C are centered around the types of expressions; the common name for it is "declaration mimics use". As a simple example, suppose we have a pointer to int named p and we want to access the integer value it's currently pointing to. We would dereference the pointer with the unary * operator, like so:
x = *p;
The type of the expression *p is int, so the declaration of the pointer variable p is
int *p;
In this case, aPointer is a pointer to a pointer to char; if we want to get to the character value it's currently pointing to, we would have to dereference it twice:
c = **aPointer;
So, going by the logic above, the declaration of the pointer variable aPointer is
char **aPointer;
because the type of the expression **aPointer is char.
Why would you ever have a pointer to a pointer? It shows up in several contexts:
You want a function to modify a pointer value; one example is the strtol library function, whose prototype (as of C99) is
long strtol(const char * restrict str, char ** restrict ptr, int base);
The second argument is a pointer to a pointer to char; when you call strtol, you pass the address of a pointer to char as the second argument, and after the call it will point to the first character in the string that wasn't converted.
Remember that in most contexts, an expression of type "N-element array of T" is implicitly converted to type "pointer to T", and its value is the address of the first element of the array. If "T" is "pointer to char", then an expression of type "N-element array of pointer to char" will be converted to "pointer to pointer to char". For example:
void foo(char **arr)
{
size_t i = 0;
for (i = 0; arr[i] != NULL; i++)
printf("%s\n", arr[i]);
}
void bar(void)
{
char *ptrs[N] = {"foo", "bar", "bletch", NULL};
foo(ptrs); // ptrs decays from char *[N] to char **
}
You want to dynamically allocate a multi-dimensional array:
#define ROWS ...
#define COLS ...
...
char **arr = malloc(sizeof *arr * ROWS);
if (arr)
{
size_t i;
for (i = 0; i < ROWS; i++)
{
arr[i] = malloc(sizeof *arr[i] * COLS);
if (arr[i])
{
size_t j;
for (j = 0; j < COLS; j++)
{
arr[i][j] = ...;
}
}
}
}
It means that aPointer points to a char pointer.
So
aPointer: pointer to char pointer
*aPointer :pointer to char
**aPointer: char
An example of its usage is creating a dynamic array of c strings
char **aPointer = (char**) malloc(num_strings);
aPointer gives you a char, which can be used to represent a zero-terminated string.
*aPointer = (char*)malloc( string_len + 1); //aPointer[0]
*(aPointer + 1) = (char*)malloc( string_len + 1); //aPointer[1]
This is a pointer to a pointer to char.

Resources