How can one address can store more than one value? - c

Question is given in title:
I dont know why is this happening.
Can someone tell me how such tricks works.
Here is my code:
#include<stdio.h>
int main(){
int a = 320;
char *ptr;
printf("%p\n",&a);
ptr =( char *)&a;
printf("%p\n",ptr);
printf("%d\n",a);
printf("%d\n",*ptr);
return 0;
}
Output:
0x7fffc068708c
0x7fffc068708c
320
64

There is only one value stored.
The second printf takes the first char's worth of data at that address, promotes it to int, and prints the result. The first prints the whole int.
(320 == 256 + 64, or 0x140 == 0x01 0x40)

The actual data at 0x7fffc068708c is 0x00000140.
That's 320 in decimal.
But if you access it via ptr =( char *)&a;, then you only get 0x40.
That's 64 in decimal.

Simple, really: using a char pointer, you get rid of any extra bit of data above a byte:
a = 320
0x 00 00 00 00 01 40
| a | -> 0x 00000140 = 320
|ptr| -> 0x 40 = 64
You "see" two values because you don't use all the precision available to you.
You would have "seen" one value if you had used a short instead of a char, but really, it's just how you interpret the data.

The point is while assingning a to ptr you saying it is a pointer to a character and not a integer. Change that and try

Related

What type casting address, when assigning to pointer, does?

I'm working on understanding C and I came across this example:
int main()
{
double d = 010;
unsigned *pi = (unsigned *) &d;
printf("%x", *++pi);
}
So d has value of 8 in decimal numerical system, 0 10000000010 000... in binary and 40200000 in hexadecimal. I don't understand what this typecast of address does. Why doesn't *pi get hexadecimal value, but instead it prints 0? When it's address is incremented and then dereferenced it get's right hexadecimal value. Why?
The code actually has undefined behavior because of the aliasing rule: you are accessing the representation of the double variable with a pointer to another type that is not a character type.
The intent is to print the 32-bits from the bytes 4 to 7 of the double variable, which are all 0 because of the way 8.0 is represented on your architecture.
The cast tells the compiler to convert the pointer to another type of pointer. This usually does not change its value, but dereferencing the resulting pointer may produce undefined behavior, except for character types.
Here is a modified version that is portable and prints the byte values:
#include <stdio.h>
int main() {
double d = 010;
unsigned char *p = (unsigned char*)&d;
int n = sizeof(double);
while (n --> 0) {
printf("%02x ", *p++);
}
printf("\n");
return 0;
}
Output on an Intel Mac (little endian): 00 00 00 00 00 00 20 40
Output on a big-endian system: 40 20 00 00 00 00 00 00

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.

int to hex conversion not going proper for high values 225943 is being converted into 0x000372ffffff97

My C program takes a random int high value and convert it into hex and write it to a file. Everything goes well if the value is 225919 or less
eg. 225875 is 00 03 72 53
but if the value is above 225919 it starts writing extra ffffff for last byte in the hex value example 885943 is 00 03 72 ffffff97, while the right value would have been 00 03 72 97.
Code that writes the value into file is as follows:
char *temp = NULL;
int cze = 225943;
temp = (char *)(&cze);
for (ii = 3; ii >= 0; ii--) {
printf(" %02x ", temp[ii]); //just for printing the values
fprintf(in, "%02x", temp[ii]);
}
Output is: 00 03 72 ffffff97
Expected output: 00 03 72 97
Please help, any pointer is appreciated.
Your temp array contains char values, which in most cases means signed char. The values are then being printed as signed chars, so any byte greater than 0x7f is considered a negative value. When that value is passed to printf, it is implicitly converted to int. This adds one or more bytes containing all 1 bits if the number is negative.
Change the datatype to unsigned char. This will cause the implicit promotion to change to unsigned int and you'll get the correct values.
unsigned char *temp=NULL;
int cze=225943;
temp=(unsigned char *)(&cze);
for(ii=3;ii>=0;ii--){
printf(" %02x ",temp[ii] );//just for printing the values
fprintf(in,"%02x",temp[ii]);
}
Alternately, you can use the hh length modifier in printf, which tells it that the argument is a char or unsigned char. This will restrict it to printing 1 byte's worth of data.
printf(" %02hhx ",temp[ii] );

Need clarification about unsigned char * in C

