I tried to understand the size of address used to store variables and pointers, pointers-pointers and pointers-pointers-pointers. The results are kind of confusing.
Here is the code:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main(void)
{
char *** ppptr_string = NULL;
int *** ppptr_int = NULL;
double *** ppptr_dbl = NULL;
char c=0; int i=0; double d=0;
printf("\n %d %d %d %d %d\n", sizeof(&ppptr_string),
sizeof(ppptr_string), sizeof(*ppptr_string), sizeof(**ppptr_string),
sizeof(***ppptr_string));
printf("\n %d %d %d %d %d\n", sizeof(&ppptr_int), sizeof(ppptr_int),
sizeof(*ppptr_int), sizeof(**ppptr_int), sizeof(***ppptr_int));
printf("\n %d %d %d %d %d\n", sizeof(&ppptr_dbl), sizeof(ppptr_dbl),
sizeof(*ppptr_dbl), sizeof(**ppptr_dbl), sizeof(***ppptr_dbl));
printf("\n sizeof(char) = %d, sizeof(int) = %d, sizeof(double) = %d",
sizeof(c), sizeof(i), sizeof(d));
printf("\n sizeof(&char) = %d, sizeof(&int) = %d, sizeof(&double) = %d",
sizeof(&c), sizeof(&i), sizeof(&d));
getch();
return 0;
}
Now the confusion. I can see that a variable address is always 2 bytes long on this machine. Regardless of type of the variable and regardless of the whether its a pointer variable. But why do I get size of 4 for so many entries in here? The pointer has size 4 always regardless of the type. The >address< at which the variable is stored is of size 2. And the content pointed to has a sized depending on the type.
Why do I get 4s in the output for sizeof??
My output from Borland C++ 5.02
If you have a type T and a pointer on pointer like T*** ptr, then ptr, *ptr, **ptr are pointers themselves. You're probably working on a 32bit system (or compiling a 32bit application), so sizeof(ptr) == sizeof(*ptr) == sizeof(**ptr):
--- Program output ---
4 4 4 4 1
4 4 4 4 4
4 4 4 4 8
sizeof(char) = 1, sizeof(int) = 4, sizeof(double) = 8
sizeof(&char) = 4, sizeof(&int) = 4, sizeof(&double) = 4
&ptr is an address/a pointer on T***, so its size is 4 too. Only if you dereference the pointer to its maximum level (***ptr) you will have the actual type and not another pointer.
I think what's happening is that you're getting near (16-bit) pointers for local variables, but a pointer declared as type * is a far (32-bit) pointer.
It's a quirk of working on a 16-bit Intel processor (or a 32-bit processor in "real mode"), e.g. in DOS, where you only have access to 1 MB of memory (or 640 kB in practice). The upper 16 bits of a far pointer are a segment (a 64k page in memory), and the lower 16 bits are an offset.
http://en.wikipedia.org/wiki/Real_mode
http://wiki.answers.com/Q/What_are_near_far_and_huge_pointers_in_C
Answerers not able to reproduce this are most likely using a 32-bit (or more) OS on a 32-bit (or more) processor.
Related
#include <stdio.h>
int main(void)
{
int a = 0x4565;
long ch1;
int ch2;
printf("%p %p %p\n", &ch2, &ch1, &a);
printf("%zu %zu %zu\n", sizeof(long), sizeof (int), _Alignof(a));
return 0;
}
Output:
0x7fffebb487dc 0x7fffebb487e0 0x7fffebb487ec
8 4 4
If the alignment of int is 4 then why the space for the variable had not been allocated in 0x7fffebb487e8 ?
Why compiler gives extra 4 byte space (padding) ?
This happens only if int is allocate after variable which is the size of 8 (like pointer, long, long long).
If the preceding variable is type of int i.e. having size of and alignment of 4 the compiler gives no padding.
I am confused. Please help me.
Thank you.
Without optimization on, the compiler is assigning space naïvely and is working with the stack from high addresses to low, which is the direction the stack grows in.
Starting from an aligned address which ends in 0 (hex), it assign four bytes for a, putting it at an address that ends in C. Then, for the long ch1, it has to skip four bytes to get to the eight-byte-aligned address ending in 0. Finally, for ch2, it merely subtracts four bytes.
When you turn on optimization, a smarter algorithm will be used.
so if i run this code it will give the expected answer of 9
int main()
{
int a[]={9,8,7,6,5,4,3,2,1};
int n=sizeof(a)/sizeof(a[0]); printf("%d", n);
}
but if i change sizeof(a[0]) to sizeof(&a[0])..then the output is 4
Why does this happen? Exactly what does the computer 'think' when it is given sizeof(&a[0])?
&a[0] on an array a in C yields the address of its first element. On a 16-bit system, sizeof of that address is most likely 2, on a 32-bit system, sizeof that address it is 4, and, on a 64-bit system, it is 8.
I am trying to see that for a given function, memory allocation on stack segment of memory will happen in contiguous way. So, I wrote below code and I got below output.
For int allocation I see the memory address are coming as expected but not for character array. After memory address 0xbff1599c I was expecting next address to be 0xbff159a0 and not 0xbff159a3. Also, since char is 1 byte and I am using 4 bytes, so after 0xbff159a3 I was expecting 0xbff159a7 and not 0xbff159a8
All memory locations comes as expected if I remove char part but I am not able to get expected memory locations with character array.
My base assumption is that on stack segment, memory will always be contiguous. I hope that is not wrong.
#include <stdio.h>
int main(void)
{
int x = 10;
printf("Value of x is %d\n", x);
printf("Address of x is %p\n", &x);
printf("Dereferencing address of x gives %d\n", *(&x));
printf("\n");
int y = 20;
printf("Value of y is %d\n", y);
printf("Address of y is %p\n", &y);
printf("Dereferencing address of y gives %d\n", *(&y));
printf("\n");
char str[] = "abcd";
printf("Value of str is %s\n", str);
printf("Address of str is %p\n", &str);
printf("Dereferencing address of str gives %s\n", *(&str));
printf("\n");
int z = 30;
printf("Value of z is %d\n", z);
printf("Address of z is %p\n", &z);
printf("Dereferencing address of z gives %d\n", *(&z));
}
Output:
Value of x is 10
Address of x is 0xbff159ac
Dereferencing address of x gives 10
Value of y is 20
Address of y is 0xbff159a8
Dereferencing address of y gives 20
Value of str is abcd
Address of str is 0xbff159a3
Dereferencing address of str gives abcd
Value of z is 30
Address of z is 0xbff1599c
Dereferencing address of z gives 30
Also, since char is 1 byte and I am using 4 bytes, so after 0xbff159a3 I was expecting 0xbff159a7 and not 0xbff159a8
char takes up 1 byte , but str is string and you did not count '\0' which is at the end of string and thus ,char str[]="abcd" takes up 5 bytes.
I think this could be because the addresses are aligned to boundaries(e.g. 8 byte boundary)?.
The allocations are always aligned to boundaries and allocated in chunks
in some OS. You can check using a structure. For example,
struct A
{
char a;
char b;
int c;
};
The size of the struct will not be 6 bytes on a UNIX/LINUX platform.
But it might vary from OS to OS.
Similar thing apply to other data types also .
Moreover, a string just points to an address allocated in a
heap if malloc is used and the allocation logic might vary
from OS to OS. The following is output from Linux box
for the same program.
Value of x is 10
Address of x is 0x7ffffa43a50c
Dereferencing address of x gives 10
Value of y is 20
Address of y is 0x7ffffa43a508
Dereferencing address of y gives 20
Value of str is abcd
Address of str is 0x7ffffa43a500
Dereferencing address of str gives abcd
Value of z is 30
Address of z is 0x7ffffa43a4fc
Dereferencing address of z gives 30
Both answers from #ameyCU and #Umamahesh were good but none was self-sufficient so I am writing my answer and adding more information so that folks visiting further can get maximum knowledge.
I got that result because of concept called as Data structure alignment. As per this, computer will always try to allocate memory (whether in heap segment or stack segment or data segment, in my case it was stack segment) in chunks in such a way that it can read and write quickly.
When a modern computer reads from or writes to a memory address, it will do this in word sized chunks (e.g. 4 byte chunks on a 32-bit system) or larger. Data alignment means putting the data at a memory address equal to some multiple of the word size, which increases the system's performance due to the way the CPU handles memory.
On a 32 bits architecture, computers word size is 4 bytes, so computer will always try to allocate memory with addresses falling in multiple of 4, so that it can quickly read and write in block of 4 bytes. When there are lesser number of bytes then computer does padding of some empty bytes either in start or end.
In my case, suppose I use char str[] = "abc"; then including EOL character '\0' I have requirement of 4 bytes, so there will be no padding. But when I do char str[] = "abcd"; then including EOL character '\0' I have requirement of 5 bytes, now computer wants to allocate in block of 4 so it will add padding of 3 bytes (either in start or end) and hence complete char array will be spanned over 8 bytes in memory.
Since int, long memory requirement is already in multiple of 4 so there is no issue and it gets tricky with char or short which are not in multiple of 4. This explains the thing which I reported - "All memory locations comes as expected if I remove char part but I am not able to get expected memory locations with character array."
Rule of thumb is that if your memory requirement is not in multiple of 4 (for example, 1 short, char array of size 2) then extra padding will be added and then memory allocation will happen, so that computer can read and write quickly.
Below is nice excerpt from this answer which explains data structure alignment.
Suppose that you have the structure.
struct S {
short a;
int b;
char c, d;
};
Without alignment, it would be laid out in memory like this (assuming a 32-bit architecture):
0 1 2 3 4 5 6 7
|a|a|b|b|b|b|c|d| bytes
| | | words
The problem is that on some CPU architectures, the instruction to load a 4-byte integer from memory only works on word boundaries. So your program would have to fetch each half of b with separate instructions.
But if the memory was laid out as:
0 1 2 3 4 5 6 7 8 9 A B
|a|a| | |b|b|b|b|c|d| | |
| | | |
Then access to b becomes straightforward. (The disadvantage is that more memory is required, because of the padding bytes.)
void *memory;
unsigned int b=65535; //1111 1111 1111 1111 in binary
int i=0;
memory= &b;
for(i=0;i<100;i++){
printf("%d, %d, d\n", (char*)memory+i, *((unsigned int * )((char *) memory + i)));
}
I am trying to understand one thing.
(char*)memory+i - print out adress in range 2686636 - 2686735.
and when i store 65535 with memory= &b this should store this number at adress 2686636 and 2686637
because every adress is just one byte so 8 binary characters so when i print it out
*((unsigned int * )((char *) memory + i)) this should print 2686636, 255 and 2686637, 255
instead of it it prints 2686636, 65535 and 2686637, random number
I am trying to implement memory allocation. It is school project. This should represent memory. One adress should be one byte so header will be 2686636-2586639 (4 bytes for size of block) and 2586640 (1 byte char for free or used memory flag). Can someone explain it to me thanks.
Thanks for answers.
void *memory;
void *abc;
abc=memory;
for(i=0;i<100;i++){
*(int*)abc=0;
abc++;
}
*(int*)memory=16777215;
for(i=0;i<100;i++){
printf("%p, %c, %d\n", (char*)memory+i, *((char *)memory +i), *((char *)memory +i));
}
output is
0028FF94, , -1
0028FF95, , -1
0028FF96, , -1
0028FF97, , 0
0028FF98, , 0
0028FF99, , 0
0028FF9A, , 0
0028FF9B, , 0
i think it works. 255 only one -1, 65535 2 times -1 and 16777215 3 times -1.
In your program it seems that address of b is 2686636 and when you will write (char*)memory+i or (char*)&b+i it means this pointer is pointing to char so when you add one to it will jump to only one memory address i.e2686637 and so on till 2686735(i.e.(char*)2686636+99).
now when you are dereferencing i.e.*((unsigned int * )((char *) memory + i))) you are going to get the value at that memory address but you have given value to b only (whose address is 2686636).all other memory address have garbage values which you are printing.
so first you have to store some data at the rest of the addresses(2686637 to 2686735)
good luck..
i hope this will help
I did not mention this in my comments yesterday but it is obvious that your for loop from 0 to 100 overruns the size of an unsigned integer.
I simply ignored some of the obvious issues in the code and tried to give hints on the actual question you asked (difficult to do more than that on a handy :-)). Unfortunately I did not have time to complete this yesterday. So, with one day delay my hints for you.
Try to avoid making assumptions about how big a certain type is (like 2 bytes or 4 bytes). Even if your assumption holds true now, it might change if you switch the compiler or switch to another platform. So use sizeof(type) consequently throughout the code. For a longer discussion on this you might want to take a look at: size of int, long a.s.o. on Stack Overflow. The standard mandates only the ranges a certain type should be able to hold (0-65535 for unsigned int) so a minimal size for types only. This means that the size of int might (and tipically is) bigger than 2 bytes. Beyond primitive types sizeof helps you also with computing the size of structures where due to memory alignment && packing the size of a structure might be different from what you would "expect" by simply looking at its attributes. So the sizeof operator is your friend.
Make sure you use the correct formatting in printf.
Be carefull with pointer arithmetic and casting since the result depends on the type of the pointer (and obviously on the value of the integer you add with).
I.e.
(unsigned int*)memory + 1 != (unsigned char*)memory + 1
(unsigned int*)memory + 1 == (unsigned char*)memory + 1 * sizeof(unsigned int)
Below is how I would write the code:
//check how big is int on our platform for illustrative purposes
printf("Sizeof int: %d bytes\n", sizeof(unsigned int));
//we initialize b with maximum representable value for unsigned int
//include <limits.h> for UINT_MAX
unsigned int b = UINT_MAX; //0xffffffff (if sizeof(unsigned int) is 4)
//we print out the value and its hexadecimal representation
printf("B=%u 0x%X\n", b, b);
//we take the address of b and store it in a void pointer
void* memory= &b;
int i = 0;
//we loop the unsigned chars starting at the address of b up to the sizeof(b)
//(in our case b is unsigned int) using sizeof(b) is better since if we change the type of b
//we do not have to remember to change the sizeof in the for loop. The loop works just the same
for(i=0; i<sizeof(b); ++i)
{
//here we kept %d for formating the individual bytes to represent their value as numbers
//we cast to unsigned char since char might be signed (so from -128 to 127) on a particular
//platform and we want to illustrate that the expected (all bytes 1 -> printed value 255) occurs.
printf("%p, %d\n", (unsigned char *)memory + i, *((unsigned char *) memory + i));
}
I hope you will find this helpfull. And good luck with your school assignment, I hope you learned something you can use now and in the future :-).
How i can know the size of all data type in my computer?
The following program should do the trick for the primitive types:
#include <stdio.h>
int main()
{
printf("sizeof(char) = %d\n", sizeof(char));
printf("sizeof(short) = %d\n", sizeof(short));
printf("sizeof(int) = %d\n", sizeof(int));
printf("sizeof(long) = %d\n", sizeof(long));
printf("sizeof(long long) = %d\n", sizeof(long long));
printf("sizeof(float) = %d\n", sizeof(float));
printf("sizeof(double) = %d\n", sizeof(double));
printf("sizeof(long double) = %d\n", sizeof(long double));
return 0;
}
This prints the number of "bytes" the type uses, with sizeof(char) == 1 by definition. Just what 1 means (that is how many bits that is) is implementation specific and likely depend on the underlying hardware. Some machines have 7 bit bytes for instance, some have 10 or 12 bit bytes.
You can apply sizeof to each type whose size you need to know and then you can print the result.
sizeof(T) will give you the size of any type passed to it. If you're trying to find out the size of all data types used or defined in a particular program, you won't be able to--C doesn't maintain that level of information when compiling.
Use sizeof to get the size of the type of variable (measured in bytes).
For example:
#include <stdint.h>
sizeof(int32_t) will return 4
sizeof(char) will return 1
int64_t a;
sizeof a; will return 8
See http://publications.gbdirect.co.uk/c_book/chapter5/sizeof_and_malloc.html