Arrays decaying into pointers - c

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.

Related

What is the difference between int* p and int (*p)[] in the context of arrays.?

Using DevCpp with TDM GCC 4.9.2 on Windows 8. But I don't think the platform matters for this question.
I know that we can use a pointer to point to a single data or an array of data.
I have learned about pointer to arrays but never used it. What advantage does one have over the other?
Sample Code...
#include <stdio.h>
int main()
{
int x[2]={10,20};
int *p1= NULL; //simple pointer
int (*p2)[] = NULL; //pointer to an array, specifically
p1 = x;
p2 = &x; //removing the & gives me a warning of "assignment from incompatible pointer types".
printf("x[1] = %d\n", x[1]);
*(p1+1) = 7;
printf("x[1] = %d\n", x[1]);
(*p2)[1] = 55;
printf("x[1] = %d", x[1]);
return 0;
}
Does p1 or p2 have an advantage over the other?
They are completely different.
int *p; - is the pointer to the int
int (*p)[1]; is a pointer to the array (in this case one element only)
In your trivial example the pointer arithmetic will be the same and generated code will be the same. But they still have different types and you may get warnings when compiled.
The "advantages" you will see when your example will be less trivial:
int (*p)[100];
p++; the pointer will point to the next 100 elements int array.
Pointer to an array means a pointer which accepts address of an array.
let's say array is int arr[5],in which size of int is 4 byte.
p is a pointer to an array that accept the address of an int array.
int arr[5];
int (*p)[5];
p=&arr;//address of an array block
let's say the base address is 1000 .So after increment in p it will lead us to 1020 address,because the size of the array block is 20 bytes.
p points to 1000 address
p++;
//Now p points to 1020 not 1004.
Whereas in case of int *q, q will point to 1004 as usual.

Array Pointers vs Regular Pointers in C

I am a total beginner to C so please, work with my ignorance. Why does a normal pointer
int* ptr = &a; has two spaces in memory (one for the pointer variable and one for the value it points to) and an array pointer int a[] = {5}; only has one memory space (if I print out
printf("\n%p\n", a) I get the same address as if I printed out: printf("\n%p\n", &a).
The question is, shouldn't there be a memory space for the pointer variable a and one for its value which points to the first array element? It does it with the regular pointer int* ptr = &a;
It's a little unclear from your question (and assuming no compiler optimization), but if you first declare a variable and then a pointer to that variable,
int a = 4;
int *p = &a;
then you have two different variables, it makes sense that there are two memory slots. You might change p to point to something else, and still want to refer to a later
int a = 4;
int b = 5;
int *p = &a; // p points to a
// ...
p = &b; // now p points to b
a = 6; // but you can still use a
The array declaration just allocates memory on the stack. If you wanted to do the same with a pointer, on the heap, you would use something like malloc or calloc (or new in c++)
int *p = (int*)malloc(1 * sizeof(int));
*p = 4;
but of course remember to free it later (delete in c++)
free(p);
p = 0;
The main misunderstanding here is that &a return not pointer to pointer as it expected that's because in C language there some difference between [] and * (Explanation here: Difference between [] and *)
If you try to &a if a was an pointer (e.g. int *a) then you obtain a new memory place but when your use a static array (i.e. int a[]) then it return address of the first array element. I'll also try to clarify this by mean of the next code block.
#include <stdio.h>
int main(int argc, char *argv[])
{
// for cycles
int k;
printf("That is a pointer case:\n");
// Allocate memory for 4 bytes (one int is four bytes on x86 platform,
// can be differ for microcontroller e.g.)
int c = 0xDEADBEEF;
unsigned char *b = (unsigned char*) &c;
printf("Value c: %p\n", c);
printf("Pointer to c: %p\n", &c);
printf("Pointer b (eq. to c): %p\n", b);
// Reverse order (little-endian in case of x86)
for (k = 0; k < 4; k++)
printf("b[%d] = 0x%02X\n", k, b[k]);
// MAIN DIFFERENCE HERE: (see below)
unsigned char **p_b = &b;
// And now if we use & one more we obtain pointer to the pointer
// 0xDEADBEEF <-- b <-- &p_b
// This pointer different then b itself
printf("Pointer to the pointer b: %p\n", p_b);
printf("\nOther case, now we use array that defined by []:\n");
int a[] = {5,1};
int *ptr = &a;
// 'a' is array but physically it also pointer to location
// logically it's treat differ other then real pointer
printf("'a' is array: %x\n", a);
// MAIN DIFFERENCE HERE: we obtain not a pointer to pointer
printf("Pointer to 'a' result also 'a'%x\n", &a);
printf("Same as 'a': %x\n", ptr);
printf("Access to memory that 'a' pointes to: \n%x\n", *a);
return 0;
}
This is very simple. In first case,
int* ptr = &a;
you have one variable a already declared and hence present in memory. Now you declare another variable ptr (to hold the address, in C variables which hold address of another variable are called pointers), which again requires memory in the same way as a required.
In second case,
int a[] = {5};
You just declare one variable (which will hold a collection of ints), hence memory is allocated accordingly for a[].
In this expression, int* p = &a; p has only one memory location, of the WORD size of your CPU, most probably, and it is to store the address (memory location) of another variable.
When you do *p you are dereferencing p, which means you are getting the value of what p points to. In this particular case that would be the value of a. a has its own location in memory, and p only points to it, but does not itself store as content.
When you have an array, like int a[] = {5};, you have a series (or one) of memory locations, and they are filled with values. These are actual locations.
Arrays in C can decay to a pointer, so when you printf like you did with your array, you get the same address, whether you do a or &a. This is because of array to pointer decay.
a is still the same location, and is only that location. &a actually returns a pointer to a, but that pointer sits else where in memory. If you did int* b = &a; then b here would not have the same location as a, however, it would point to a.
ptr is a variable containing a memory address. You can assign various memory addresses to ptr. a is a constant representing a fixed memory address of the first element of the array. As such you can do:
ptr = a;
but not
a = ptr;
Pointers point to an area in memory. Pointers to int point to an area large enough to hold a value of int type.
If you have an array of int and make a pointer point to the array first element
int array[42];
int *p = array;
the pointer still points to a space wide enough for an int.
On the other hand, if you make a different pointer point to the whole array, this new pointer points to a larger area that starts at the same address
int (*q)[42]; // q is a pointer to an array of 42 ints
q = &array;
the address of both p and q is the same, but they point to differently sized areas.

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

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.

Not able to access array elements?

i have this array where i am trying to access its elements by incrementing ptr, as suggested here Trying to find different methods of accessing array elements?...i must be doing something stupid...please help me!
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
char *p1 = "Cnversions";
char *p2 = "Divided";
char *p3 = "Plain";
char *p4 = "Solid";
char *arr[3];
arr[0] = p1;
arr[1] = p2;
arr[2] = p3;
arr[3] = p4;
for(i=0;i<=3;i++)
{
printf("string at arr[%d] is: %s\n",i,*arr);
arr++;
}
return 0;
}
An array like arr is located at a specific spot in memory, so it makes no sense to increment arr (what does it mean to increment an array?)
Instead, you will need to create a pointer to the start of the array and increment the pointer:
char **ptr = arr;
for(i=0; i<4; i++) {
printf("arr[%d] = %s\n", i, *ptr);
ptr++;
}
(Note also that you need to make arr four elements big, i.e. char *arr[4], to accommodate the four string pointers you put in it.)
Remember that although we tend to think of double pointers as arrays, all the compiler sees them as are pointers. When you increment a pointer, it adds a value to the address of the pointer equal to the size of the data type it's pointing at. For example:
int *p;
p = (int *) malloc(sizeof(int));
p is pointing to an int, so the size of p's pointed data is (typically) 4 bytes. This means when you increment p, it will be pointing at a location 4 bytes greater than where it was before.
The type of arr is a char**, meaning that it's a pointer to a pointer to a char. Pointers on most machines these days are 8 bytes. So when you incrementing arr, you are effectively telling the computer to set arr to point to an address 8 bytes higher than what it was at before. In the case of arr, this is an illegal address, so you'll get some kind of crash.