Given the code:
...
int x = 123
...
unsigned char * xx = (char *) & x;
...
I have xx[0] = 123, xx[1] = 0, xx[2] = 0, etc.
Can someone explain what is happening here? I dont have a great understanding of pointers in general, so the simpler the better.
Thanks
You're accessing the bytes (chars) of a little-endian int in sequence. The number 123 in an int on a little-endian system will usually be stored as {123,0,0,0}. If your number had been 783 (256 * 3 + 15), it would be stored as {15,3,0,0}.
I'll try to explain all the pieces in ASCII pictures.
int x = 123;
Here, x is the symbol representing a location of type int. Type int uses 4 bytes of memory on a 32-bit machine, or 8 bytes on a 64-bit machine. This can be compiler dependent as well. But for this discussion, let's assume 32-bits (4 bytes).
Memory on x86 is managed "little endian", meaning if a number requires multiple bytes (it's value is > 255 unsigned, or > 127 signed, single byte values), then the number is stored with the least significant byte in the lowest address. If your number were hexadecimal, 0x12345678, then it would be stored as:
x: 78 <-- address that `x` represents
56 <-- x addr + 1 byte
34 <-- x addr + 2 bytes
12 <-- x addr + 3 bytes
Your number, decimal 123, is 7B hex, or 0000007B (all 4 bytes shown), so would look like:
x: 7B <-- address that `x` represents
00 <-- x addr + 1 byte
00 <-- x addr + 2 bytes
00 <-- x addr + 3 bytes
To make this clearer, let's make up a memory address for x, say, 0x00001000. Then the byte locations would have the following values:
Address Value
x: 00001000 7B
00001001 00
00001002 00
00001003 00
Now you have:
unsigned char * xx = (char *) & x;
Which defines a pointer to an unsigned char (an 8-bit, or 1-byte unsigned value, ranging 0-255) whose value is the address of your integer x. In other words, the value contained at location xx is 0x00001000.
xx: 00
10
00
00
The ampersand (&) indicates you want the address of x. And, technically, the declaration isn't correct. It really should be cast properly as:
unsigned char * xx = (unsigned char *) & x;
So now you have a pointer, or address, stored in the variable xx. That address points to x:
Address Value
x: 00001000 7B <-- xx points HERE (xx has the value 0x00001000)
00001001 00
00001002 00
00001003 00
The value of xx[0] is what xx points to offset by 0 bytes. It's offset by bytes because the type of xx is a pointer to an unsigned char which is one byte. Therefore, each offset count from xx is by the size of that type. The value of xx[1] is just one byte higher in memory, which is the value 00. And so on. Pictorially:
Address Value
x: 00001000 7B <-- xx[0], or the value at `xx` + 0
00001001 00 <-- xx[1], or the value at `xx` + 1
00001002 00 <-- xx[2], or the value at `xx` + 2
00001003 00 <-- xx[3], or the value at `xx` + 3
Yeah, you're doing something you shouldn't be doing...
That said... One part of the result is you're working on a little Endian processor. The int x = 123; statement allocates 4 bytes on the stack and intializes it with the value 123; Since it is little Endian, the memory looks like 123, 0, 0, 0 in memory. If it was big Endian, it would be 0, 0, 0, 123. Your char pointer is pointing to the first byte of memory where x is stored.
unsigned char * xx = (char *) & x;
You take the address of x, you tell the compiler it is a pointer to a character[string], you assign that to xx, which is a pointer to a character[string]. The cast to (char *) just keeps the compiler happy.
Now if you print xx, or inspect it, it can depend on the machine what you see - the so-called little-endian ot big-endian way of storing integers. X86 is little endian and stores the bytes of the integer in reverse. So storing 0x00000123 will store 0x23 0x01 0x00 0x00, which is what you see when inspecting the location xx points to as characters.

Integer Conversion for Char Array

I've been trying to brush up on my C recently and was writing a program to manually parse through a PNG file.
I viewed the PNG file in a hex editor and noticed a stream of bytes that looked like
00 00 00 0D
in hex format.
This string supposedly represents a length that I am interested in.
I used getc(file) to pull in the bytes of the PNG file.
I created a char array as
char example[8];
to store the characters retrieved from getc.
Now, I have populated example and printing it with
printf("%#x, %#x, %#x, %#x", example[0]....
shows 0, 0, 0, 0xd which is exactly what I want.
However when I use
int x = atoi(example)
or
int x = strtol(example, NULL, 16)
I get back zero in both cases (I was expecting 13). Am I missing something fundamental?
atoi converts strings like "0" to its numeric equivalent, in this case 0. What you have instead is the string "\0\0\0\0\0\0\0\r" which is nowhere near numeric characters.
If you want to interpret your bytes as a number you could do something like
char example[4] = {0, 0, 0, 0xd};
printf("%d\n", *(uint32_t*) example);
You will notice (in case you're using a x86 CPU) that you will get 218103808 instead of 13
due to little endianness: the farther you go right the more significant the number gets.
As PNG uses big endian you can simply use be32toh (big endian to host endianess):
uint32_t* n = example;
printf("%u\n", be32toh(*n)
atoi and strtol expect text strings, while you have an array of binary values. To combine the individual bytes in an array to a larger integer, try something like:
uint32_t x = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
atoi etc. operates on (ascii) strings.
You would get 123 for "123", which is in bytes 49 50 41 0.
What you have instead is binary 00 00 00 7B ... (well, endianess matters too).
Simple, but in this case wrong solution (ignoring endianess):
Cast the array address to int* and then get a value with *.
As integers in PNG are supposed to be big endian in any case,
the pointer casting would only work with big endian machines.
As portable solution, shifting the bytes with 24,16,8,0 and binary-orĀ“ing them will do.

Resources