When I run the following code:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int array[100];
int (*array_ptr)[100];
void *buff = malloc(500);
int *ptr;
printf("array: %p \narray+1: %p\n", array, array+1);
printf("array_ptr: %p \narray_ptr+1: %p\n", array_ptr, array_ptr+1);
printf("buff: %p\n", buff);
printf("ptr: %p\n", ptr);
}
the result is like this:
array: 0x7fffe6dc6bd0
array+1: 0x7fffe6dc6bd4
array_ptr: (nil)
array_ptr+1: 0x190
buff: 0x1f80260
ptr: 0x7fffe6dd417c
I run it multiple times, array, array+1, buff and ptr all change values randomly, but array_ptr and array_prt+1 never change, although the pointer arithmetic result 0x190 is as expected.
Does it indicate that the array pointed by array_ptr is stored in heap? But the dynamically allocated memory chunk pointed by buff is also supposed to be in heap and its value changes, why is that? Thanks!
array_ptr is uninitialized pointer, and gets an undefined value(in your case 0).
array_ptr+1 is sizeof(int)*100 = 400 = 0x190 more than array_ptr
ptr is also an uninit pointer, which in your case points to garbage.
You need to initialize pointers after they're defined to get any valid results
To your question, array is on the stack, buff is on the heap, and ptr/array_ptr are uninitialized will give you garbage or segmentation fault if you try to access their data
Does it indicate that the array pointed by array_ptr is stored in heap?
No. array_ptr points to nothing, neither on the stack nor on the heap.
int (*array_ptr)[100];
array_ptr is one pointer to an array of 100 int objects, but with this statement you do not create an array with 100 int objects by which array_ptr is pointing to the first element of this array. It only creates the pointer itself.
With:
printf("array_ptr: %p \narray_ptr+1: %p\n", array_ptr, array_ptr+1);
You are trying to print the addresses of objects the pointer array_ptr and its offset by 1 point to, but this isn´t possible since array_ptr is not initialized to point to such objects. Thus, You´ll get any kind of Undefined Behavior/ unpredictable results.
You need to initialize array_ptr with, f.e. the address of the first int object of array:
int (*array_ptr)[100] = array;
The same goes for the pointer ptr with:
printf("ptr: %p\n", ptr);
ptr needs to have an address of an object it points to in order to show the address of that object.
But the dynamically allocated memory chunk pointed by buff is also supposed to be in heap and its value changes, why is that?
This is a completely different thing. With malloc you do allocate memory on the heap (if it was successful of course) and you do get a pointer to that memory back, which isn´t the case with int (*array_ptr)[100];.
Related
When a pointer is allocated memory using malloc, pointer (say x)will now point to memory address.
Later I free this(x) memory pointer,but pointer is still pointing to it's old memory.
This would now create dangling pointer.
(Because I did not point the old pointer to NULL after free)
Now, assume I use malloc and assume new pointer(y) now points to same memory location as old pointer (x)
Doesn't memsetting new pointer (y) to 0 solve dangling pointer issue.
Assume I have only one struct type.So every malloc which I do is always of same size of same structure.
If it was different struct , I know i may still have some data at the end of struct if new pointer (y) has small memory allocation than pointer (x)
The term dangling pointer means that whatever address in memory it points to is invalid. If you make it valid, like your 2nd malloc, then the address becomes valid. If you store the same address in two different variables (via your assumption) both are valid pointers:
#include <stdio.h>
#include <stdlib.h>
struct s { int i; };
int main() {
struct s *p = malloc(sizeof(struct s));
printf("before: %p\n", (void *) p);
free(p);
// p is dangling
printf("after: %p\n", p);
struct s *p2 = malloc(sizeof(struct s));
// p and p2 are valid
printf("before: %p\n", (void *) p2);
free(p2);
// p and p2 are dangling
printf("after: %p\n", p2);
}
and the output from my pleasingly corroborative malloc:
before: 0x561b73d3b260
after: 0x561b73d3b260
before: 0x561b73d3b260
after: 0x561b73d3b260
Dangling pointers are only a concern if you try to use them after you've freed them.
Yes, it's possible that a new allocation can return the same address that x has. But you can never know whether this is going to happen, so you still can't use x any more. It would just be a coincidence if its address became valid again.
Even if you keep allocating and freeing the same size, there's no expectation that it will keep reusing the same address.
For safety you must assume that a freed pointer will never become valid again.
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).
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.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
char *p[2];
char **pp = calloc(2, 4);
p[0] = "ab";
p[1] = "cd";
// p[2] = "ef";
pp[0] = "ab";
pp[1] = "cd";
pp[2] = "ef";
printf("pp: %s, %s, %s\n", pp[0], pp[1], pp[2]);
printf("size_p: %d\nsize_pp: %d\n", sizeof p, sizeof pp);
}
if 'p[2]' is defined and assigned a value - the resulting behavior is a segfault. if 'pp[2]' is assigned - the output is the following: "ab, cd, ef". 'sizeof' returns 8 (2x4 bytes per pointer) for 'p' and only 4 bytes for 'pp'. why am i being able to assign 'pp[2]', even though it should only be in possession of 8 bytes of allocated memory (that should be able to store only 2 pointer addresses)? also, how does 'sizeof' determine the actual memory size in both of the cases?
p is declared to have two elements, so p[2] does not exist - hence the segfault. Since p is a local array (of pointers), sizeof(p) gives the size of the element type (and the element type is char *, whose size is 4) multiplied by the number of elements (2). pp, on the other hand, is a pointer (to a pointer), not an array, so sizeof(p) is simply the size of a char **, which is the same as the size of any other pointer on a 32-bit machine, namely 4. That the assignment to pp[2] seems to succeed is pure chance - you're writing outside the allocated memory (which only contains space for two char * elements).
By the way, pointers to string literals should be const char *.
With char *p[2]; you allocate 2 char* on the stack. When accessing p[2], you have a buffer overflow and might access any other fings belonging to the stack frame of the current method (some compilers check this in debug mode).
With calloc, you allocate memory in the heap. Accessing pp[2] is (probabely) free memory, you no segfault here. But this memory could also be used by other objects, so this is absolutely not ok!
For size calculation: sizeof(char**) is 4, as is for every 32-bit pointer. sizeof(char*[2]) is 8, because it is 2x4 bytes.
As Aasmund Eldhuset said, p[2] does not exist. p[0] and p[1] are the two elements of the array.
The reason it segfaults for p[2] and not pp[2] is, as I understand it, because p is stored on the stack and pp is stored on the heap. So although you don't own the memory at pp[2], it doesn't seg fault. Instead, it just overwrites god-knows-what and will probably cause your program to misbehave in unpredictable ways.
In general, dynamically allocated memory (such as pp in your example) will not always segfault if you overstep their bounds, whereas statically allocated memory (eg. p) will segfault.