Related
For the code below
int main()
{
int x = 2;
int *ip = &x;
printf("%d",*ip); // Printing the value of *ip gives 2
//Now if the value of ip is incremented
ip++;
printf("%d",*ip); //Printing the value of *ip gives the incremented memory
}
Can someone please explain as how the value of *ip is getting printed as the incremented memory location. *ip being the deferencing operator should return the value at the address right?
I see two things wrong with the code. One is the line:
int *ip = x;
This attempts to assign the value of an int to a pointer. This can be forced with compiler flags, but should give an error. Nevertheless, I suspect this may be a typo in your question, since dereferencing an address of 2 should almost certainly crash, but you've claimed it ran and produced an output of 2. I'm going to assume you actually have:
int *ip = &x;
The second problem is:
ip++;
Here you are incrementing the pointer, rather than the int it points to. I think what you intended (to increment 2 to 3) would be:
(*ip)++;
That is, increment the value the pointer points to.
If you increment the pointer, it will now point to somewhere else on your stack, which could be another local variable (like the pointer itself), or the return address, or the stack frame pointer, or some other hidden value. There is a good chance the new value will be some sort of pointer which a value similar to the address of your pointer, or will otherwise look like the output of printing a pointer. Naturally, you should not be incrementing a pointer that points to a single element. It's never a good idea.
This code may behave unpredictably, because
int *ip = x;
assigns the value of x, to a pointer.
Basically it hard codes 2 into the pointer ip.
It may compile with warnings.
It may later lead to memory errors at run time.
Pointers are a really tricky thing in C. For a lot of people is hard to understand it, so for a good understanding I wrote following code:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int *p; // pointer -> will be dynamic allocated
int *a; // array -> will be dynamic allocated
// print before allocate memory (1)
printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
printf("&a: %p\ta: %p\t*a: %d\n", &a, a, *a);
printf("\n");
// allocate memory (2)
p = (int *)malloc(sizeof(int));
a = (int *)malloc(sizeof(int) * 10);
// print after allocate, but before give a value to poinetrs (3)
printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
printf("&a: %p\ta: %p\t*a: %d\n", &a, a, *a);
printf("\n");
// give a value to poinetrs (4)
*p = 1;
for (int i = 0; i < 10; i++) { a[i] = i; }
// print after we gave a value to pointers (5)
printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
printf("&a: %p\ta: %p\t*a: ", &a, a);
// because a is an array we must use a loop for print
for (int i = 0; i < 10; i++) { printf("%d ", a[i]); }
printf("\n");
printf("\n");
// free pointers (6)
free(p);
free(a);
// print pointers after free (7)
printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
printf("&a: %p\ta: %p\t*a: ", &a, a);
// because a is an array we must use a loop for print
for (int i = 0; i < 10; i++) { printf("%d ", a[i]); }
printf("\n");
printf("\n");
// try to change values after free (8)
*p = 12;
for (int i = 0; i < 10; i++) { a[i] = 3; }
// print after (8)
printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
printf("&a: %p\ta: %p\t*a: ", &a, a);
// because a is an array we must use a loop for print
for (int i = 0; i < 10; i++) { printf("%d ", a[i]); }
printf("\n");
printf("\n");
return 0;
}
Output:
&p: 0xbfe5db64 p: 0xbfe5dc24 *p: -1075452506
&a: 0xbfe5db68 a: 0xbfe5dc2c *a: -1075452502
&p: 0xbfe5db64 p: 0x8716008 *p: 0
&a: 0xbfe5db68 a: 0x8716018 *a: 0
&p: 0xbfe5db64 p: 0x8716008 *p: 1
&a: 0xbfe5db68 a: 0x8716018 *a: 0 1 2 3 4 5 6 7 8 9
&p: 0xbfe5db64 p: 0x8716008 *p: 0
&a: 0xbfe5db68 a: 0x8716018 *a: 0 1 2 3 4 5 6 7 8 9
&p: 0xbfe5db64 p: 0x8716008 *p: 12
&a: 0xbfe5db68 a: 0x8716018 *a: 3 3 3 3 3 3 3 3 3 3
Now, questions and observations:
When I print pointers before give memory for it, why pointer have a random value and a random address to point to it and why it isn't NULL?
After we use malloc, we can see the address where pointer points to changed and its value is NULL, so what malloc really does?
After we give a value to it and print it, we free it and print it again, but values and address are same as behind for array, but not for the integer, why? So what free really does?
After we freed space, we can continue to change values of array and integer, why is this possible after free space? We don't need to reuse malloc?
Because the language specification says so. The value of the pointer (i.e. the address it points to) is indeterminate. It can point anywhere, just like an int could hold any value. Reading those values, (as you do with *p and *a in the first printfs) is actually undefined behaviour.
If you mean the data it points to is 0, that is by chance. The memory allocated does not have to be zeroed out. For example, it could be part of a block previously allocated with malloc and then freed (free doesn't zero out the memory, see point 3. below.)
That is also by chance. When you free the memory, it is not zeroed out, and it does not have to be used immediately. It can keep storing old values until it is used for something else (for instance, by another allocation)
That is also undefined behaviour. You are writing to memory you no longer own. Anything can happen. The program could have crashed. By chance, it seems like you can successfully write to the array, probable because the memory is still not used by anything else that would cause a more apparent run time error.
1.When I print pointers before give memory for it, why pointer have a random value and a random address to point to it and why it isn't NULL?
You didn't make the pointer NULL. you are just declaring it. After declaring the pointer, it may have any value.
To make NULL-
int *p = NULL;
int *a = NULL;
2.After we use malloc, we can see the address where pointer points to changed and its value is NULL, so what malloc really does?
Man Page says-
void *malloc(size_t size);
The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
If your allocated memory have 0 means that is by a chance only! The memory allocated by malloc doesn't freed out. But calloc does!
3.After we give a value to it and print it, we free it and print it again, but values and address are same as behind for array, but not for the integer, why? So what free really does?
free does not mean that it will actually delete the memory! It will inform to the OS that I don't want this memory any more, use it for some other process!
You can certainly continue to use memory a after calling free(...) and nothing will stop you. However the results will be completely undefined and unpredictable. It works by luck only. This is a common programming error called "use after free" which works in many programs for literally years without "problems" -- until it causes a problem.
4.After we freed space, we can continue to change values of array and integer, why is this possible after free space? We don't need to reuse malloc?
This is totally Undefined behavior! After freeing the memory also the pointer still points to the same memory location. It is called Dangling Pointer.
To avoid dangling pointer, Make pointer to null after free!
But after freeing the memory, you need to use memory means use malloc to allocate memory and use it!
What are pointers
Pointer declarations look much like other declarations: but don't be misled. When pointers are declared, the keyword at the beginning declares the type of variable that the pointer will point to. The pointer itself is not of that type, it is of type pointer to that type. A given pointer only points to one particular type, not to all possible types. In practice, all pointers are treated as integers, but the compiler will most likely complain about an assignment between incompatible types.
int *p;
The pointer p hasn't been assigned an address, so it still contains whatever random value was in the memory it occupies (whatever value was there before it was used for p). So, provided that a pointer holds the address of something, the notation *p is equivalent to giving the name of the something directly. What benefit do we get from all this? Well, straight away it gets round the call-by-value restriction of functions. Imagine a function that has to return, say, two integers representing a month and a day within that month.
Summary
Arrays always index from zero—end of story.
There are no multidimensional arrays; you use arrays of arrays instead.
Pointers point to things; pointers to different types are themselves different types.
They have nothing in common with each other or any other types in C; there are no automatic conversions between pointers and other types.
Pointers can be used to simulate ‘call by reference’ to functions, but it takes a little work to do it.
Incrementing or adding something to a pointer can be used to step along arrays.
To facilitate array access by incrementing pointers, the Standard guarantees that in an n element array, although element n does not exist, use of its address is not an error.
Pointer arithmetic
Not only can you add an integral value to a pointer, but you can also compare or subtract two pointers of the same type. They must both point into the same array, or the result is undefined. The difference between two pointers is defined to be the number of array elements separating them; the type of this difference is implementation defined and will be one of short, int, or long. This next example shows how the difference can be calculated and used, but before you read it, you need to know an important point.
In an expression the name of an array is converted to a pointer to the first element of the array. The only places where that is not true are when an array name is used in conjunction with sizeof, when a string is used to initialize an array or when the array name is the subject of the address-of operator (unary &). We haven't seen any of those cases yet, they will be discussed later. Here's the example.
#include <stdio.h>
#include <stdlib.h>
#define ARSZ 10
main(){
float fa[ARSZ], *fp1, *fp2;
fp1 = fp2 = fa; /* address of first element */
while(fp2 != &fa[ARSZ]){
printf("Difference: %d\n", (int)(fp2-fp1));
fp2++;
}
exit(EXIT_SUCCESS);
}
freed Pointers
Calling free() on a pointer doesn't change it, only marks memory as free. Your pointer will still point to the same location which will contain the same value, but that vluae can now get overwritten at any time, so you should never use a pointer after it is freed. To ensure that it is a good idea to always set the pointer to NULL after free'ing it.
Regarding 1), reading an uninitialised value is undefined behaviour. Undefined behaviour means that the C standard does not specify what the compiler should do with your program when you attempt to read an uninitialised value, and therefore the compiler writer is free to pretend that uninitialised values will never be read from - and aren't required to account for that happening in a program.
Within the context of your code, you are presumably using GCC or Clang to compile your program. Your two pointer variables are local variables, and local variables are stored on the stack in GCC and Clang C code. The stack may contain 'random' bytes in it; a pointer on 64-bit computers is generally a 64-bit (8-byte) number that corresponds to an address of memory.
For each of the two pointer variables, these randomly initialised 8 bytes are interpreted as a memory address. You can attempt to read from this random memory address, and if you do this (and your program is allowed to access that particular memory address), you will read some garbage values that will be interpreted as the datatype that your pointer points to. For example, in your case, a regular int.
Regarding 4), not to add to what the accepted answer has already said - I'm curious whether, if you malloc a number of objects and you free one of them and you make no further memory allocations, you are not creating new malloc metadata since you have no new allocations. It would be reasonable that the free'd block does not have its contents mutated, right?
To my knowledge, free does not actually return memory to the operating system. Therefore, one would expect that the answer to the above be yes - the block is not mutated.
I came across this program on HSW:
int *p;
int i;
p = (int *)malloc(sizeof(int[10]));
for (i=0; i<10; i++)
*(p+i) = 0;
free(p);
I don't understand the loop fully.
Assuming the memory is byte addressable, and each integer takes up 4 bytes of memory, and say we allocate 40 bytes of memory to the pointer p from address 0 to 39.
Now, from what I understand, the pointer p initially contains value 0, i.e. the address of first memory location. In the loop, a displacement is added to the pointer to access the subsequent integers.
I cannot understand how the memory addresses uptil 39 are accessed with a displacement value of only 0 to 9. I checked and found that the pointer is incremented in multiples of 4. How does this happen? I'm guessing it's because of the integer type pointer, and each pointer is supposedly incremented by the size of it's datatype. Is this true?
But what if I actually want to point to memory location 2 using an integer pointer. So, I do this: p = 2. Then, when I try to de-reference this pointer, should I expect a segmentation fault?
Now, from what I understand, the pointer p initially contains value 0
No, the pointer p would not hold the value 0 in case malloc returns successfully.
At the point of declaring it, the pointer is uninitialized and most probably holds a garbage value. Once you assign it to the pointer returned by malloc, the pointer points to a region of dynamically allocated memory that the allocator sees as unoccupied.
I cannot understand how the memory addresses uptil 39 are accessed
with a displacement value of only 0 to 9
The actual displacement values are 0, 4, 8, 12 ... 36. Because the pointer p has a type, in that case int *, this indicates that the applied offset in pointer arithmetics is sizeof(int), in your case 4. In other words, the displacement multiplier is always based on the size of the type that your pointer points to.
But what if I actually want to point to memory location 2 using an
integer pointer. So, I do this: p = 2. Then, when I try to
de-reference this pointer, should I expect a segmentation fault?
The exact location 2 will most probably be unavailable in the address space of your process because that part would either be reserved by the operating system, or will be protected in another form. So in that sense, yes, you will get a segmentation fault.
The general problem, however, with accessing a data type at locations not evenly divisible by its size is breaking the alignment requirements. Many architectures would insist that ints are accessed on a 4-byte boundary, and in that case your code will trigger an unaligned memory access which is technically undefined behaviour.
Now, from what I understand, the pointer p initially contains value 0
No, it contains the address to the first integer in an array of 10. (Assuming that malloc was successful.)
In the loop, a displacement is added to the pointer to access the subsequent integers.
Umm no. I'm not sure what you mean but that is not what the code does.
I checked and found that the pointer is incremented in multiples of 4. How does this happen?
Pointer arithmetic, that is using + - ++ -- etc operators on a pointer, are smart enough to know the type. If you have an int pointer a write p++, then the address that is stored in p will get increased by sizeof(int) bytes.
But what if I actually want to point to memory location 2 using an integer pointer. So, I do this: p = 2.
No, don't do that, it doesn't make any sense. It sets the pointer to point at address 0x00000002 in memory.
Explanation of the code:
int *p; is a pointer to integer. By writing *p = something you change the contents of what p points to. By writing p = something you change the address of where p points.
p = (int *)malloc(sizeof(int[10])); was written by a confused programmer. It doesn't make any sense to cast the result of malloc in, you can find extensive information about that topic on this site.
Writing sizeof(int[10]) is the same as writing 10*sizeof(int).
*(p+i) = 0; is the very same as writing p[i] = 0;
I would fix the code as follows:
int *p = malloc(sizeof(int[10]));
if(p == NULL) { /* error handling */ }
for (int i=0; i<10; i++)
{
p[i] = 0;
}
free(p);
Since you have a typed pointer, when you perform common operations on it (addition or subtraction), it automatically adjusts the alignment for your type. Here, since on your computer sizeof (int) is 4, p + i will result in the address p + sizeof (int) * i, or p + 4*i in your case.
And you seem to misunderstand the statement *(p+i) = 0. This statement is equivalent to p[i] = 0. Obviously, your malloc() call won't return you 0, except if it fails to actually allocate the memory you asked.
Then, I assume that your last question means "If I shift my malloc-ated address by exactly two bytes, what will occur?".
The answer depends on what you do next and on the endianness of your system. For example:
/*
* Suppose our pointer p is well declared
* And points towards a zeroed 40 bytes area.
* (here, I assume sizeof (int) = 4)
*/
int *p1 = (int *)((char *)p + 2);
*p1 = 0x01020304;
printf("p[0] = %x, p[1] = %x.\n", p[0], p[1]);
Will output
p[0] = 102, p[1] = 3040000.
On a big endian system, and
p[0] = 3040000, p[1] = 102
On a little endian system.
EDIT : To answer to your comment, if you try to dereference a randomly assigned pointer, here is what can happen:
You are lucky : the address you type correspond to a memory area which has been allocated for your program. Thus, it is a valid virtual address. You won't get a segfault, but if you modify it, it might corrupt the behavior of your program (and it surely will ...)
You are luckier : the address is invalid, you get a nice segfault that prevents your program from totally screwing things up.
It is called pointer arithmetic. Add an integer n to a pointer of type t* moves the pointer by n * sizeof(t) elements. Therefore, if sizeof(int) is 4 bytes:
p + 1 (C) == p + 1 * sizeof(int) == p + 1 * 4 == p + 4
Then it is easier to index your array:
*(p+i) is the i-th integer in the array p.
I don't know if by "memory location 2" you mean your example memory address 2 or if you mean the 2nd value in your array. If you mean the 2nd value, that would be memory address 1. To get a pointer to this location you would do int *ptr = &p[1]; or equivalently int *ptr = p + 1;, then you can print this value with printf("%d\n", *ptr);. If you mean the memory address 2 (your example address), that would be the 3rd value in the array, then you'd want p[2] or p + 2. Note that memory addresses are usually in hex and wouldn't actually start at 0. It would be something like 0x092ef000, 0x092ef004, 0x092ef008, . . .. All of the other answers aren't understanding that you are using memory addresses 0 . . . 39 just as example addresses. I don't think you honestly are referring to the physical locations starting at address 0x00000000 and if you are then what everyone else is saying is right.
Below are 2 programs
First
#include<stdio.h>
void main()
{
int a[5]={1,2,3,4,5};
int *p;
p=&a;
printf("%u %u",p,p+1);
}
Second
#include<stdio.h>
void main()
{
int a[5]={1,2,3,4,5};
printf("%u %u",&a,&a+1);
}
Now, in the two programs..I have printed the values of &a using p in first code and directly in the second..
Why are the results different?
the answer i m getting are.
for first 3219048884 3219048888
for second 3219048884 3219048904
The type of &a is int (*) [5]. Therefore &a+1 is a pointer that's 5 ints further on than a. However the type of p is int *, therefore p+1 is a pointer that's 1 int further on than p.
When I run that, I get this:
1245036 1245040 1245036 1245040
1245036 1245040 1245036 1245056
with the only difference being in the last position, p+1 vs &a+1
p is a pointer to an integer, so p+1 is the address of the next integer. (i.e 4 byte further in memeory)
a is an array of 5 integers, so &a+1 is the address of the next array of 5 integers. (i.e., 20 bytes further in memeory)
In both programs, you are printing the memory addresses of the array.
This can vary each time you run the program. The memory that the OS chooses to give you can be different.
When your program declares an array of 5 integers, The OS promises to give you 5 consecutive integers, it does NOT promise what memory you will get, or that you will get the same memory every time.
You have two programs with different stack frames, no surprise the addresses of local variables are different. Il may change each time you run the program (that's what it does when I try it, code compiled with gcc on Linux).
But you'll get the same values with the program below one except for the last value of the serie (except for the last one, because of the way pointer arithmetic works).
#include<stdio.h>
void main()
{
int a[5]={1,2,3,4,5};
int *p;
p=&a;
printf("%u %u %u %u ",a,a+1,p,p+1);
printf("%u %u %u %u",a,a+1,&a,&a+1);
}
For a (quite) complete explanation of difference between pointers and arrays you can look at my answer here
Your first program is invalid. It is illegal to assign p = &a, since p has type int * and &a has type int (*)[5]. These types are not compatible. If your compiler is loose enough to allow this kind of assignment (did it at least warn you?), it probably interpreted it as p = (int *) &a, i.e. it forcefully reinterprets the value of &a as an int * pointer. Thus, all pointer arithmetic in your first program is int * arithmetic. This is why the first program produces the same output for a+1 and p+1 values.
In the second program the value of &a is not reinterpreted. It keeps its original type ``int ()[5]and it follows the rules of normal pointer arithmetic for typeint ()[5], meaning that when you do&a + 1, the pointer is movedsizeof(int[5])` bytes, as it should. This is why the result is different from the first program.
You should use p = a and not p = &a. An array like a is already assumed a constant pointer. You do not need to dereference it with the & operator.
I am trying some programs in c face a problem with this program
can any one tell me what is the problem with this and i also want to know that when in the above case if the pointer value is incremented then will it over write the previous value address as
#include<stdio.h>
int main()
{
int a=9,*x;
float b=3.6,*y;
char c='a',*z;
printf("the value is %d\n",a);
printf("the value is %f\n",b);
printf("the value is %c\n",c);
x=&a;
y=&b;
z=&c;
printf("%u\n",a);
printf("%u\n",b);
printf("%u\n",c);
x++;
y++;
z++;
printf("%u\n",a);
printf("%u\n",b);
printf("%u\n",c);
return 0;
}
suppose that the value we got in the above program (without the increment in the pointer value )is
65524
65520
65519
and after the increment the value of the pointer is
65526(as 2 increment for the int )
65524(as 4 increment for the float )
65520(as 1 increment for the char variable )
then if in that case will the new pointer address overwrite the content of the previous address and what value be contained at the new address
You can't just increment x,y,z like that.
You have no guarantee that they are laid out in memory in that order - the memory address after 'x' could be anything.
Edit just to clarify:
Yes you can increment a pointer, but you have to be sure that you 'own' the memory that you are then pointing to - typically memory in a string or an array.
You can't assume that separate variables are adjacent to each other in memory - in fact different types will be probably be spaced out so that each new one starts at a 4byte boundary.
First of all, I assume your calls to printf are supposed to display the values of x, y and z, or the addresses of a, b, and c, correct? In that case you need to change them to:
printf("%p\n", x);
printf("%p\n", y);
printf("%p\n", z);
These will take into account the size of a pointer on your processor, if that is different from the size of an int. They will also print the address in hexadecimal, which is much more common since addresses can get quite large.
and after the increment the
value of the pointer is 65526(as 2
increment for the int )
Assuming you're on a platform where int is 2 bytes (on most modern home PCs int is probably 4 now).
then if in that case will the new
pointer address overwrite the content
of the previous address and what value
be contained at the new address
......plz help
You haven't actually dereferenced any of the pointers here. So the memory occupied by a, b, and c is still untouched; all you've done is changed what x, y, and z are pointing to. If you were to dereference one of the pointers after incrementing it, you would be modifying memory past the variable it initially pointed to. So if a is at address 65526 decimal and int is 2 bytes:
int *x = &a; // x points to the integer at "65526" (a)
x++; // x points to the integer at "65528", a is still at 65526
*x = 5; // you've just modified the memory at addresses 65528 and 65529.
If 65528 or 65529 contained some other important data (like b or c) you've just corrupted your program's state.
If you're trying to output the values of the pointers x, y and z, then you need to change the last six printf statements like so:
printf("%p\n",x);
printf("%p\n",y);
printf("%p\n",z);
x++;
y++;
z++;
printf("%p\n",x);
printf("%p\n",y);
printf("%p\n",z);
Printing them out in this way will print their addresses, and you should see their address change after you increment them.
However, if you attempt to access the values stored in them after you increment them, you'll either get garbage or your program will crash. When you increment the value of a pointer like that, it will point to the next location in memory. When the pointer points to an array it will point to the array's next cell. However, your pointers do not point to an array, so the address they point to will probably not be valid.