I couldn't understand use of (int*) p in following program for pointer to an array
#include<stdio.h>
void main()
{
int s[4][2];
int (*p)[2];
int i,j,*pint;
for(i=0;i<=3;i++)
{
p=&s[i];
pint=(int*)p; /*here*/
printf("\n");
for(j=0;j<=1;j++)
printf("%d",*(pint+j));
}
}
can i use *p instead of (int*) p here. thanks in advance
In your code,
pint=(int*)p;
p is of type int (*)[2], i.e., pointer to an array of 2 ints, and pint is a int *. They are not compatible types, so you need the cast.
If you have an array declaration like this
int s[4][2];
then these three pointers have the same value
int ( *p1 )[4][2] = &s;
int ( *p2 )[2] = &s[0];
int *p3 = &s[0][0];
because all the pointers point to the initial address of the extent of memory allocated for the array.
However the pointers have different types because they point to objects of different types.
The first pointer points to the array in whole as a single object.
the second pointer points to an array element that in turn has the array type int[2].
And the third array point to a scalar object of the type int.
So you may not assign directly one pointer to another because they are incompatible though as it was mentioned they have the same value (address).
You need to cast one pointer type to another pointer type explicitly.
This assignment in the original program
p=&s[i];
assigns the address of each element (array of the type int[2]) to the pointer. In fact it is the address of the first element of the array that is it is equal to &s[i][0]. However the first expression and the last expression have different pointer types.
So you need to use casting in this assignment
pint=(int*)p;
Now using the pointer arithmetic in this expression
*(pint+j)
you can traverse all scalar elements of the array initially pointed to by the pointer p.
Pay attention to that this declaration of main
void main()
is nit a standard declaration.
You should declare the function main like
int main( void )
Related
I have a basic doubt, when we de-reference a pointer to an array why we get name of the array instead the value of first member of an array, I see this has been asked here but I didn't get it
exactly how?
dereferencing pointer to integer array
main()
{
int var[10] = {1,2,3,4,5,6,7,8,9,10};
int (*ptr) [10] = &var;
printf("value = %u %u\n",*ptr,ptr); //both print 2359104. Shouldn't *ptr print 1?
}
So, is it like when we dereference a pointer, it cancel out the reference operator and what we get is variable name, and in case of pointer to an array, it is the array name ?
main()
{
int a = 10;
int *p = &a;
printf("%d\n", *p) /* p = &a; *p = *(&a); and having a dereference cancel out the &, gives us *p = a ? */
}
Because ptr has type int (*)[10] which is a pointer to an array, *ptr has type int[10] which is an array type.
This array decays to a pointer to its first element when it is passed to printf which then prints the pointer value. The result would be the same if you passed var to printf instead of *ptr.
You do not get a variable name when you dereference a pointer. If the pointer points to an object the you get that object. If it does not point to an object then you get undefined behavior. In particular, if the pointer points to a whole array, then you get that array. That's a fundamental aspect of how pointers work.
However, a fundamental aspect of how arrays work is that in most contexts, an expression of array type is automatically converted to a pointer to the first array element. This address corresponds to the address of the array itself, but has different type (int * in your case, as opposed to int (*)[10]). Typically, converting these to an integer type produces the same value. Thus, in your example code, *ptr is equivalent to var, and each is automatically converted to a pointer of type int *, equivalent to &var[0].
But note also that it is not safe to convert pointers to integers by associating them with printf directives, such as %u, that expect a corresponding integer argument. The behavior is undefined, and in practice, surprising or confusing results can sometimes be observed. One prints a pointer value with printf by using a %p directive, and converting the pointer value to type void *. Example:
printf("pointer = %p %p\n", (void *)*ptr, (void *)ptr);
Combined with the type and value of ptr from your example, this can be expected to reliably print two copies of the same hexadecimal number.
Before anyone closes this question because there's another related one, hear me out. I've already looked at the other question and I didn't get it. I would like to create a pointer to a multi dimensional array but I don't know how. I thought I was supposed to do it like this:
int test_arr[2][4];
int *ptr_array = test_arr;
But when I do that, I get a warning saying:
incompatible pointer types initializing 'int *' with an expression of type 'int [2][4]'
I have no idea what I'm doing wrong. Can someone help me please?
In order to do pointer arithmetic the pointer has to know the size of what it is pointing to.
int test_arr[2][4]; is equivalent to 2 elements of type int[4]. So whenever you add 1 to the pointer, it will jump the size of 4 integers. If you had int* it would increment the size of a single integer only.
Like said in the comments, what you want is: int (*ptr_array)[4] = test_arr;
I know, the syntax is a little weird, but that's how you do it.
You need to understand the basics.
[Below in post, read 1D as 1 dimension and 2D as 2 dimension]
First, lets take an example of pointer to 1D array:
Take an int type and a pointer pointing to it:
int x = 1;
int *px = &x;
The type of x is int and the type of &x is int * and type of px is int * i.e. it can hold the address of an int type variable. Hence the assignment is valid.
Take a 1D int array and a pointer pointing to it:
int arr[2] = {1,2};
int *parr = arr;
Note that the type of px and parr is same i.e. int * and assigning arr to parr is completely valid although the arr is a 1D array.
This is because of the fact that, in C, an array of type converted to pointer of type that points to the initial element of the array object but there are few exceptions to this rule and one of them is when used unary & operator.
The type of arr is int [2] but in the above statment (parr declare and initialisation statement) it is converted to pointer pointing to initial element of array which is an integer i.e. arr is converted to int * type in the int *parr = arr; statement. Hence, it is valid to assign arr to parr or to any variable of type int *.
As, I have mentioned that there are few exceptions to the rule (array of type converted to pointer of type....) and one of the exception is when used unary & operator. So type of &arr will be int (*)[2]. That means you can assign &arr to any variable of type int (*)[2].
int (*parr2)[2] = &arr;
i.e. parr2 is a pointer to an array of 2 integer.
The difference between this
int *parr = arr;
and
int (*parr2)[2] = &arr;
is that parr can hold address of any int pointer but parr2 can hold the address of any array of 2 integers. Both are pointing to same address but their types are different.
If you understood the above mentioned things completely then read below otherwise read the above part again.
Now lets come to 2D array.
Take a 2D array and a pointer pointing to it:
int arr[2][2];
int (*ptr)[2] = arr;
In the above ptr declare and initialisation statement, the type of arr is int (*)[2]. Why??
Recall the rule mentioned above - array of type converted to pointer of type that points to the initial element of the array object.
arr is array of 2 1D arrays of size 2 (2 int elements). So, it's first element is array of 2 int and, by rule, it will be converted to pointer to the initial element i.e. pointer to
1D array of 2 int which is int (*)[2].
Hence, you can assign arr to a pointer variable of type int (*)[2].
The type of &arr is int (*)[2][2], so this is also perfectly fine:
int (*ptr2)[2][2] = &arr;
So, there are two ways you can have pointer to 2D arr but remember that the types of ptr and ptr2 is different. This matters, for e.g., if you add 1 to pointer ptr it will be incremented by size of int [2] but if you add 1 to ptr2 it will be incremented by size of int [2][2].
How to access the array members using pointer:
In case of 1D array:
int arr[2] = {1,2};
int *parr = arr;
int (*parr2)[2] = &arr;
// access arr members via parr pointer
printf ("%d\n", parr[0]); // this will give value of first member of array arr
// access arr members via parr2 pointer
printf ("%d\n", (*parr2)[0]); // this will give value of first member of array arr
Similarly, in case of 2D array:
int test_arr[2][4];
int (*ptr_array)[4] = test_arr;
int (*ptr_array2)[2][4] = &test_arr;
// access test_arr members via ptr_array pointer
printf ("%d\n", ptr_array[0][0]); // this will give value of first member of array test_arr
// access test_arr members via ptr_array2 pointer
printf ("%d\n", (*ptr_array2)[0][0]); // this will give value of first member of array test_arr
Based on above explanation, try yourself creating multidimensional array (> 2D array) pointers and play with them.
Hope, above explanation resolves your all confusions related to pointer to a 2D array and you understood now why compiler is giving incompatible pointer types .... warning on statement int *ptr_array = test_arr;. It's all about type compatibility during initialisation/assignment.
How can you interpret the following line of code?
int (*arrayABC)[10];
In my textbook, it says that we have a pointer to a pointer to the 0th element of an integer array.
However, I don't quite understand this.
My interpretation: We have some variable, which gets as its value some address. This address is then the address of the 0th element of an UNNAMED integer array. Basically we have a pointer to the 0th element.
Why then to have a pointer TO A POINTER?
This is a pointer to an array. It is not a pointer to a pointer. Arrays and pointers are different. An array has an address, but an array is not an address. An array is a series of contiguous elements.
This pointer points to the whole array and not just the first element, in the same way that a float * points to the whole float and not just the first byte.
If you have for example:
int foo[10];
int (*arrayABC)[10] = &foo;
then the expressions (*arrayABC) and foo are identical. E.g. foo[3] is the same as (*arrayABC)[3].
If you have an object of a type T then a pointer to the object is declared like
T obj;
T *ptr = &obj;
Now let's the type T is defined the following way
typedef int T[10];
Thus the code above
T obj;
T *ptr = &obj;
can be rewritten using the typedef definition like
int obj[10];
int (*ptr)[10] = &obj;
In the both cases, when T is some abstract type and when T is an alias for int[10], ptr is a pointer to an object. In the last case ptr is a pointer to an array of 10 elements of type int. That is the object pointed to by ptr has array type. Arrays and poiters are different types.
Try the following simple demonstrative program
#include <stdio.h>
int main( void )
{
typedef int T[10];
T a;
T *pa = &a;
printf( "%zu\n", sizeof( *pa ) );
int b[10];
int ( *pb )[10] = &b;
printf( "%zu\n", sizeof( *pb ) );
}
Its output is
40
40
As you can see the both values are equal to the size of an integer array of 10 elements. So the pointers point to arrays.
If you write
int *arrayABC[10];
you will get an array of 10 pointers of type int *.
If you write
int (*arrayABC)[10];
you will get a pointer to an array of 10 integers.
In my textbook, it says that we have a pointer to a pointer to the 0th element of an integer array.
Your textbook is ... badly worded, let's leave it at that. It's a pointer to a 10-element array of int.
I can kind of see where the book is coming from. Given the declaration
int (*a)[10];
the expression *a will have type int [10] (10-element array of int). However, unless that expression is the operand of the sizeof or unary & operators, it will be converted ("decay") from type int [10] to int *, and the value of the expression will be the address of the first element of the array:
Expression Type "Decays" to Value
---------- ---- ----------- -----
*a int [10] int * Address of first element of the array;
equivalent to `&(*a)[0]`.
Thus, if I call a function like
foo( *a );
what the function actually receives will be a pointer to the first element of the pointed-to array (its type will be int *, not int **).
So in effect, yes, a often winds up behaving as a pointer to a pointer to the first element of the array; however, its type is not "pointer to pointer to int", and type matters. Given:
int (*a)[10];
int **b;
then you'll get different behavior for the following:
sizeof *a vs. sizeof *b
a + i vs b + i (also applies to a++ vs b++)
Is there a difference between &array[0] and &array when passed to a C Function. This array is a void* array which currently takes integer as data.
Added the test code
#include <iostream>
#include <conio.h>
using namespace std;
int read_buffer[10] = {0,0,0,0,0,0,0,0,0,0};
int write_buffer[10] = {0,1,2,3,4,5,6,7,8,9};
void WriteBlock(void* SrcPtr)
{
//WriteBlock will use SrcPtr and store the data to a common memory block which ReadBlock will access.
}
void ReadBlock(void* DstPtr)
{
//ReadBlock function will fetch data from readBuffer and put the data back into the *DstPtr.
}
void main()
{
WriteBlock((int*)&write_buffer);
//Is there a difference between these two below calls.
ReadBlock(&read_buffer[0]);
ReadBlock(&read_buffer);
}
Yes, there's a big difference, and it depends on context.
Consider this:-
char arrayA[10];
char *arrayB;
&arrayA[0] and &arrayB[0] both have type char *.
But &arrayA has type char (*)[10] while &arrayB has type char ** - the address of the pointer.
For arrayA, these point to the same address - but for arrayB, they do not! There's a common C misconception that "pointers and arrays are the same". This is a great example of where they are absoluelty not,
See this : http://ideone.com/OcbuXZ
Assuming array is declared
void *array[N];
then the expressions &array[0] and &array will yield the same value (the address of the first element of the array is the same as the address of the array itself), but will have different types.
Expression Type
---------- ----
&array void *(*)[10] -- pointer to 10-element array of `void *`
&array[0] void ** -- pointer to pointer to void
Your function prototype will need to match up with whichever expression you pass. If you call the function as
func(&array);
then the function prototype needs to be
void func(void *(*arrp)[10]) {...}
If you call the function as
func(&array[0]);
then the function prototype needs to be
void func(void **arrp) {...}
although in that case you should pass the size of the array as a separate parameter.
Now, assuming array is declared
void **array = malloc(sizeof *array * N);
then the expressions &array and &array[0] will yield different values and different types.
Expression Type
---------- ----
&array void ***
&array[0] void **
&array will give you the address of the array variable itself, which is different from the address of the heap memory that's been allocated for the array. Again, your function prototype will need to match up with the type of the expression you use.
If array is really an array, then
&array[0] is the pointer to element 0 of array[]
&array is the pointer to the entire array[]
So, these two expressions are of different types. And that's the main difference that may cause your code to fail to compile if you pass the wrong one of the two.
At the low level, however, the two pointers are going to hold the same address.
Yes there is a big different
&array[0]==>void**
AND
&array==>void***
This won't compile, you are using a void * and try to get the first element of it. But what size does it have? The compiler doesn't know. Using int * may compile, if you are not trying something like this:
int main (void) {
int *arr = malloc( 10 );
arr = &arr[0]; // this is ok
arr = &arr; // wrong data type
}
&array returns an int **, &array[0] returns int *. These are different data types.
I'm messing around with multidimensional arrays and pointers. I've been looking at a program that prints out the contents of, and addresses of, a simple array. Here's my array declaration:
int zippo[4][2] = { {2,4},
{6,8},
{1,3},
{5,7} };
My current understanding is that zippo is a pointer, and it can hold the address of a couple of other pointers. By default, zippo holds the address of pointer zippo[0], and it can also hold the addresses of pointers zippo[1], zippo[2], and zippo[3].
Now, take the following statement:
printf("zippo[0] = %p\n", zippo[0]);
printf(" *zippo = %p\n", *zippo);
printf(" zippo = %p\n", zippo);
On my machine, that gives the following output:
zippo[0] = 0x7fff170e2230
*zippo = 0x7fff170e2230
zippo = 0x7fff170e2230
I perfectly understand why zippo[0] and *zippo have the same value. They're both pointers, and they both store the address (by default) of the integer 2, or zippo[0][0]. But what is up with zippo also sharing the same memory address? Shouldn't zippo be storing the address of the pointer zippo[0]? Whaaaat?
When an array expression appears in most contexts, its type is implicitly converted from "N-element array of T" to "pointer to T", and its value is set to point to the first element in the array. The exceptions to this rule are when the array expression is an operand of either the sizeof or address-of (&) operators, or when the array is a string literal being used as an initializer in a declaration.
Thus, the expression zippo "decays" from type int [4][2] (4-element array of 2-element arrays of int) to int (*)[2] (pointer to 2-element array of int). Similarly, the type of zippo[0] is int [2], which is implicitly converted to int *.
Given the declaration int zippo[4][2], the following table shows the types of various array expressions involving zippo and any implicit conversions:
Expression Type Implicitly converted to Equivalent expression
---------- ---- ----------------------- ---------------------
zippo int [4][2] int (*)[2]
&zippo int (*)[4][2]
*zippo int [2] int * zippo[0]
zippo[i] int [2] int *
&zippo[i] int (*)[2]
*zippo[i] int zippo[i][0]
zippo[i][j] int
&zippo[i][j] int *
*zippo[i][j] invalid
Note that zippo, &zippo, *zippo, zippo[0], &zippo[0], and &zippo[0][0] all have the same value; they all point to the base of the array (the address of the array is the same as the address of the first element of the array). The types of the various expressions all differ, though.
When you declare a multidimensional array, the compiler treats it as a single dimensional array. Multidimensional arrays are just an abstraction to make our life easier. You have a misunderstanding: This isn't one array pointing to 4 arrays, its always just a single contigous block of memory.
In your case, doing:
int zippo[4][2]
Is really the same as doing
int zippo[8]
With the math required for the 2D addressing handled for you by the compiler.
For details, see this tutorial on Arrays in C++.
This is very different than doing:
int** zippo
or
int* zippo[4]
In this case, you're making an array of four pointers, which could be allocated to other arrays.
zippo is not a pointer. It's an array of array values. zippo, and zippo[i] for i in 0..4 can "decay" to a pointer in certain cases (particularly, in value contexts). Try printing sizeof zippo for an example of the use of zippo in a non-value context. In this case, sizeof will report the size of the array, not the size of a pointer.
The name of an array, in value contexts, decays to a pointer to its first element. So, in value context, zippo is the same as &zippo[0], and thus has the type "pointer to an array [2] of int"; *zippo, in value context is the same as &zippo[0][0], i.e., "pointer to int". They have the same value, but different types.
I recommend reading Arrays and Pointers for answering your second question. The pointers have the same "value", but point to different amounts of space. Try printing zippo+1 and *zippo+1 to see that more clearly:
#include <stdio.h>
int main(void)
{
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
printf("%lu\n", (unsigned long) (sizeof zippo));
printf("%p\n", (void *)(zippo+1));
printf("%p\n", (void *)(*zippo+1));
return 0;
}
For my run, it prints:
32
0xbffede7c
0xbffede78
Telling me that sizeof(int) on my machine is 4, and that the second and the third pointers are not equal in value (as expected).
Also, "%p" format specifier needs void * in *printf() functions, so you should cast your pointers to void * in your printf() calls (printf() is a variadic function, so the compiler can't do the automatic conversion for you here).
Edit: When I say an array "decays" to a pointer, I mean that the name of an array in value context is equivalent to a pointer. Thus, if I have T pt[100]; for some type T, then the name pt is of type T * in value contexts. For sizeof and unary & operators, the name pt doesn't reduce to a pointer. But you can do T *p = pt;—this is perfectly valid because in this context, pt is of type T *.
Note that this "decaying" happens only once. So, let's say we have:
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
Then, zippo in value context decays to a pointer of type: pointer to array[2] of int. In code:
int (*p1)[2] = zippo;
is valid, whereas
int **p2 = zippo;
will trigger an "incompatible pointer assignment" warning.
With zippo defined as above,
int (*p0)[4][2] = &zippo;
int (*p1)[2] = zippo;
int *p2 = zippo[0];
are all valid. They should print the same value when printed using printf("%p\n", (void *)name);, but the pointers are different in that they point to the whole matrix, a row, and a single integer respectively.
The important thing here is that int zippy[4][2] is not the same type of object as int **zippo.
Just like int zippi[5], zippy is the address of a block of memory. But the compiler knows that you want to address the eight memory location starting at zippy with a two dimensional syntax, but want to address the five memory location starting at zippi with a one dimensional syntax.
zippo is a different thing entirely. It holds the address of a a block of memory big enough to contain two pointer, and if you make them point at some arrays of integers, you can dereference them with the two dimensional array access syntax.
Very well explained by Reed, I shall add few more points to make it simpler, when we refer to zippo or zippo[0] or zippo[0][0], we are still referring to the same base address of the array zippo. The reason being arrays are always contiguous block of memory and multidimensional arrays are multiple single dimension arrays continuously placed.
When you have to increment by each row, you need a pointer int *p = &zippo[0][0], and doing p++ increments the pointer by every row.
In your example id its a 4 X 2 array, on doing p++ its, pointer currently points to second set of 4 elements.