Assignment of pointers? - c

int arr[]={1,2,3};
char* p;
p=arr;
This is a fragment of a program and it works.
Can anyone explain how can an int variable address be assigned to char pointer?

This works, because size of char pointer is the same as size of an int pointer. However, when some pointer arithmetic will be applied, you won't get valid results. It means that if you would like to access second element of your array - p[1] then only one byte would added to the p address. If p would be of type int, then 4 byte would be added (since that's the size of int) and second element would be accessed properly.
#include <stdio.h>
int main(void)
{
int arr[] = {1,2,3};
char* p;
p = arr;
printf("%d\n", p[0]);
printf("%d\n", p[1]);
int* pp = arr;
printf("%d\n", pp[0]);
printf("%d\n", pp[1]);
return 0;
}
output:
1
0 - as you can see that is not the value from arr[1]
1
2
As I have intel processor, which is in little endian, arr[0] in memory is stored as following:
01 00 00 00
^
p[0]
p[1] which is equivalent to *(p + 1), will add one byte to p pointer, because size of p is char.
01 00 00 00
^
p[1]
and printf("%d\n, p[1]); gives 0. Note that if you were on big endian machine, the result of printing p[0] would be different (e.g. 0).
However, your compiler should warn you about what you're doing.
warning: assignment from incompatible pointer type [enabled by
default]

When you assign a char point to the address of integer array, many things can happen, depending on the size of the integer. Below is the memory location of the array in compile under 32 bit windows OS. You may also want to cast it p=(char*)arr.
01 00 00 00 02 00 00 00 03 00 00 00
int arr[]={1,2,3};
// arr[0] = 1;
// arr[1] = 2;
// arr[2] = 3;
char* p;
p=(char*)arr;
// p[0] = 1
// p[1] = 0
// p[2] = 0
// p[3] = 0
// p[4] = 2
// p[5] = 0
// p[6] = 0
// p[7] = 0
// p[8] = 3
// p[9] = 0
// p[10] = 0
// p[11] = 0

Your code is invalid. In C language an int * pointer cannot be assigned to a char * pointer without an explicit conversion. C language prohibits assignment of incompatible pointer types. (I.e. it prohibits implicit conversion between such types). Your compiler probably issued a diagnostic message telling you exactly the same thing. Your code contains constraint violation - it is not a valid C code.
This conversion was legal a long time ago, in archaic non-standardized versions of C language. For that reason, by default C compilers are rather permissive with regard to invalid code of this kind. They issue diagnostic messages as "warnings", but continue to compile the code, which misleads some people into believing that the code is valid.
Many C compilers offer you additional options that make them more explicit in detecting such errors. For example, in GCC you have to specify -pedantic-errors switch to have this constraint violation reported with an "error" message.
If your compiler accepted the code, its behavior is the same as if you wrote p = (char *) arr, i.e. it makes p point to the beginning of the arr array. That's all there is to it. If you attempt to access the array data through pointer p, you will simply reinterpret the memory occupied by arr as a sequence of chars. What you will see there will depend on many implementation-dependent factors. (I.e. there are no universal answers to your "Why do I see 0 there? Why do I see 2 there?" questions.) For example, the reinterpreted data will look different between big-endian and little-endian platforms.

Yes you can assign a address of variable of any type to pointer of any type (however you may get a warning about assigning incompatible pointer type). This is because sizeof pointer of any type is same.
For Example:-
int main(void)
{
char *c;
int *i;
float *f;
printf("%d %d %d",sizeof(c),sizeof(i),sizeof(f)); // Output: 4 4 4
}
Side effect of this:
Consider the following example:
int main(void)
{
int i1=127;
int i2=128;
char *c1=&i1;
char *c2=&i2;
printf("%d %d",*c1,*c2); //Output : 127 -128
}
In order to understand this output you need to consider binary values of variables.
Lets start with i1:- Binary value of i1 is
00000000 00000000 00000000 01111111
and by assigning address of this memory to char pointer causes char pointer c1 to point to first byte (Little Endian Method) .
Now binary value of i2 is
00000000 00000000 00000000 10000000
here again c2 points to first byte but why output is -128?
because first byte is 10000000 that sign bit is 1 which means number is negative
now perform a reverse operation of 2's complement
10000000 ---> 01111111(minus one) --->10000000(one's complement)

Your compiler should give you a warning that this is not compatible.
After assignment , lets say address of arr is 1000, arr[0] will be at address 1000, arr[1] will be at address 1004 and arr[2] will be at address 1008
Now p points to arr, so it points to address 1000, so every time you want to access arr[1] you will have to use *(p + 4) since char is 1 byte only (Also care should be taken if its a little endian or big endian machine)
Though its incompatible you can use it but you should be carefull when you use this assignment.
gdb output.
(gdb) p *p
$8 = 1 '\001'
(gdb) p *(p+1)
$9 = 0 '\000'
(gdb) p *(p+2)
$10 = 0 '\000'
(gdb) p *(p+3)
$11 = 0 '\000'
(gdb) p *(p+4)
$12 = 2 '\002'
(gdb) p *(p+5)
$13 = 0 '\000'
(gdb) p *(p+6)
$14 = 0 '\000'
(gdb) p *(p+7)
$15 = 0 '\000'
(gdb) p *(p+8)
$16 = 3 '\003'

Related

why the value of *p0 is having a different value every time in the compilation. here is the code for the the problem in c language .?

<#include <stdio.h>
int main()
{
//type casting in pointers
int a = 500; //value is assgned
int *p; //pointer p
p = &a; //stores the address in the pointer
printf("p=%d\n*p=%d", p, *p);
printf("\np+1=%d\n*(p+1)=%d", p + 1, *(p + 1));
char *p0;
p0 = (char *)p;
printf("\n\np0=%d\n*p0=%d", p0, *p0);
return 0;
}
I was exploring the pointers in the C language and found a problem in finding the value at the address of
the char pointer when I converted it from a integer pointer.
Tell me how it works and explain please
To print a pointer use %p and cast the argument to (void*).
Like
printf("p=%p\n*p=%d", (void*)p, *p);
Reading p + 1, i.e. doing *(p + 1), is undefined behavior because p + 1 doesn't point to an int. So don't do that!
In a comment OP asks:
p=6487564 *p=500 p+1=6487568 *(p+1)=0 p0=6487564 *p0=-12
these are the output i am getting why *p0 is -12 pz explain
The decimal value 500 is the same as the hexadecimal value 0x000001F4. On a little endian machine (with 32 bit int) this is stored like:
p -> F4 01 00 00
Then you assign p0 the value of p so you have
p -> F4 01 00 00
^
|
p0
so p0 points to 0xF4 (assuming 8 bit char).
On a machine with signed chars, the hex value 0xF4 is the decimal value -12 (i.e. signed 8 bit 2's complement representation).
Conclusion On a little endian machine with signed 8 bit chars the printed value will be -12.
If you change
char *p0;
p0 = (char *)p;
to
unsigned char *p0;
p0 = (unsigned char *)p;
then it will print 244. That may be easier to understand because 500 is 256 + 244 (or in hex: 0x1F4 = 0x100 + 0xF4).

Cannot get pointers result

#include<stdio.h>
void main()
{
int v=10;
char *p=&v;
int i;
for(i=0;i<10;i++,p++)
{
++(*p);
printf("%d",v);
}
}
Output
11
267
65803
16843019
16843019
16843019
I am not getting how output came like this please explain
I can only assume, that an expected behavior is to get variable v incremented 10 times using pointer.
If that's correct, you have two mistakes:
Type of pointer should be the same with the data you're pointing. If you're pointing at int variable, you should use int * pointer.
In the for loop condition: at each iteration you're incrementing both i and p (i++,p++).
When you're incrementing pointer, it moves to the next memory cell (in simple words, actually it's a bit complicated).
If you want to work with variable v only, you should not modify the pointer itself, only the variable it refers to.
Thus, if you'll remove p++ part , you'll get 11, 12, 13, ... as a result.
Why it shows such a weird results now? Just because at each iteration you're changing pointer (thus it refers to other memory cell). Memory that pointer refers to after increment may contain random data, which we are able to see. However, such an approach contains undefined behavior, and results may vary. It may even end with termination of the program.
However, it's indeed not clear what behavior are you expecting to get, and if you'll clarify that more, I guess community will be able to help you more.
I am not getting how output came like this please explain
First let's make some minor changes to your code and print the values in hex:
int main() {
int v = 10;
char *p = (char*)&v;
int i;
printf("%8d (0x%08x)\n", v, v);
for(i=0; i<sizeof(i); i++, p++)
{
++(*p);
printf("%8d (0x%08x)\n", v, v);
}
return 0;
}
Output:
10 (0x0000000a)
11 (0x0000000b)
267 (0x0000010b)
65803 (0x0001010b)
16843019 (0x0101010b)
So what happens here is that the int is four bytes - consequently I get 4 values printed by the loop (plus the print before the loop).
Since p is a char pointer and my system is little endian, p will first point to the LSB (least significant byte) of the integer, i.e. "0a", and increment that byte to "0b".
When p is incremented by p++ it will point to the next byte, i.e. "00" and increment that byte to "01". So now the integer holds "0000010b" (267 decimal). This step is repeated twice so that the integer first become "0001010b" (65803 decimal) and then "0101010b" (16843019 decimal).
In memory it looks like:
After initialization: 0a 00 00 00
^
|
p
After loop 1: 0b 00 00 00
^
|
p
After loop 2: 0b 01 00 00
^
|
p
After loop 2: 0b 01 01 00
^
|
p
After loop 4: 0b 01 01 01
^
|
p
BTW: Notice that the standard gives no guarantees about this behavior. Updating bytes inside an integer using a char pointer is not well defined by the standard.

Why is the output 2,0 instead of 2,3?

#include<stdio.h>
int main()
{
int arr[3] = {2, 3, 4};
char *p;
p = arr;
p = (char*)((int*)(p));
printf("%d, ", *p);
p = (int*)(p+1);
printf("%d", *p);
return 0;
}
Isn't p = (int*)(p+1) ; pointing to the next element of the array? (viz 3?) So the output should be 2,3. But the output is 2,0. Why?
You are increasing the char pointer p to the next char memory position - that is one of the 0 padding bytes for the number 2, which, being an int takes 4 memory positions (the other 3 filled up with zeros).
In short, just replace char *p; for int *p; and get rid of all the casting at p = (char*)((int*)(p)); - your program should just work.
(To make it working keeping the not-useful casting, change p = (int*)(p+1); for p = (char *) (((int *) p) + 1); so that the increment happens on an integer pointer, not on a char pointer)
In a little-endian memory model, such as used in current PC´s, int numbers each take 4 bytes in memory - the first one being the least significative (so, for numbers smaller than 256 (2 ^ 8), they contain the whole number).
You have in memory, this byte sequence: '02 00 00 00 03 00 00 00 04 00 00 00'
When you use a "char *" pointer, the compiler knows that the size of the char data element is 1 byte. On increasing it, it just proceeds to the neighbouring byte, which is "0".
On the "printf" call, you access the content at "char * p", which is a single byte number - 0, and the compiler pads that value in the call to "printf", so that the function still sees "0" - but in other compielrs and systems, it could print garbage or segfault, since 3 of the bytes expected by the printf's "%d" parameter would not be there.
That's because p is the wrong kind of pointer for the datatype.
When you increment p, it doesn't increase its value by 1 * sizeof(int), it increases it by 1 * sizeof(char).
The contents of arr at the byte level, assuming an int is 4 bytes and little endian byte ordering is:
2 0 0 0 3 0 0 0 4 0 0 0
When p is first set, you have this:
2 0 0 0 3 0 0 0 4 0 0 0
^------ p
When you set p to (int*)(p + 1), you increment p by only 1. The cast doesn't help you here. So you get this:
2 0 0 0 3 0 0 0 4 0 0 0
^------ p
So dereferencing p reads 1 byte at that memory location, so you have 0.
If you wanted to increment p by the size of an int, you need to cast p itself, then add to it:
p = `(int*)(p) + 1`
Then you'll get the result you expect.
This is why type of pointer should be of the same data type as of the data it's pointing to for the sake of Pointer Arithmatics
adding 1 to a pointer of specific data type will add number of bytes to the memory address to which a pointer is currently pointing and now it will be pointing to the p+(x-bytes) address and de referencing it will give you the value at that address
for example
you declare a pointer of type int like
int *p = new int[5];
each element in array(if you populate the array) will be stored in memory with the space of 4 bytes (in address terms and in case of 32bit systems) in memory.
And adding 1 to pointer like p = p+1 will take you to the next element in array which is at 4 byte's address ahead of it.
same is the case for any other type of pointer just with the difference that it will be jumping to that much bytes in address space as of the data type the pointer itself it.
now you can say pointer are just pointing to memory so it should not make any difference whether we declare any type of pointer. Yes that's true but not recommended any time as when you're using pointers , pointer arithmatic is very certain to be used there. For the sake of exact jumps in memory addresses we declare pointers of the same data type as of the data they are pointing to

Char pointer to integer array

int main()
{
int x[] = {1, 2, 3};
char *p = &x;
printf("%d", *(p+1));
return 0;
}
I run the code in codeblocks and it is giving 0 as output.
If I I change p as int pointer then its giving 2 as output.
int main()
{
int x[] = {1, 2, 3};
int *p = &x;
printf("%d", *(p+1));
return 0;
}
Why so?
When p is declared as a pointer to char, it is expected to point at data with size of 1 byte. So (p + 1) increments p by 1 byte.
Since an int is at least 4 bytes long, (p + 1) is likely pointing to the second of the higher order bytes of 1, which is still 0.
If you wanted it to have identical output, you would do something like that
printf("%d\n", *(p + sizeof(int)));
But it's best to avoid such code and compile with the -Wall flag, which would definitely produce a warning in your case.
Assume sizeof(int) is 16 bits. 2 in binary is 00000000 00000010.
sizeof(char) is 8 bits.
Little and big endian are two ways of storing multibyte data-types.
Consider the following code:
int i = 2;
char c = (char)&i;
if ((*c)==2)
printf("Little endian");
else //if *c is 0
printf("Big endian");
From this code you can conclude that Big Endian will store 2 as 00000000 00000010. But Little Endian will store it as 00000010 00000000. , So zero as output would mean first 8 bits are zero, so system is Big Endian. Had it been using Little Endian, answer would be 2 as a char p is supposed to point 8 bits only.
Actually, declaring the data type of pointer means to specify how any bits do you want it to refer and how many bits it will jump when incremented.
If in this example, as p is a char pointer, *(p+1) will refer 00000010 in Big endian and 00000000 in Little Endian.
Your compiler may be using 32 bit for interger, so i think in both cases *(p+1) will give 0. (as 2 => 00000000 00000000 00000000 00000010 2nd byte from either side is 0)
Refer to this: `#include
int main()
{
int x[] = {1, 2, 3};
char *p = &x;
printf("%d\n", *p);
printf("%d\n", *(p+1));
printf("%d\n", *(p+2));
printf("%d\n", *(p+3));
printf("%d\n", *(p+4));
printf("%d\n", *(p+5));
printf("%d\n", *(p+6));
printf("%d\n", *(p+7));
printf("%d\n", *(p+8));
return 0;
}`
Output:
1
0
0
0
2
0
0
3
To have a look from a slightly different angle, about the binary + operator, chapter 6.5.6, paragraph 8 of C99 standard says, [emphasis mine]
When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and
(P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist.
So, in your First case, p is of type char * and (p + 1) gives a result as a pointer which is incremented by sizeof(char)[that's 1 byte, most of the cases] and hence points to the 2nd element of the char array held by p. Since actually, the array held by p is of type int [Let's say 4 bytes of length, in a 32 bit system], so as per the value stored, [1 getting stored as 0000 0000 0000 0001], the *(p+1) prints out 0.
OTOH, in your second case, p is of type int * and (p + 1) gives a result as a pointer which is incremented by sizeof(int) and hence points to the 2nd element of the int array held by p. Since actually, the array held by p is of type int, so as per the value stored, [int x[] = {1, 2, 3};], the *(p+1) prints out 2.
When you increment a pointer, it moves by the size of the thing it is pointing to.
Let's say you have 16 bit integers. In binary, the number one is: 0000 0000 0000 0001
A char pointer can only point to 8 bits at a time: 0000 0000

Which of the following is the correct output for the program given below?

if the machine is 32bit little-endianess and the sizeof(int) is 4 byte.
Given the following program:
line1: #include<stdio.h>
line2: {
line3: int arr[3]={2,3,4};
line4: char *p;
line5: p=(char*)arr;
line6: printf("%d",*p);
line7: p=p+1;
line8: printf("%d\n",*p);
line9: return 0;
}
What is the expected output?
A: 2 3
B: 2 0
C: 1 0
D: garbage value
one thing that bothering me the casting of the integer pointer to an character pointer.
How important the casting is?
What is the compiler doing at line 5? (p = (char *) arr;)
What is happening at line 7? (p = p + 1)
If the output is 20 then how the 0 is being printed out?
(E) none of the above
However, provided that (a) you are on a little-endian machine (e.g. x86), and (b) sizeof(int) >= 2, this should print "20" (no space is printed between the two).
a) the casting is "necessary" to read the array one byte at a time instead of as a series of ints
b) this is just coercing the address of the first int into a pointer to char
c) increment the address stored in p by sizeof(char) (which is 1)
d) the second byte of the machine representation of the int is printed by line 8
(D), or compiler specific, as sizeof(int) (as well as endianness) is platform-dependent.
How important the casting is?
Casting, as a whole is an integral (pun unintended) part of the C language.
and what the compilar would do in line number5?
It takes the address of the first element of arr and puts it in p.
and after line number 5 whats going on line number7?
It increments the pointer so it points to the next char from that memory address.
and if the output is 2 0 then how the 0 is being printed by the compiler?
This is a combination of endanness and sizeof(int). Without the specs of your machine, there isn't much else I can do to explain.
However, assuming little endian and sizeof(int) == 4, we can see the following:
// lets mark these memory regions: |A|B|C|D|
int i = 2; // represented as 0x02000000
char *ptr = (char *) &i; // now ptr points to 0x02 (A)
printf("%d\n", *ptr); // prints '2', because ptr points to 0x02 (A)
ptr++; // increment ptr, ptr now points to 0x00 (B)
printf("%d\n", *ptr); // prints '0', because ptr points to 0x00 (B)
1.important of casting:-
char *p;
this line declare a pointer to a character.That means its property is it can de-reference
only one byte at a time,and also displacement are one one byte.
p=(char*)arr;
2. type casting to char * is only for avoid warning by compiler nothing else.
If you don't then also same behavior.
as pointer to a character as I already write above p=p+1 point to next byte
printf("%d\n",*p);
%d is formatting the value to decimal integer so decimal format shown
here *p used and as per its property it can de-reference only one byte.So now memory organisation comes into picture.
that is your machine follows little endian/LSB first or big endian/MSB first
as per your ans your machine follow little endian.So first time your ans is 0.
Then next byte must be zero so output is 0.
in binary:
2 represented as 00-00-00-02(byte wise representation)
but in memory it stores like
02-00-00-00 four bytes like this
in first memory byte 02
and in 2nd memory byte 00

Resources