I'm learning C and currently learn about pointers. I understand the principle of storing the address of a byte in memory as a variable, which makes it possible to get the byte from memory and write to the memory address.
However, I don't understand where the address of a pointer is stored. Let's say the value of a pointer (the address of a byte in memory) is stored somewhere in memory - how can the program know where the pointer is stored? Wouldn't that need a pointer for a pointer resulting in endless pointers for pointers for pointers... ?
UPDATE
The actual question is: "How does the compiler assign memory addresses to variables". And I found this question which points out this topic.
Thanks to everybody who's answered.
This is an implementation detail, but...
Not all addresses are stored in memory. The processor also has registers, which can be used to store addresses. There are only a handful of registers which can be used this way, maybe 16 or 32, compared to the billions of bytes you can store in memory.
Variables in registers
Some variables will get stored in registers. If you need to quickly add up some numbers, for example, the compiler might use, e.g., %eax (which is a register on x86) to accumulate the result. If optimizations are enabled, it is quite common for variables to exist only in registers. Of course, only a few variables can be in registers at any given time, so most variables will need to get written to memory at some point.
If a variable is saved to memory because there aren't enough registers, it is called "spilling". Compilers work very hard to avoid register spilling.
int func()
{
int x = 3;
return x;
// x will probably just be stored in %eax, instead of memory
}
Variables on the stack
Commonly, one register points to a special region called the "stack". So a pointer used by a function may be stored on the stack, and the address of that pointer can be calculated by doing pointer arithmetic on the stack pointer. The stack pointer doesn't have an address because it's a register, and registers don't have addresses.
void func()
{
int x = 3; // address could be "stack pointer + 8" or something like that
}
The compiler chooses the layout of the stack, giving each function a "stack frame" large enough to hold all of that function's variables. If optimization is disabled, variables will usually each get their own slot in the stack frame. With optimization enabled, slots will be reused, shared, or optimized out altogether.
Variables at fixed addresses
Another alternative is to store data at a fixed location, e.g., "address 100".
// global variable... could be stored at a fixed location, such as address 100
int x = 3;
int get_x()
{
return x; // returns the contents of address 100
}
This is actually not uncommon. Remember, that "address 100" doesn't correspond to RAM, necessarily—it is actually a virtual address referring to part of your program's virtual address space. Virtual memory allows multiple programs to all use "address 100", and that address will correspond to a different chunk of physical memory in each running program.
Absolute addresses can also be used on systems without virtual memory, or for programs which don't use virtual memory: bootloaders, operating system kernels, and software for embedded systems may use fixed addresses without virtual memory.
An absolute address is specified by the compiler by putting a "hole" in the machine code, called a relocation.
int get_x()
{
return x; // returns the contents of address ???
// Relocation: please put the address of "x" here
}
The linker then chooses the address for x, and places the address in the machine code for get_x().
Variables relative to the program counter
Yet another alternative is to store data at a location relative to the code that's being executed.
// global variable... could be stored at address 100
int x = 3;
int get_x()
{
// this instruction might appear at address 75
return x; // returns the contents of this address + 25
}
Shared libraries almost always use this technique, which allows the shared library to be loaded at whatever address is available in a program's address space. Unlike programs, shared libraries can't pick their address, because another shared library might pick the same address. Programs can also use this technique, and this is called a "position-independent executable". Programs will be position-independent on systems which lack virtual memory, or to provide additional security on systems with virtual memory, since it makes it harder to write shell code.
Just like with absolute addresses, the compiler will put a "hole" in the machine code and ask the linker to fill it in.
int get_x()
{
return x; // return the contents of here + ???
// Relocation: put the relative address of x here
}
A variable that is a pointer is still a variable, and acts like any other variable. The compiler knows where the variable is located and how to access its value. It is just that the value happens to be a memory address, that's all.
The pointer is just a variable. The only difference between this and, e.g. a long variable is that we know that what is stored in a pointer variable is a memory address instead of an integer.
Therefore, you can find the address of a pointer variable by the same way as you can find the address of any other variable. If you store this address in some other variable, this one will also have an address, of course.
You confusion seems to originate from the fact that the pointer (i.e. a variable address) can in its turn be stored. But it does not have to be stored anywhere (you only do it when you for some reason need this address). From the point of view of your program, any variable is more or less a named memory location. So the "pointer to the variable" is a named memory location that contains the value that is supposed to "point" to another memory location, hence the name "pointer".
Let's say the value of a pointer (the address of a byte in memory) is stored somewhere in memory
The address of a byte that you allocated, say like this
char ch = 'a';
is referenced by the compiler in the symbol table with the right offset. At run time, the instructions generated by the compiler will use this offset for moving it to from the primary memory to a register for some operation on it.
A pointer, in the sense you're asking, is not stored anywhere, it's just a type when you refer to a variable's address, unless you explicitly create a pointer variable to store it like this
&ch; // address of ch not stored anywhere
char *p = &ch; // now the address of ch is stored in p
Thus there's no recursion concept here.
From the compilers perspective, whether u declare a pointer or a general variable is just a memory space.When you declare a variable a certain block of memory is allocated to the variable.
The variable can be any either a general variable or a pointer.
So ultimately we have a variables (even pointers are variables only) and they have a memory location.
Related
I'm currently learning the Linux process address space and I'm not sure where these C variables correspond in the process address space.
I know that when a function is called, a new frame is created, it'll contain local variables and other function calls etc..
What I am not sure about is the pointers that are in the frame:
I have this function:
int main(){
char *pointer1 = NULL;
char *pointer2 = (void *)0xDDDDDDDD;
pointer1 = malloc(80);
strcpy(pointer1, "Testing..");
return(0);
}
When main is called, a new frame is created.
Variables are initialized.
What I am not sure about these are the pointers, where does:
*pointer1 correspond to in the process address space - data or text section?
*pointer2 correspond to in the process address space - data or text section?
Does NULL and 0xDDDDDDDD belong to data or text section?
since pointer1 = malloc(80), does it belong to the stack section?
First of all it should be noted that the C specification doesn't actually require local variables to be stored on a stack, it doesn't specify location of automatic variables at all.
With that said, the storage for the variables pointer1 and pointer2 themselves will most likely be put on a stack by the compiler. Memory for them will be part of the stack-frame created by the compiler when the main function is called.
To continue, on modern PC-like systems a pointer is really nothing more than a simple unsigned integer, and its value is the address where it points. The values you use for the initialization (NULL and 0xDDDDDDDD) are simply plain integer values. The initialization is done just the same as for a plain int variable. And as such, the values used for initialization doesn't really exists as "data", instead they could be encoded directly in the machine code, and as such will be stored in the "text" (code) segment.
Lastly for the dynamic allocation, it doesn't change where pointer1 is stored. What is does it simply assigning a new value to pointer1. The memory being allocated is on the "heap" which is separate from any program section (i.e. it's neither in the code, data or stack segments).
As some programmer dude just said, the C spec does not state a region where automatic variables must be placed. But it is usual for compilers to grow the stack to accommodate them there. However, they might end on the .data region, and they will if they were, e.g., defined as static char *pointer1 instead.
The initialization values may or may not exist in a program region either. In your case, since the type of values is int, most architectures will inline the initialization as appropriate machine instructions instead, if instructions with appropriate inline operators are available. In x86_64, for example, a single mov/movq operation will be issued to put the 0 (NULL) or the other int in the appropriate memory location on the stack.
However, variables initialized with global scope, such as static char string[40] = "Hello world" or other initialized global variables end up on the .data region and take up space in there. Compilers may place declared, but undefined, global scoped variables on the .bss region instead.
The question since pointer1 = malloc(80), does it belong to the stack section? is ill-defined, because it comprises two things.
The value pointer1 is a value that will be saved at &pointer1. An address which, given the above consideration, the compiler may have put on the stack.
The result of malloc(80) is a value that refers to a region on the heap, a different region, dynamically allocated outside the mapped program space.
On Linux, the result of calling malloc may even create a new NULL-backed memory region (that is, a transient region that is not permanently stored on a file; although it could be swapped by the kernel).
In essence, you could think of how malloc(80) behaves, as something like (not taking free() into consideration, so this is an oversimplification):
int space_left = 0; void *last_mapping = NULL;
void *malloc(int req) {
void *result;
if (space_left < req) {
last_mapping = mmap(NULL, MALLOC_CHUNK_LENGTH, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
space_left = MALLOC_CHUNK_LENGTH;
}
space_left -= req;
result = last_mapping;
last_mapping += req;
return result;
}
The huge difference between calling malloc and mmap with MAP_PRIVATE is that mmap is a Linux System Call, which must make a kernel context switch, allocate a new memory map and reset the MMU layer for every memory chunk allocated, while malloc can be more intelligent and use a single big region as "heap" and manage the different malloc's and free's in userspace after the heap initialization (until the heap runs out of space, where it might have to manage multiple heaps).
Last section of your doubts i.e. "since pointer1 = malloc(80), does it belong to the stack section? " , I can tell you
In C, dynamic memory is allocated from the heap using some standard library functions. The two key dynamic memory functions are malloc() and free().
The malloc() function takes a single parameter, which is the size of the requested memory area in bytes. It returns a pointer to the allocated memory. If the allocation fails, it returns NULL. The prototype for the standard library function is like this:
void *malloc(size_t size);
The free() function takes the pointer returned by malloc() and de-allocates the memory. No indication of success or failure is returned. The function prototype is like this:
void free(void *pointer);
You can refer the doc
https://www.design-reuse.com/articles/25090/dynamic-memory-allocation-fragmentation-c.html
I'm learning about pointers and have been told this: "The purpose of pointers is to allow you to manually, directly access a block of memory."
Say I have int var = 5;. Can't I use the variable 'var' to access the block of memory where the value 5 is stored, since I can change the value of the variable whenever I want var = 6;? Do I really need a pointer when I can access any variable's value just by using its variable, instead of using a pointer that points to the address where the value is stored?
"The purpose of pointers is to allow you to manually, directly access a block of memory."
This is not always true. Consider
*(int*)(0x1234) = some_value;
this is "direct" memory access. Though
int a = some_value, *ptr = &a;
*ptr = some_other_value;
you are now accessing a indirectly.
Can't I use the variable 'var' to access the block of memory where the
value 5 is stored, since I can change the value of the variable
whenever I want var = 6; ?
Surely; but the semantics is different.
Do I really need a pointer when I can access any variable's value just by using its variable, instead of using a pointer that points to the address where the value is stored?
No, you don't. Consider the first example: within the scope where a has been declared, modifying its value through ptr is rather pointless! However, what if you are not within the scope of a? That is
void foo(int x)
{
x = 5;
}
int main(void)
{
int x = 10;
foo(x);
}
In foo, when you do x = 5, there is an ambiguity: do you want to modify foo::x or main::x? In the latter case that has to be "requested" explicitly and the fact that happens through pointers -or, better, through indirection- is a coincidence and a language choice. Other languages have others.
Pointer types have some traits that make them really useful:
It's guaranteed that a pointer will be so large that it can hold any address that is supported by the architecture (on x86, that is 32 bits a.k.a. 4 bytes, and an x64 64 bits a.k.a. 8 bytes).
Dereferencing and indexing the memory is done per object, not per byte.
int buffer[10];
char*x = buffer;
int*y = (int*)buffer;
That way, x[1] isn't y[1]
Both is not guaranteed if you use simple ints to hold your values. The first trait is at least guaranteed by uintptr_t (not by size_t though, although most of the time they have the same size - except that size_t can be 2 bytes in size on systems with segmented memory layout, while uintptr_t is still 4 bytes in size).
While using ints might work at first, you always:
have to turn the value into a pointer
have to dereference the pointer
and have to make sure that you don't go beyond certain values for your "pointer". For a 16 bit int, you cannot go beyond 0xFFFF, for 32 bit it's 0xFFFF FFFF - once you do, your pointer might overflow without you noticing it until it's too late.
That is also the reason why linked lists and pointers to incomplete types work - the compiler already knows the size of the pointers you are going to you, and just allocates memory for them. All pointers have the same size (4 or 8 bytes on 32-bit/64-bit architectures) - the type that you assign them just tells the compiler how to dereference the value. char*s take up the same space as void*s, but you cannot dereference void*s. The compiler won't let you.
Also, if you are just dealing with simple integers, there's a good chance that you will slow down your program significantly do to something called "aliasing", which basically forces the compiler to read the value of a given address all the time. Memory accesses are slow though, so you want to optimized these memory accesses out.
You can compare a memory address to a street address:
If you order something, you tell the shop your address, so that they can send you what you bought.
If you don't want to use your address, you have to send them your house, such that they can place the parcel inside.
Later they return your house to you. This is a bit more cumbersome than using the address!
If you're not at home, the parcel can be delivered to your neighbor if they have your address, but this is not possible if
you sent them your house instead.
The same is true for pointers: They are small and can be transported easily, while the object they point to
might be large, and less easily transportable.
With pointer arithmetics, pointers can also be used to access other objects than the one they originally pointed to.
You call a function from main() or from another function, the function you called can only return 1 value.
Let say you want 3 values changed, you pass them to the called function as pointers. That way you don't have to use global values.
One possible advantage is that it can make it easier to have one function modify a variable that will be used by many other functions. Without pointers, your best option is for the modifying function to return a value to the caller and then to pass this value to the other functions. That can lead to a lot of passing around. Instead, you can give the modifying function a pointer where it stores its output, and all the other functions directly access that memory address. Kind of like global variables.
This may be a pretty basic question. I understand that there is a C convention to set the value of null pointers to zero. Is it possible that you can ever allocate space for a new variable in Windows, and the address of that allocated space happens to be zero? If not, what usually occupies that address region?
On MS-DOS the null pointer is a fairly valid pointer and due to the OS running in real mode it was actually possible to overwrite the 0x0 address with garbage and corrupt the kernel. You could do something like:
int i;
unsigned char* ptr = (unsigned char *)0x0;
for(i = 0; i < 1024; i++)
ptr[i] = 0x0;
Modern operating systems (e.g. Linux, Windows) run in protected mode which never gives you direct access to physical memory.
The processor will map the physical addresses to virtual addresses that your program will make use of.
It also keeps track of what you access and dare you touch something not belonging to you will you be in trouble (your program will segfault). This most definitely includes trying to dereference the 0x0 address.
When you "set the value of a pointer to zero" as in
int *p = 0;
it will not necessarily end up pointing to physical address zero, as you seem to believe. When a pointer is assigned a constant zero value (or initialized with it), the compiler is required to recognize that situation and treat it in a special way. The compiler is required to replace that zero with implementation-dependent null-pointer value. The latter does not necessarily point to zero address.
Null pointer value is supposed to be represented by a physical address that won't be used for any other purpose. If in some implementation physical address zero is a usable address, then such implementation will have to use a different physical address to represent null pointers. For example, some implementation might use address 0xFFFFFFFF for that purpose. In such implementation the initialization
int *p = 0;
will actually initialize p with physical 0xFFFFFFFF, not with physical zero.
P.S. You might want to take a look at the FAQ: http://c-faq.com/null/index.html, which is mostly dedicated to exactly that issue.
The value 0 has no special meaning. It is a convention to set a pointer to 0 and the C compiler has to interpret it accordingly. However, there is no connection to the physical address 0 and in fact, that address can be a valid address. In many systems though the lower adresses are containing hardware related adresses, like interrupt vectors or other. On the Amiga for example, the address 4 was the entry point into the operating system, which is also an arbitrary decision.
If the address of allocated space is zero, there is insufficient memory available. That means your variable could not be allocated.
The address at 0x0 is where the CPU starts executing when you power it on. Usually at this address there's a jump to the BIOS code and IIRC the first 64K (or more) are reserved for other tasks (determined by the BIOS/UEFI). It's an area which is not accessbile by an application.
Given that it should be clear that you cannot have a variable at address 0x0 in Windows.
I'm just starting C. I have read about pointers in various books/tutorials and I understand the basics. But one thing I haven't seen explained is what are the numbers.
For example:
int main(){
int anumber = 10;
int *apointer;
apointer = &anumber;
printf("%i", &apointer);
}
may return a number like 4231168. What does this number represent? Is it some storage designation in the RAM?
Lots of PC programmer replies as always. Here is a reply from a generic programming point-of-view.
You will be quite interested in the actual numerical value of the address when doing any form of hardware-related programming. For example, you can access hardware registers in a computer in the following way:
#define MY_REGISTER (*(volatile unsigned char*)0x1234)
This code assumes you know that there is a specific hardware register located at address 0x1234. All addresses in a computer are by tradition/for convenience expressed in hexadecimal format.
In this example, the address is 16 bits long, meaning that the address bus on the computer used is 16-bits wide. Every memory cell in your computer has an address. So on a 16-bit address bus you could have a maximum of 2^16 = 65536 addressable memory cells.
On a PC for example, the address would typically be 32 bits long, giving you 4.29 billion addressable memory cells, ie 4.29 Gigabyte.
To explain that macro in detail:
0x1234 is the address of the register / memory location.
We need to access this memory location through a pointer, so therefore we typecast the integer constant 0x1234 into an unsigned char pointer = a pointer to a byte.
This assumes that the register we are interested in is 1 byte large. Had it been two bytes large, we would perhaps have used unsigned short instead.
Hardware registers may update themselves at any time (their contents are "volatile"), so the program can't be allowed to make any assumptions/optimizations of what's stored inside them. The program has to read the value from the register at every single time the register is used in the code. To enforce this behavior, we use the volatile keyword.
Finally, we want to access the register just as if it was a plain variable. Therefore the * is added, to take the contents of the pointer.
Now the specific memory location can be accessed by the program:
MY_REGISTER = 1;
unsigned char var = MY_REGISTER;
For example, code like this is used everywhere in embedded applications.
(But as already mentioned in other replies, you can't do things like this in modern PCs, since they are using something called virtual addressing, giving you a slap on the fingers should you attempt it.)
It's the address or location of the memory to which the pointer refers. However, it's best if you regard this as an opaque quantity - you are never interested in the actual value of the pointer, only that to which it refers.
How the address then relates to physical memory is a service that the system provides and actually varies across systems.
That's a virtual address of anumber variable. Every program has its own memory space and that memory space is mapped to the physical memory. The mapping id done by the processor and the service data used for that is maintained by the operating system. So your program never knows where it is in the physical memory.
It's the address of the memory1 location where your variable is stored. You shouldn't care about the exact value, you should just know that different variables have different addresses, that "contiguous memory" (e.g. arrays) has contiguous addresses, ...
By the way, to print the address stored in a pointer you should use the %p specifier in printf.
Notice that I did not say "RAM", because in most modern OSes the "memory" your process sees is virtual memory, i.e. an abstraction of the actual RAM managed by the OS.
A lot of people told you, that the numeric value of a pointer will designate its address. This is one way how implementations can do it, but it is very important, what the C standard has to say about pointers:
The nil pointer has always numeric value 0 when operated on in the C programming language. However the actual memory containing the pointer may have any value, as long as this special, architecture dependent value is consistently treated nil, and the implementation takes care that this value is seen as 0 by C source code. This is important to know, since 0 pointers may appear as a different value on certain architectures when inspected with a low level memory debugger.
There's no requirement whatsoever that the values of the pointer are in any way related to actual addresses. They may be as well abstract identifiers, resolved by a LUT or similar.
If a pointer addresses an array, the rules of pointer arithmetic must hold, i.e. int array[128]; int a, b; a = (int)&array[120]; b = (int)&array[100]; a - b == 20 ; array + (a-b) == &array[20]; &array[120] == (int*)a
Pointer arithmetic between pointers to different objects is undefined and causes undefined behaviour.
The mapping pointer to integer must be reversible, i.e. if a number corresponds to a valid pointer, the conversion to this pointer must be valid. However (pointer) arithmetic on the numerical representation of pointers to different objects is undefined.
Yes, exactly that - it's the address of the apointer data in memory. Local variable such as anumber and apointer will be allocated in your program's stack, so it will refer to an address in the main() function's frame in the stack.
If you had allocated the memory with malloc() instead it would refer to a position in your program's heap space. If it was a fixed string it may refer to a location in your program's data or rodata (read-only data) segments instead.
in this case &apointer represent the address in RAM memory of the pointer variable apointer
apointer is the "address" of the variable anumber. In theory, it could be the actual physical place in RAM where the value of anumber is stored, but in reality (on most OS'es) it's likely to be a place in virtual memory. The result is the same though.
It's a memory address, most likely to the current location in your program's stack. Contrary to David's comment, there are times when you'll calculate pointer offsets, but this is only if you have some kind of array that you are processing.
It's the address of the pointer.
"anumber" takes up some space in RAM, the data at this spot contains the number 10.
"apointer" also takes up some space in RAM, the data at this spot contains the location of "anumber" in RAM.
So, say you have 32 bytes of ram, addresses 0..31
At e.g. position 16 you have 4 bytes, the "anumber" value 10
At e.g. position 20 you have 4 bytes, the "apointer" value 16, "anumber"'s position in RAM.
What you print is 20, apointer's position in RAM.
Note that this isn't really directly in RAM, it's in virtual address space which is mapped to RAM. For the purpose of understanding pointers you can completely ignore virtual address space.
it is not the address of the variable anumber that is printed but it is the address of the pointer which gets printed.look carefully.had it been just "apointer",then we would have seen the address of the anumber variable.
I wanted to know in which section of the program are function pointers stored? As in, is it on the program stack or is there a separate section for the same?
void f(void){}
int main(void){
int x[10];
void (*fp)(void) = NULL;
fp = f;
return 0;
}
Now, will the address of x and fp be in the same segment of the program's stack memory?
A function pointer is no different from any other pointer in terms of storage, which is again no different from any other variable. So yes, they'll all be stored together in the same place, which is the stack for local variables.
With a good compiler, they won't exist anywhere because their values are never used and contribute nothing to the output of the program.
The answer to this precise question is that your two examples (an array of ints and a pointer-to-a-function) are both local variables and both are kept on "the stack" (the stack is a bit conceptual but at the level of your question, it's the right way to think about it), so the addresses of x and fp are both there.
What you might possibly be getting at however (with "which section of the program are function pointers stored") maybe something a bit different: if you assign a value to the pointer-to-function--as in you assign it the address of an actual function-- the address of the function is contains will almost certainly be somewhere else, because executable code is located in a different part of system memory than the execution stack.
(The array of ints is allocated entirely on the stack and if you treat x as a pointer, it will point into the stack area.)