How to use "pointer to array 10 of int"?

I have the following code:
#include<stdio.h>
int main()
{
int(* a)[10]; //declare a as pointer to array 10 of int
int b[10]; // taken a array of 10 int
b[2]=32;
a=&b;
printf("b is on %p\n",&b);
printf("a is on %p\n",a);
printf("magic is %d\n",a[2]); // why this is not showing 32
return 0;
}
output:
b is on 0xbfa966d4
a is on 0xbfa966d4
magic is -1079417052
Here I have taken a as pointer to array 10 of int which points to the array b, so now why am I unable to get the value of 32 on a[2]?
a[2] is evaluated as *(a+2) so now a has address of array b so *(b+2) and *(a+2) are similar so why am I not getting value 32 here?
Edit :
i got answer by using
(*a)[2]
but i am not getting how it works ...
see
when
a[2] is *(a+2) and a+2 is a plus 2 * sizeof(int[10]) bytes.
this way (*a)[2] how expand?
Since a is already a pointer, you have to dereference it in order to refer to the array that it points to:
(*a)[2]
By the rules of pointer arithmetic, a[2] is *(a+2) and a+2 is a plus 2 * sizeof(int[10]) bytes.
(Think of an ordinary int *p; p+1 is p plus sizeof(int) bytes and (char *)(p + 1) is different from (char *)p + 1. Now replace int with int[10])
#include<stdio.h>
int main()
{
int(* a)[10]; //declare a as pointer to array 10 of int
int b[10]; // taken a arry of 10 int
b[2]=32;
a=&b;
printf("b is on %p\n",&b);
printf("a is on %p\n",a);
printf("magic is %p\n",a + 2); // Changed to show pointer arithmetic
return 0;
}
This prints the following:
b is on 0xbfe67114
a is on 0xbfe67114
magic is 0xbfe67164
Do you see what's going on? magic minus a equates 80, that is, 4 * 10 * 2.
This is because a is a pointer to an array of ten integers, so sizeof(*a) == 10 * sizeof(int) and not sizeof(a) == sizeof(int), which is what you was expecting to.
Pay attention to types in pointer arithmetic next time!
I was not able to add a comment here since it requires 50 reputation. So here goes my question for the question posted.
Sorry if I will be violating some of the rules by posting the question in the answer box.
This question shows that we should be careful while performing pointer arithmetic. But what is the good use of using pointers to an array if same thing could be done just by using pointers to integers ....?
int b[10] == int* that points to the first value in the array
int (*a)[10] == int** that point to the address of a pointer that points to an array
a+2 == (&b)+2
Hope this clears things up for you

Resources