I'm playing with OnlineGDB compiler in order to understand how pointers work in C.
First, I ran the following code and got the output I expected:
int *array1[] = {1,4,3,4};
int main()
{
printf("%d \n", array1[0+1]);
printf("%d", array1[1+1]);
return 0;
}
Output was:
4
3
Secondly, I ran the following code - And I can't understand its output:
int *array1[] = {1,4,3,4};
int main()
{
printf("%d \n", array1[0]+1);
printf("%d", array1[1]+1);
return 0;
}
Output:
5
8
It seems like I'm adding 4 to the value from the array, but why? (each element in the array is consisted from a byte).
Thanks!
It seems like I'm adding 4 to the value from the array, but why?
No, each element of the array is an int * because you declared the array that way:
int *array1[] = {1,4,3,4};
That says array1 is an array whose values have type pointer to int. Remove the * if you want an array of int, like:
int array1[] = {1,4,3,4};
When you add or subtract from pointer types, the value changes by some multiple of the size of the type that the pointer refers to. An int on your system is probably 4 bytes, so an expression like array1[0]+1 gets the int * stored in array[0] and increments it, so it increases by sizeof(int).
(each element in the array is consisted from a byte).
Even if you had declared your array as an array of int rather than an array of int *, the size of an int is probably not 1 byte. int is typically 4 bytes long, but size depends on the compiler and target system.
With
int *array1[] = {1,4,3,4};
you are defining tan array of pointers to integers.
So every element of that array, even if initialized with what appear to be integer values, are actually pointers, that are addresses.
If you had deferenced those pointers you would probably have caused a segmentation fault. But fortunately you simply printed them, even if using %d instead of %p: a choice that according to C standard could have caused undefined behavior. Anyway in your case the pointers were converted to integers, and the printed values were the expected ones. Exactly like if the array was an array of integers.
In the second example you pushed it further: you added 1 to the array elements. But since they are pointers, then pointers arithmetics is applied. Meaning that pointer + N = pointer + N * sizeof(*pointer). In this case, since sizeof(int) is 4:
array[0] + 1 =
= 1 + sizeof (array[0]) =
= 1 + sizeof( int ) =
= 1 + 4 = 5
Related
I am learning c in school , and having a little confusion on how to use type casting.
here is my code.
I am trying to figure out what type casting is and how it works.
I initialized a pointer(ptr3) that points the adress of k, then initialized ptr4 and assign ptr3 that is converted into int*.
but this does not seem like working, since it gives random values every time.
Why is it?
I appreciate any feedback ! thank you so much.
#include <stdio.h>
int main() {
char k = 10;
char* ptr3 = &k;
int* ptr4 = (int*) ptr3;
printf("*ptr3 = %d *ptr4 = %d\n", *ptr3, *ptr4);
return 0;
}
output is
*ptr3 = 10 *ptr4 = 1669824522
You have two undefined behaviour in one line.
When you dereference int * pointer you read outside the k object which is illegal.
Even if the k had enough size (for example is a char array), using the data as another type violates the strict aliasing rules - which is UB as well
Generally speaking, do not typecast pointers unless you really know what you are doing. If you want to convert byte array to integer use memcpy functionh.
A char is 1 byte in size, however, an integer is 4 bytes.
What you are doing is called Type Punning, where you are telling the compiler to not convert your char to an int and directly read 4 bytes from that same memory address while you are only allocating 1 byte. Those other 3 bytes could be anything.
The bytes of the char look like this:
10
Real simple, only one number. Integers need 3 more bytes than a char so here is what the integer could look like in bytes:
10 ? ? ?
The solution:
#include <stdio.h>
int main()
{
char k = 10;
int i = (int)k;
printf("k = %d i = %d\n", k, i);
return 0;
}
This code instead of directly reading the memory tells the compiler to convert the char to an int, filling in those 3 random bytes in the process with zeros. Here is what the variable i could look like in memory:
10 0 0 0
Those last 3 bytes were filled in with zeros and the integer is 10.
I hope this answer helps and I am open to feedback to improve it.
I'm new in programming and learning about pointers in array. I'm a bit confused right now. Have a look at the program below:
#include <stdio.h>
int fun();
int main()
{
int num[3][3]={23,32,478,55,0,56,25,13, 80};
printf("%d\n",*(*(num+0)+1));
fun(num);
printf("%d\n", *(*(num+0)+1));
*(*(num+0)+0)=23;
printf("%d\n",*(*(num+0)));
return 0;
}
int fun(*p) // Compilation error
{
*(p+0)=0;
return 0;
}
This was the program written in my teacher's notes. Here in the main() function, in the printf() function dereference operator is being used two times because num is pointer to array so first time dereference operator will give pointer to int and then second one will give the value at which the pointer is pointing to.
My question is that when I'm passing the array name as argument to the function fun() then why *p is used; why not **p as num is a pointer to array?
Second thing why *(p+0) is used to change the value of zeroth element of the array; why not *(*(p+0)+0)=0 as in the main() function *(*(num+0)+0) is used to change the value of zeroth element?
The whole thing is very confusing for me but I have to understand it anyway. I have searched about this and found that there is a difference between pointer to array and pointer to pointer but I couldn't understand much.
The trick is the array-pointer-decay: When you mention the name of an array, it will decay into a pointer to its first element in almost all contexts. That is num is simply an array of three arrays of three integers (type = int [3][3]).
Lets analyse the expression *(*(num + 1) + 2).
When you mention num in the expression *(num + 1), it decays into a pointer to its first element which is an array of three integers (type = int (*)[3]). On this pointer pointer arithmetic is performed, and the size of whatever the pointer points to is added to the value of the pointer. In this case it is the size of an array of three integers (that's 12 bytes on many machines). After dereferencing the pointer, you are left with a type of int [3].
However, this dereferencing only concerns the type, because right after the dereferencing operation, we see expression *(/*expression of type int[3]*/ + 2), so the inner expression decays back into a pointer to the first array element. This pointer contains the same address as the pointer that results from num + 1, but it has a different type: int*. Consequently, the pointer arithmetic on this pointer advances the pointer by two integers (8 bytes). So the expression *(*(num + 1) + 2) yields the integer element at an offset of 12 + 8 = 20 bytes, which is the sixth integer in the array.
Regarding your question about the call of fun(), that call is actually broken, and only works because your teacher did not include the arguments in the forward declaration of fun(). The code
int fun(int* arg);
int main() {
int num[3][3] = ...;
...
fun(num);
}
would have generated a compile time error due to the wrong pointer type. The code of your teacher "works", because the pointer to the first array in num is the same as the pointer to the first element of the first array in num, i. e. his code is equivalent to
int fun(int* arg);
int main() {
int num[3][3] = ...;
...
//both calls are equivalent
fun(num[0]);
fun(&num[0][0]);
}
which would compile without error.
This example shows a matrix, pointers to the first integers of arrays, and pointer to pointer
#include<stdio.h>
int fun(int (*p)[3]); /* p is pointer to array of 3 ints */
int main()
{
/* matrix */
int num[3][3]={{23,32,478},{55,0,56},{25,13, 80}};
/* three pointers to first integer of array */
int *pnum[3] = {num[0], num[1], num[2]};
/* pointer to pointer */
int **ppnum = pnum;
printf("%d\n", *(*(num+1)+2));
fun(num);
printf("%d\n", *(*(num+1)+2));
pnum[1][2] = 2;
printf("%d\n", *(*(num+1)+2));
ppnum[1][2] = 3;
printf("%d\n", *(*(num+1)+2));
return 0;
}
int fun(int (*p)[3])
{
p[1][2]=1;
return 0;
}
You do not actually need any pointers to print anything here.
Your int num[3][3] is actually an array of three elements, each of which is an array of three integers. Thus num[0][0] = 23, num[1][1] = 0, and so on. Thus you can say printf("%d", num[0][0]) to print the first element of the array.
Pointer to variable:
Pointer is variable which stores the address( of a variable). Every one know that.
Pointer to Array:
An array is a variable which has the starting point(address) of group of same objects.
And the pointer is a variable which stores the starting point(address) of an Array.
For example:
int iArray[3];
iArray is a variable which has an address value of three integers and the memory is allocated statically. And the below syntax is provided in a typical programming languages.
// iArray[0] = *(iArray+0);
// iArray[1] = *(iArray+1);
// iArray[2] = *(iArray+2);
In the above the iArray is a variable through which we can access the three integer variables, using any of the syntax mentioned above.
*(iArray+0); // Here iArray+0 is the address of the first object. and * is to dereference
*(iArray+1); // Here iArray+1 is the address of the second object. and * is to dereference
So simple, what is there to confuse.
The below lines are for your understanding
int iArray1[3];
int iArray2[3][3];
int *ipArray = 0;
ipArray = iArray1; // correct
ipArray = iArray2[0]; // correct
ipArray = iArray2[2]; // correct
int **ippArray = iArray2; // wrong
As per the above last line, compiler will not take it as a valid assignment. So **p is not used.
Pointer arthmatic cannot be applied on double arrays because of the way memory is allocated.
Why does a 3D array print address after being dereferenced twice? Please help me understand the code posted below, (assume that the array begins at location 1002).
int main()
{
int a[2][3][4]={
{
1,2,3,4,
4,5,6,7,
9,1,1,2
},
{
2,1,4,7,
6,7,8,9,
0,0,0,0
}
};
printf("%u %u %u %u\n",a,*a,**a,***a); //a == *a == **a, all print address 1002. Why?
}
**a has type int * and points to the first int in the 3D array
*a has type int (*)[4] and points to the first row of the 3D array
a has type int (*)[3][4] and points to the first 2D array in the 3D array
&a has type int (*)[2][3][4] and points to the whole 3D array
So they are all pointers that point to the same address. It's just that the type of the pointer is different. The following code may help illustrate this point.
int main( void )
{
int a[2][3][4]={ 1,2,3,4, 4,5,6,7, 9,1,1,2, 2,1,4,7, 6,7,8,9, 0,0,0,0 };
int *ptrInt; // pointer to an int
int (*ptrArray1)[4]; // pointer to an array of ints
int (*ptrArray2)[3][4]; // pointer to a 2D array of ints
int (*ptrArray3)[2][3][4]; // pointer to a 3D array of ints
ptrInt = **a;
ptrArray1 = *a;
ptrArray2 = a;
ptrArray3 = &a;
printf( "%p %p\n", ptrInt , ptrInt + 1 );
printf( "%p %p\n", ptrArray1, ptrArray1 + 1 );
printf( "%p %p\n", ptrArray2, ptrArray2 + 1 );
printf( "%p %p\n", ptrArray3, ptrArray3 + 1 );
}
Note: I left out the inner braces in the array initialization specifically to demonstrate that the inner braces are optional. Best practice would have all of the inner braces.
Typical output from this code is shown below. I've added comments to show the difference between the two pointers as a decimal number.
0x17b00 0x17b04 // 4 bytes, hence pointer to an int
0x17b00 0x17b10 // 16 bytes, pointer to int[4]
0x17b00 0x17b30 // 48 bytes, pointer to int[3][4]
0x17b00 0x17b60 // 96 bytes, pointer to int[2][3][4]
Note that when you add 1 to any pointer, the size of the object is added to the pointer. For example, if you have an int * and you add 1 to that pointer, the value of the pointer will increase by 4 because sizeof(int) == 4. (Yes, that assumes that ints are 32-bits, thank you.)
So by adding 1 to a pointer, you can determine the size of the object that the pointer points to. That gives you a clue about the type of the pointer from the compiler's point of view. In the example above, notice that adding 1 to ptrArray1 changes the pointer by 16. That's because ptrArray1 points to an object of size 16, specifically it points to an array of 4 ints.
Just so that we're all completely confused, allow me to say that the following line of code will print the number 8. I chose 8 since it only appears once in the array, so you can tell where it's coming from.
printf( "%d\n", ptrArray3[0][1][1][2]);
Notice that it appears that I'm using ptrArray3 as a 4-dimensional array. This is why pointers to multidimensional arrays are so confusing in C. When you convert an array to a pointer, the pointer has one less dimension than the array. But when you use the pointer with array syntax, you use it as though it had one more dimension.
So for example, start with a 2D array
int array[4][100];
The corresponding pointer is a pointer to a 1D array
int (*ptr)[100] = array;
But you can use that pointer like a 2D array
ptr[2][100] = 6;
That is the basis for all of the confusion, and the reason that pointer-to-array is a seldom used feature in C.
a has the type array of size 2 of arrays of size 3 of arrays of size 4 of int.
*a has the type array of size 3 of arrays of size 4 of int.
**a has the type array of size 4 of int.
All three arrays when decayed to corresponding pointers have the same value because they point to the same location in memory.
Try the following Code:
int main()
{
int a[2][3][4]={
{
{1,2,3,4},
{4,5,6,7},
{9,1,1,2}
},
{
{2,1,4,7},
{6,7,8,9},
{0,0,0,0}
}
};
printf("%u %u %u u%",a,*a,**a,***a);//how a == *a == **a print address 1002 please help me to understand ?
}
The reason it was returning the address was because you didn't declare your 3d array properly at all. The above is the corrected code, try it out and let us know how it goes
This question already has answers here:
Is an array name a pointer?
(9 answers)
Closed 8 years ago.
i have often heard that array and pointers can be used interchangeable in some situation but the two does not mean the same thing so what are the circumstances in which we can use array as a pointer and vice versa.
Arrays and pointers are never the same thing.
However, under certain circumstances, an array name in your code will "decay" to a pointer to the first element. That means you lose information about the size of the array since a pointer doesn't know how many elements it points to (technically, it only points at one though you can advance through a contiguous array if you can tell where the end is, such as with a length or sentinel value).
Situations in which arrays do not behave like pointers are (for example):
when you do a sizeof: for the array, it's the size of the entire array, for a decayed pointer, it's the size of the pointer.
when you want to move through an array: with a real array, you must use indexing while you can simply increment the pointer.
Consider the following code:
#include <stdio.h>
void fn (int arr[]) {
printf ("sz = %d\n", sizeof(arr));
printf ("#4 = %d\n", arr[4]);
arr = arr + 1;
printf ("#4 = %d\n", arr[4]);
}
int main (void) {
int x[] = {1,2,3,4,5,6,7,8,9};
printf ("sz = %d\n", sizeof(x));
printf ("#4 = %d\n", x[4]);
//x = x + 1; // Cannot do this
printf ("#4 = %d\n", x[4]);
puts("=====");
fn(x);
return 0;
}
which outputs:
sz = 36
#4 = 5
#4 = 5
=====
sz = 4
#4 = 5
#4 = 6
You can see from that the sizeof is different and you can actually move the pointer whereas the array name is at a fixed location (you'll get an error if you uncomment the line that tries to increment it).
The name of an array behaves pretty much like a pointer to the first element. That is it's value, although it has other attributes that are different.
This is most obvious when calling a function. If you have:
float sum_floats(const float *x, size_t num_values);
you can call it with:
float three[] = { 1.f, 2.f, 3.f };
const float sum = sum_floats(three, sizeof three / sizeof *three);
Note how three in the function call "decays" into &three[0], i.e. a pointer to the first element in the array. Note also how sizeof three still works, since three really is an array.
Inside the function, the array has decayed into const float *, the type of the function's argument, and you can no longer use sizeof to get the size of the caller's array (since the function has no idea that the caller used an array).
Typically an array is a container for a number of elements of the same type, while a pointer is the memory address for a memory location that contains a specific value.
When you declare an array like this:
int arr[] = {1, 2, 3, 4, 5};
printf("%d", *arr); /* will print 1 */
printf("%d", arr[0]); /* will print 1 as well */
/*or*/
int arr[5];
you are allocating memory for 5 integers. Take care that the array name by itself acts as a pointer to the first element in the array.
You can achieve the same thing using pointers:
int* arr = new int[5];
Suppose I have:
int (* arrPtr)[10] = NULL; // A pointer to an array of ten elements with type int.
int (*ptr)[3]= NULL;
int var[10] = {1,2,3,4,5,6,7,8,9,10};
int matrix[3][10];
Now if I do,
arrPtr = matrix; //.....This is fine...
Now can I do this:
ptr = var; //.....***This is working***
OR is it compulsory to do this:
ptr= (int (*)[10])var; //....I dont understand why this is necessary
Also,
printf("%d",(*ptr)[4]);
is working even though we declare
int (*ptr)[3]=NULL;
^^^
In some cases, Name of Array is Pointer to it's First Location.
So, when you do,
ptr = var;
You are assigning address of var[0] to ptr[0]
int var[10] declaration makes var as an int pointer
As both are int pointers, the operation is valid.
For Second Question,
When you declare a Pointer, It points to some address.
Say
int * ptr = 0x1234; //Some Random address
now when you write ptr[3], it's 0x1234 + (sizeof(int) * 3).
So Pointer works irrespective of it's declared array size.
So when ptr = NULL,
*ptr[4] will point to NULL + (sizeof(int) * 4)
i.e. A Valid Operation!
ptr and var aren't compatible pointers because ptr is a pointer to an array of 3 ints and var is an array of 10 ints, 3 ≠ 10.
(*ptr)[4] works likely because the compiler doesn't do rigorous boundary checks when indexing arrays. This probably has to do with the fact that a lot of existing C code uses variable-size structures defined something like this:
typedef struct
{
int type;
size_t size; // actual number of chars in data[]
unsigned char data[1];
} DATA_PACKET;
The code allocates more memory to a DATA_PACKET* pointer than sizeof(DATA_PACKET), here it would be sizeof(DATA_PACKET)-1+how many chars need to be in data[].
So, the compiler ignores index=4 when dereferencing (*ptr)[4] even though it's >= 3 in the declaration int (*ptr)[3].
Also, the compiler cannot always keep track of arrays and their sizes when accessing them through pointers. Code analysis is hard.
ptr is a pointer to array of 3 integers, so ptr[0] will point to the start of the first array, ptr[1] will point to the start of the second array and so on.
In your case:
printf("%d",(*ptr)[4]);
works as you print the element no 5 of the first array
and
printf("%d",(*ptr+1)[4]);
print the element no 5 of the second array ( which of course doesn't exists)
for example the following is the same as yours
printf("%d",ptr[0][4]);
but this doesn't mean that you depend on this as var is array of 10 integers, so ptr has to be decelared as
int *ptr = NULL
in this case to print the element no 5
printf("%d", ptr[4]);