Unexpected memory allocation in stack segment - c

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.)

Related

Weird alignment behaviour in C

#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.

Pointer in arrays. How does it work "physically" in memory?

I have been wondering about pointers and can't find a source explaining them with details.
For example. Given an array int a[3]
There is a pointer pointing at 4 locations?
It starts as *[a+0] and points at address of a?
Then what does it do next? Int is minimum of 16 bites, so it needs to read 2 bytes, but every byte is given an address.
Does it mean that for a[0] the pointer points at the beginning address, then the program reads sizeof(int) bytes starting at the given address?
What would it do the next? Would it stop reading, give the result and
for a[1] would it point at address of &a+1*sizeof(int).
It would start reading at address of (&a+2(as 2 stands for already read addresses of 2 bytes)), start reading, so it would read another 2 bytes and on and on?
I can't quite understand these concepts.
PS: String consist of unsigned char which are 1 byte elements.
The post you mentioned doesn't explain what happens with elements larger than 1 byte. It also doesn't explain exactly what the program does beside "here is a string the program reads from memory". I assume that I am right, but nonetheless the title you mentioned is far away from what I asked about.
(since somebody wrote this already, one address stands for one byte)
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|----|----|----|----|----|----| | | | | | | | | | |
0----+----01---+----12---+----2----+----+----+----+----+----+----+----+----+----+
I specifically asked if
int a[2] means that the pointer first:
Points at memory address (54), the program reads data from 2 following addresses (54 to 54 as int takes 2 bytes), then the pointer points at address 54+2, the program starts reading from address range <56,57>. Then again, the pointer points at starting range of 58, the program reads at address of <58,59>
Is this logic correct? It isn't a string ended up with NULL.
My guess to strings is that the program would access memory byte's address by byte's address and read the values till it found NULL.
Arrays aren't strings.
Consider
int a[3] = {};
int b[300] = {};
These 2 arrays are "similar" in that they contain values of int and are different in these two major regards:
They are of different "size" - that is the memory they point to is reserved with different amount for each. The first array points to a memory that is reserved to hold at least 3 int values. However that is the minimum allocated memory (in this case - on a stack, so most likely it is also a precise amount of memory allocated for it as well)
They point to different addresses in memory (again - in this case they are both allocated on a stack but it is still a RAM)
You can just as easily take an address of the first element of either array:
int * p = a;
p = &a[0]; // same as above
p = b; // now p points to the first element of the second array
When you perform an indexing operation what the compiler does is: it takes the address of the first element and increments it by a value that is equal to the index times the size of each element (if there's no padding due to alignment, of course). In essence the compiler is doing this:
b[1] = 1;
*(p+1) = 1; // same as above
uint8_t * c = reinterpret_cast<uint8_t*>(p); // WARNING! Explanation follows
The last line will cause the compiler to reinterpret the pointer differently and "the same" address arithmetic "suddenly" works differently:
c[1] = 1; // this is NOT the same as b[1] = 1
In this case the compiler will only "move" the pointer 8-bits (not 16 or 32 bits, depending on your platform's sizeof(int)) and end up in the middle of that first int element of array b. Granted this can be useful (especially when dealing directly with hardware) but is super-duper-puper non-portable and you should avoid doing so at all times!
This is admittedly not a comprehensive answer but I was not aiming to provide one as the topic is very vast and there are plenty of resources on the Web that can provide you with many more details on this subject

Understanding the stack address manipulation

Consider the following piece of code (on a 32-bit Intel/Linux system):
struct mystruct {
char a;
int b;
short c;
char d;
};
int main()
{
struct mystruct foo[3];
char ch;
int i;
printf("%p %p %p %p %p\n", &foo[0], &foo[1], &foo[2], &ch, &i);
return 0;
}
Which of the following would be the most likely candidate for its output?
0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8f 0xfeeece88
0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeeceb4 0xfeeeceb8
0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeeceb4 0xfeeeceb5
0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8c 0xfeeece88
The output is option (1). I could not understand, how the option a is the right answer..
Stack grows from higher addresses to lower addresses. Here foo[3], foo[2], foo[1], foo[0], ch, i ... i will be at the lower address of stack and foo[3] at the higher address. Here the sizeof(mystruct) is 16, hence the foo[3], foo[2], foo[1], ch will be laid with the address gap of 16.
I couldn't get the address difference 16 here with the below address:
0xfeeece90 0xfeeece9c 0xfeeecea8 0xfeeece8f 0xfeeece88
The options that are given to you suppose a sizeof(mystruct) of 12 bytes, which is plausible, since you'll have
a at offset 0
3 bytes of padding to keep b aligned to 4 bytes
b at offset 4
c at offset 8 (no padding required, we are already at a multiple of 2)
d at offset 10 (no padding required, char does not need any particular alignment)
1 byte of padding to keep the next element of an array on 4 bytes boundaries (so that the b of all elements remains aligned to 4 bytes boundaries).
So, all the options are plausible in this respect; next comes ch; assuming that the compiler keeps the order of variables (which is definitely not plausible in optimized builds) will sit right over foo. foo starts at 0xfeeece90 and ch does not have alignment requirements, so it'll be 0xfeeece8f. Finally, i will sit at the nearest 4-bytes boundary above ch, which is indeed 0xfeeece88.
Again: this discussion is realistic as far as the struct is concerned, it is not when talking about the locals. In an optimized build the order of declaration does not matter, the compiler will probably reorder them to avoid wastes of space (and, if you do not ask for their address, will try to fit them in registers).

Memory address of variables in c

// intialize a char variable, print its address and the next address
char charvar = '\0';
printf("address of charvar = %p\n", (void *)(&charvar));
printf("address of charvar - 1 = %p\n", (void *)(&charvar - 1));
printf("address of charvar + 1 = %p\n", (void *)(&charvar + 1));
// intialize an int variable, print its address and the next address
int intvar = 1;
printf("address of intvar = %p\n", (void *)(&intvar));
printf("address of intvar - 1 = %p\n", (void *)(&intvar - 1));
printf("address of intvar + 1 = %p\n", (void *)(&intvar + 1));
This is a code i found online and here is the concerned output
address of charvar = 0x7fff9575c05f
address of charvar - 1 = 0x7fff9575c05e
address of charvar + 1 = 0x7fff9575c060
address of intvar = 0x7fff9575c058
address of intvar - 1 = 0x7fff9575c054
address of intvar + 1 = 0x7fff9575c05c
My doubt is why the memory address in a computer is stored in a hexadecimal format? We know the size of one char is 8bits or 1 byte, what does 1 byte mean in memory that is the address of the start bit of charvar is 0x7fff9575c05f shouldn't the address of the char+1 be the 0x7fff9575c05f + 8bits be 0x7fff9575c067, but it seems that one memory location in the computer is organised in terms of 8bits or 1 byte. Am i correct?If so why?
The memory is organized in terms of bytes, and pointers point to a specific byte, not to a single bit. The reason is probably that early computers had 8-bit registers/... and usually whole bytes were processed at once. Since the computer was operating on whole bytes, addressing bytes instead of single bits made more sense. It also saves address space, allowing for more memory to be addressed with the same pointer size.
Also the memory addresses are not really stored in hexadecimal format, they are just formatted that way when printed out. Internally in memory they are binary numbers just like all the other numbers a computer works with.
The smallest part of memory you can easily access is a byte, so there would be no use making an address for every bit.
Memory is addressed in bytes rather than bits, you have to accept this as a matter of fact. Once you get a value of a certain byte in a memory you can work with its bits using logical (bitwise) functions or operators, such as &, |, ^, ~ etc. See http://www.cprogramming.com/tutorial/bitwise_operators.html
Moreover, the address is not stored in hexadecimal format, the hexadecimal format is only the format of the number printed to the output. If you used other formatter %d rather than %p in your printf call you will get decadic format. See http://www.cplusplus.com/reference/cstdio/printf/

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