I tested a small program which is written below.My question is why there is a 12 bytes difference between the pointer to a value and a pointer to the first pointer.But if you look at other pointer addresses there is only a difference of 8 bytes every time.I executed this program multiple times and always I see this difference.Can anyone explain me what could be the reason?Thanks in advance..
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int val;
int *ptr;
int **ptrptr;
int ***ptrptrptr;
int ****ptrptrptrptr;
int *****ptrptrptrptrptr;
val=10;
ptr=&val;
ptrptr=&ptr;
ptrptrptr=&ptrptr;
ptrptrptrptr=&ptrptrptr;
ptrptrptrptrptr=&ptrptrptrptr;
printf("Value-%d\n",val);
printf("Value address - %d\n",ptr);
printf("Pointer address - %d\n",ptrptr);
printf("Pointer Pointer Address -%d\n",ptrptrptr);
printf("Pointer Pointer Pointer Address -%d\n",ptrptrptrptr);
printf("Pointer Pointer Pointer Pointer Address -%d\n",ptrptrptrptrptr);
return 0;
}
The results are:
Value-10
Value address - -1308521884
Pointer address - -1308521896
Pointer Pointer Address --1308521904
Pointer Pointer Pointer Address --1308521912
Pointer Pointer Pointer Pointer Address --1308521920
It's just the stack layout your compiler chose, f.e. it could be for alignment reasons. Things would most likely still work with other layouts.
Side note, you should use %p to print addresses.
Related
I'm slightly confused between these two pieces of code:
version 1: (gives warnings after compiling)
int func(int *ptr2)
{
*ptr2 += 1;
}
int main()
{
int a = 5;
int *ptr = &a;
printf("Address of a: %x\n", a);
printf("Before: %x\n", ptr);
func(&ptr);
printf("After: %x\n", ptr);
return 0;
}
Output:
Address of a: 5770a18c
Before: 5770a18c
After: 5770a18d
version 2:
int func(int **ptr2)
{
*ptr2 += 1;
}
int main()
{
int a = 5;
int *ptr = &a;
printf("address of a: %x\n", &a);
printf("Before: %x\n", ptr);
func(&ptr);
printf("After: %x\n", ptr);
return 0;
}
Output:
Address of a: cc29385c
Before: cc29385c
After: cc293860
If I'm understanding pointers in C correctly when we pass by reference, we are creating a pointer to that location. This allows us to change the value at the address held by the pointer through the dereference operator.
However, if we want to change the value held by a pointer, we use a pointer to a pointer. We pass the address of the pointer and create a new pointer to hold said address. If we want to change the value, we use the dereference operator to access our pointer's (defined elsewhere) value.
Hopefully I'm on the right track, but I'm struggling to visualize what's happening with version 1 specifically. Mainly, I'd just like to understand the difference in make-up and output between these two programs. I assume version 1 is still a pointer to a pointer, but why are the incremented values different between both programs? If version 1 is successfully incrementing ptr's value (which I suspect is not), why is that I cannot find code with the same syntax? I think I'm missing something fairly trivial here... Any help is appreciated
Based on your output, you appear to be compiling for a 32-bit system where addresses and int are of that size.
When you increment the value at *ptr with that type being int, it will simply add 1.
When *ptr resolves to an int* then it will increment by sizeof(int) because the value at the current address in this case is 4 bytes long, so we have to increase the address by the number of bytes that an int consumes so that we're pointing at the next int. Note that doing this is only valid if you actually have allocated memory at the subsequent address.
Generally you pass a T** when the callee needs to modify the address to point to - such as say, the callee performs a malloc() to allocate space for the pointer.
&ptr is a pointer to a pointer, but what is passed to func() is a pointer to int converted from &ptr in implementation-defined manner. Then, *ptr2 += 1; is incrementing int and add 1 to what is pointed by ptr2 (the pointer ptr in main(), which eventually have the same reepresentation as `int in your system).
In version 2, the pointer to a pointer is correctly passed to func(). Therefore, pointer aritimetic is performed and the size of int is added to the address.
Note that you invoked undefined behavior by passing data having wrong type to printf(). The correct way to print pointers is like this:
printf("Before: %p\n", (void*)ptr);
As you see, cast the pointer to void* and use %p specifier.
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
struct node
{
int id;
struct node *next;
};
typedef struct node NODE;
int main()
{
NODE *hi;
printf("\nbefore malloc\n");
printf("\naddress of node is: %p",hi);
printf("\naddress of next is: %p",hi->next);
return 0;
}
The output is:
before malloc
address of node is: 0x7ffd37e99e90
address of next is: 0x7ffd37e9a470
Why both are not same?
TL;DR
Your code provokes Undefined Behavior, as already mentioned in Morlacke's Answer. Other than that, it seems that you're having problems on understanding how pointers work. See references for tutorials.
First, From your comments
When you say that there's memory allocated for ip in this case:
int i = 10;
int *ip;
ip = &i;
What happens is:
You declare an int variable called i and assign the value 10 to it. Here, the computer allocates memory for this variable on the stack. Say, at address 0x1000. So now, address 0x1000 has content 10.
Then you declare a pointer called ip, having type int. The computer allocates memory for the pointer. (This is important, see bellow for explanation). Your pointer is at address, say, 0x2000.
When you assign ip = &i, you're assigning the address of variable i to variable ip. Now the value of variable ip (your pointer) is the address of i. ip doesn't hold the value 10 - i does. Think of this assignment as ip = 0x1000 (don't actually write this code).
To get the value 10 using your pointer you'd have to do *ip - this is called dereferencing the pointer. When you do that, the computer will access the contents of the address held by the pointer, in this case, the computer will access the contents on the address of i, which is 10. Think of it as: get the contents of address 0x1000.
Memory looks like this after that snippet of code:
VALUE : 10 | 0x1000 |
VARIABLE : i | ip |
ADDRESS : 0x1000 | 0x2000 |
Pointers
Pointers are a special type of variable in C. You can think of pointers as typed variables that hold addresses. The space your computer allocates on the stack for pointers depends on your architecture - on 32bit machines, pointers will take 4 bytes; on 64bit machines pointers will take 8 bytes. That's the only memory your computer allocates for your pointers (enough room to store an address).
However, pointers hold memory addresses, so you can make it point to some block of memory... Like memory blocks returned from malloc.
So, with this in mind, lets see your code:
NODE *hi;
printf("\nbefore malloc\n");
printf("\naddress of node is: %p",hi);
printf("\naddress of next is: %p",hi->next);
Declare a pointer to NODE called hi. Lets imagine this variable hi has address 0x1000, and the contents of that address are arbitrary - you didn't initialize it, so it can be anything from zeroes to a ThunderCat.
Then, when you print hi in your printf you're printing the contents of that address 0x1000... But you don't know what's in there... It could be anything.
Then you dereference the hi variable. You tell the computer: access the contents of the ThunderCat and print the value of variable next. Now, I don't know if ThunderCats have variables inside of them, nor if they like to be accessed... so this is Undefined Behavior. And it's bad!
To fix that:
NODE *hi = malloc(sizeof NODE);
printf("&hi: %p\n", &hi);
printf(" hi: %p\n", hi);
Now you have a memory block of the size of your structure to hold some data. However, you still didn't initialize it, so accessing the contents of it is still undefined behavior.
To initialize it, you may do:
hi->id = 10;
hi->next = hi;
And now you may print anything you want. See this:
#include <stdio.h>
#include <stdlib.h>
struct node {
int id;
struct node *next;
};
typedef struct node NODE;
int main(void)
{
NODE *hi = malloc(sizeof(NODE));
if (!hi) return 0;
hi->id = 10;
hi->next = hi;
printf("Address of hi (&hi) : %p\n", &hi);
printf("Contents of hi : %p\n", hi);
printf("Address of next(&next): %p\n", &(hi->next));
printf("Contents of next : %p\n", hi->next);
printf("Address of id : %p\n", &(hi->id));
printf("Contents of id : %d\n", hi->id);
free(hi);
return 0;
}
And the output:
$ ./draft
Address of hi (&hi) : 0x7fffc463cb78
Contents of hi : 0x125b010
Address of next(&next): 0x125b018
Contents of next : 0x125b010
Address of id : 0x125b010
Contents of id : 10
The address of variable hi is one, and the address to which it points to is another. There are several things to notice on this output:
hi is on the stack. The block to which it points is on the heap.
The address of id is the same as the memory block (that's because it's the first element of the structure).
The address of next is 8 bytes from id, when it should be only 4(after all ints are only 4 bytes long) - this is due to memory alignment.
The contents of next is the same block pointed by hi.
The amount of memory "alloced" for the hi pointer itself is 8 bytes, as I'm working on a 64bit. That's all the room it has and needs.
Always free after a malloc. Avoid memory leaks
Never write code like this for other purposes than learning.
Note: When I say "memory alloced for the pointer" I mean the space the computer separates for it on the stack when the declaration happens after the Stack Frame setup.
References
SO: How Undefined is Undefined Behavior
SO: Do I cast the result of malloc
SO: What and where are the stack and heap?
Pointer Basics
Pointer Arithmetic
C - Memory Management
Memory: Stack vs Heap
Memory Management
The Lost Art of C Strucutre Packing will tell you about structures, alignment, packing, etc...
You have no malloc here.
hi pointer points to something undefined.
hi->next the same.
About the question. Why they should be?
I think you do not understand pointers.
because next is a pointer type and it is pointing to 0x7ffd37e9a470.
if you print the address if next &(hi->next), you can see both hi and hi->next has a difference of 2 (because of int id is the first element).
int *ptr;
ptr=(int *)malloc(sizeof(int)*2);
ptr=100; /*What will happen if I put an asterisk(*) indicating *ptr=100? */
ptr++;
printf("ptr=%d",*ptr);
free(ptr);
So, I wanted the pointer to increment. I allocated a size of 4(2*2) for the pointer. But I couldn't understand how the pointer increments only by 2. And if I put an asterisk int the 3rd line,that is *ptr=100; It shows something else.
If you have int * ptr, then ptr++ increments the pointer by the size of a single int. If int is two bytes on your platform, that's why it increments by two.
*ptr = 100 would store the value 100 at the int pointed to by ptr, i.e. the first of the two ints that you allocated with your malloc() call.
ptr = 100 will attempt to assign the memory address 100 to ptr, which is almost certainly not what you want, as you would lose your reference to the memory you just malloc()ed, and what is at memory location 100 is probably not meaningful for you or accessible to you.
As it currently stands, if you were to do *ptr = 100 and then ptr++, your printf() call would result in undefined behavior since you'd have incremented the pointer to point to uninitialized memory (i.e. the second of the two ints you allocated with your malloc() call), whose contents you then attempt to output.
(*ptr)++ on the other hand would increment that 100 value to 101, leave the value of ptr unchanged, your printf() call would be fine, and output 101. The second of the two ints you allocate would still remain uninitialized, but that's no problem if you don't attempt to access it.
Also, don't cast the return from malloc(), ptr=(int *)malloc(sizeof(int)*2) should be ptr=malloc(sizeof(int)*2), or even better, ptr = malloc(sizeof(*ptr) * 2);
Try this:
int *ptr;
ptr = malloc(2 * sizeof *ptr);
printf("ptr = %p.\n", (void *) ptr); // Examine pointer before increment.
ptr++;
printf("ptr = %p.\n", (void *) ptr); // Examine pointer after increment.
You will see that the value of ptr is incremented by the number of bytes in an int. The C language automatically does pointer arithmetic in units of the pointed-to element. So a single increment of an int pointer in C becomes, at the machine level, an increment of the number of bytes of an int.
Notes
%p is the proper specifier to use when printing a pointer, not %d. Also, the pointer must be cast to void * or const void *.
ptr = malloc(2 * sizeof *ptr); is a cleaner way to allocate memory and assign a pointer than your original code, because:
Using sizeof *ptr causes the code to automatically adapt if you ever change the type of ptr. Instead of having to change the type in two places (where ptr is declared and where malloc is called), one change suffices. This reduces opportunities for errors.
malloc does not need to be cast to the destination type. It returns a void *, which C will automatically convert to the destination type of the assignment without complaint. (C++ is different.) It will still work if you cast it, but this can mask another problem: If you accidentally do not declare malloc (as by failing to include <stdlib.h>, and compile in an old version of C, malloc will be implicitly declared to return an int, and the cast will mask the error. Leaving the expression without a cast will cause a warning message to be produced when this happens.
This line changes value of address in pointer to some nonsense (100 will not be any valid address):
ptr=100;
Then you increment the pointer to 100 + sizeof(int) because the pointer has type of int* which automatically increments address by amount of bytes to get to the next integer that ptr points to.
At next line you dereference the invalid pointer so your code should crash, but the command is ok if your pointer had valid address:
printf("ptr=%d",*ptr);
To repair your code just don't change the pointer itself but change the data:
int *ptr;
ptr=(int *)malloc(sizeof(int)*2);
*ptr=123; /*What will happen if I put an asterisk(*) indicating *ptr=100? */
printf("ptr=%d",*ptr);
ptr++;
*ptr=234;
printf("ptr+1=%d",*ptr);
// you can set or get your data also this way:
ptr[0] = 333;
ptr[1] = 444;
printf("ptr[0]=%d",ptr[0]);
printf("ptr[1]=%d",ptr[1]);
free(ptr);
First thing you need to understand is a POINTER points to ADDRESS, when your assign 100 to ptr, it means your pointer ptr now points to memory location whose address is 100.
Secondly pointer arithmetic depends on type of pointer, in your case ptr is a pointer pointing to integer. SO when you increment ptr, it means it will jump to the memory location of next integer. So, ptr gets incremented by 2 (memory occupied by one int on your platform)
To be simple
ptr=100;
By this you are trying to store a int as an address to a pointer, which Is nonsense.
In other words you are trying to make the pointer ptr to point the address 100, which is not an address.
But by
*ptr=100;
You are trying to store value 100 to the address pointed by ptr, which is valid.
Also
ptr++;
Means that now ptr is pointing to ptr+4 or (ptr+2 for 16 bit compiler like tc) address.
Also for your particular code, you are just changing and incrementing the address pointed by ptr, but you are not storing any value at the address pointed by ptr.
So your code will print garbage value or it may also crash as 100 is not a valid address.
Also you should have done
ptr=(int*)100;
It would remove
warning: assignment makes pointer from integer without a cast [enabled by default]
But still it is undefined behaviour.
I am trying to give a value to a pointer.
this code works fine
int i =5;
int *ptr ;
ptr = &i;
printf(" %d\n",*ptr);
but this code shows an error
int i =5;
int *ptr ;
*ptr = 5;
printf(" %d\n",*ptr);
can someone explain this to me?
int *ptr gets initialized to a random location, which possibly points to invalid memory, and you try to write 5 to that location.
When you declare int *ptr, you're creating a variable called ptr which can hold the address of an int. When you dereference it in *ptr = 5, you're saying "store 5 in the address that ptr points to" - but as ptr is uninitialised, where it points to is undefined. So you're invoking undefined behaviour.
An int * does not store an int, but just an address that points to one. There still has to be a real int at that address.
If you want to allocate an int that exists outside of the local scope, you can use malloc. A simple conversion of your example without error checking:
int *ptr = malloc(sizeof(int));
*ptr = 5;
printf(" %d\n",*ptr);
If you do use malloc, just remember to free the allocated memory when you're finished:
free(ptr);
The second version assigns 5 to the memory pointed to by ptr, but you haven't yet initialized ptr to point to a known location.
So it writes the value to the memory at whatever address happens to be in ptr, which is whatever was in memory where ptr was declared.
You can't deterrence a pointer that doesn't point to somewhere you own.
int* ptr;
That allocates space for the pointer, but it doesn't allocate space for the chunk the pointer points to.
Also, since it's not initialized, ptr has an indeterminate value. This means that not only does it likely point to something you don't own, it also would be rather difficult to check if it's a valid pointer. It's usually a good idea to initialize pointers to either NULL (or nullptr if available) or an actual location (like you did in the first example).
Here is a program, I write it to output all the characters of a string one by one. But I also print the address of individual blocks of the array. The problem is addresses for all blocks are same. Why?
Does someone know?
#include<stdio.h>
int main()
{
char enter[]="Kinsman";
char *ptr;
ptr=enter;
int i=0;
while(*ptr!='\0')
{
printf("%c%p\n",*ptr,&ptr);
ptr++;
for(i=0;i<=100000000;i++);
}
return 0;
}
Because you print the address of the actual pointer.
When you use &ptr you get the address of the actual pointer and not the address if points to. Remove the ampersand (address-of operator &) so you have only ptr.
You are printing the address of the pointer, not the value of the pointer
Try
printf("%c%p\n",*ptr, static_cast<void*>(ptr));
(https://stackoverflow.com/a/18929285/259)
ptr is a pointer and it is also a variable in stack that has an address. This is fixed, while what it points to is varying by ptr++, thus you've to print the pointed-to value and not the address of the pointer itself.
printf("%c%p\n",*ptr, (void*)ptr);
// ^ remove & , and add void*