why is the address px+1 holding the value 0.3? (on every execution) the variable f has also the value 0.3, but it has an other address(px-1)!? (even the values on px+2, px+3 and px-2 hold the value 0.3..., when I print it out)
#include <stdio.h>
int main(){
int* px;
int i = 1;
float f= 0.3;
double d=0.005;
char c = '*';
px=&i;
printf("Values: i=%i f=%f d=%f c=%c\n",i,f,d,c);
printf("Addresses: i=%lX f=%lX d=%lX c=%lX\n",&i,&f,&d,&c);
printf("Pointer Values (size of int = %d):\n px=%lX; px+1=%lX; px+2=%lX; px+3=%lX\n",sizeof(int),px,px+1,px+2,px+3);
printf("Dereference: at px+1=%lX, value is:%f \n",px+1,*(px+1));
/* Output :
Values: i=1 f=0.300000 d=0.005000 c=*
Addresses: i=7FFF5C546BB4 f=7FFF5C546BB0 d=7FFF5C546BA8 c=7FFF5C546BA7
Pointer Values (size of int = 4):
px=7FFF5C546BB4; px+1=7FFF5C546BB8; px+2=7FFF5C546BBC; px+3=7FFF5C546BC0
Dereference: at px+1=7FFF5C546BB8, value is:0.300000
*/
}
You have several problems, all leading to undefined behavior. First of all, you should use "%p" to print pointers, and the pointers should be casted to void * for maximum compatibility. Secondly, dereferencing a pointer out of bounds, like when you do *(px + 1) leads to undefined behavior. Thirdly, the pointer px points to an integer, but you try to print it using float conversion which also leads to undefined behavior.
By writing *(px+1), you're trying to access out of bound memory. It invokes undefined behaviour.
Also,
to print an address, you should be using the %p format specifier.
to print an int you should use %d or %i
Related
I initialized the pointer with a constant, and I knew its address will be delivered to the pointer. So when I tried to test whether the constant can be print or not, the program crashed. Is that illegal?
#include <stdio.h>
int main()
{
int *i = (int *)1;
printf("The value that i pointer points to is %d\n", *i);
return 0;
}
You seem to think (int *)1 produces the address where the value 1 is stored. It does not.
When a cast such as (int *) is used to convert an integer to a pointer, the result is generally that the value is made into an address.1
Thus int *i = (int *)1; sets i to point to the address 1. Then, when attempting to print *i, your program crashed because 1 was not a valid memory address. (Quite commonly, the first page of memory is kept unmapped so that incorrect uses of the null pointer will crash and reveal a problem rather than allowing the program to continue executing with incorrect data.)
To set i to point to an int with the value 1, you must set it to the address of an int object that has the value 1. One way to do this is:
int n = 1;
int *i = &n;
You can also create an unnamed int with the value 1 using a compound literal:
int *i = & (int) { 1 };
The (int) { 1 } creates a compound literal with the value 1, and the & takes its address, and then i is initialized to that address.
Footnote
1 According to the C standard, the result is implementation-defined. So a compiler could define any result it wants. However, every C compiler I have seen makes the integer value into an address, in one way or another. The resulting address is not necessarily valid to use for accessing an object.
(int *)1; is not a pointer to value 1. but rather the pointer to the memory cell # 1. What you probably want is
#include <stdio.h>
int main()
{
int n=1;
int *i = &n;
printf("The value that i pointer points to is %d\n", *i);
return 0;
}
printf("The value that i pointer points to is %d\n", *i);
You try to dereference the pointer i, but it's value (the value of the pointer) is some value, you set yourself. Can you guarantee that at address 0x0001 is an integer you own? All you can do with such a pointer is print it's pointer value (not the value it points to):
printf("The value of pointer i is %p\n", i);
Causes a segmentation fault:
int n;
int *variable = scanf("%d",&n);
printf("Printing :%d",*variable);
No problem:
int n;
scanf("%d",&n);
int *variable = &n;
printf("Printing :%d",*variable);
How to achieve the first one without the segmentation fault?
Assuming scanf was successful, it returns 1 (in general it returns the number of variables that were set).
In your second snippet you discard that (useful) information, and you are setting a pointer varaible to the address of n, which is perfectly valid. (If scanf returned 0 then n would be uninitialised, and the behaviour of your printf call undefined.)
In the first snippet you set a pointer to the int constant 0 or 1 depending on the return value of scanf. That's fine too, but the behaviour on dereferencing that pointer with
*variable
is undefined.
If you want to be flashy, and have a robust conversation with your code reviewer, you could use the expression separator operator and write
int n;
int *variable = (scanf("%d",&n), &n);
but that's naughty since, again, you discard the return value of scanf, and n could be uninitialised.
scanf("%d",&n); returns integer not pointer to integer. Below is the prototype of scanf.
int scanf(const char *format, ...);
When you point like below you are actually pointing to invalid address and it will lead to undefined behavior.
int *variable = scanf("%d",&n);
When you declare and initialize the pointer you assign the value to the pointer itself. The * is needed to show the compiler that you are declaring the pointer to the object of some type not the object itself
When you use the * later in the code you dereference that pointer.
void foo(void)
{
int a;
int *b = &a; //you assign the pointer `b` itself - no dereferencing
*b = 5; //you dereference the pointer and asssign the the referenced object
}
The "fresh" declared pointer (unless initialized with the reference to the valid object) does not point to the valid object and its dereferencing invokes the Undefined Behavior
void foo(void)
{
int a;
int *b = &a; //b is pointing to the valid object -> the variable `a`
int *c; //c is not pointing to valid object
int *d; //d is not pointing to valid object
c = malloc(sizeof(*c)); //now c is pointing to the valid object (if malloc has not failed of course)
*c = 5 // correct no UB
*d = 5; // incorrect - UB
*b = 5; //correct no UB
}
the syntax is similar (the * before the pointer name) but it does something completely different. I have noticed that it is a bit confusing for the beginners
#include <stdio.h>
int main () {
char c = 'A';
int *int_ptr;
double *double_ptr;
*int_ptr = *(int *)&c;
*double_ptr = *(double *)&c;
printf("Original char = %c \n", c);
printf("Integer pointer = %d \n", *int_ptr);
printf("Double pointer = %f\n", *double_ptr);
return 0;
}
The questing is – Why can't I assign the double_ptr using this code, because it causes segmentation fault, but works fine for integer?
As I understand char is 1-byte long and int is 4-bytes long, so double is 8 bytes-long.
By using expression *(double *)&c I expect the following:
& – Get the memory address of c.
(double *) – pretend that this is a pointer to double.
*() – get the actual value and assign it to double var.
Your code has Undefined Behaviour. Therefore anything could happen.
The UB is because you are casting a char which is one byte to types that are 4 and 8 bytes, which means you are (potentially) accessing memory out of bounds, or with the wrong alignment.
Whether any of this will "work" or "not work" on any particular system is not very relevant, because the code is erroneous.
In your program, typecast of char to int* or double* and then a dereference would get some number of extra bytes from memory, which is undefined behavior.
#include <stdio.h>
int main()
{
int i;
int buf[10];
char *p ;
p = 4;
printf("%d",p);
return 0;
}
Output:
4
How come it is 4? I was expecting some address value. Can you please help me understand it?
This is undefined behavior, because %d expects an integer.
The reason why you see this output is that pointers have enough capacity to store small integer numbers, such as 4. If by coincidence the pointer size on your system matches the size of an integer, printf would find a representation that it expects at the location where it expects it, so it would print the numeric value of your pointer.
The proper way to print your pointer would be with the %p format specifier, and a cast:
printf("%p", (void*)p);
I was expecting some address value.
You would get an address value if you had assigned p some address. For example, if you did this
char buf[10];
char *p = &buf[3];
printf("%p", (void*)p);
you would see the address of buf's element at index 3.
Demo.
If I run the following on OS X:
int main (void)
{
int* n; // initialise(declare) pointer
*n = 20; // the value in address pointed to by n is 20
printf("n: %i, n&: %i\n", n, &n);
return 0;
}
I get:
n: 1592302512, n&: 1592302480
Why the differing values?
Why do pointer and &pointer have different values?
The expression &n yields the address of n itself, while n evaluates to the value of the pointer, i.e. the address of the thing it points to.
But note that you have undefined behaviour First of all, because you are de-referencing an uninitialized pointer. You need to make n point somewhere you can write to.
For example,
int* n;
int i = 42;
n = &i;
// now you can de-reference n
*n = 20;
Second, you have the wrong printf specifier for &n. You need %p:
printf("n: %i, &n: %p\n", n, &n);
int* n declares a variable called n which is a pointer to an integer.
&n returns the address of the variable n, which would be a pointer to a pointer-to-integer.
Let's say we have the following code:
int a = 20; // declare an integer a whose value 20
int* n = &a; // declare a pointer n whose value is the address of a
int** p = &n; // declare a pointer p whose value is the address of n
In this case we would have the following:
variable name | value | address in memory
a | 20 | 1592302512
n | 1592302512 | 1592302480
p | 1592302480 | who knows?
In your code
int* n; //initialization is not done
*n = 20;
invokes undefined behavior. You're trying to de-reference (write into) uninitialized memory. You have to allocate memory to n before de-referencing.
Apart form that part,
n is of type int *
&n will be of type int **
So, they are different and supposed to have different values.
That said, you should use %p format specifier with printf() to print the pointers.
Just as an alternative, let me spell this out a different way.
char *ptr;
char c='A';
ptr = &c;
In this code, here's what's happening and what values are found when we qualify ptr in different ways.
ptr itself contains the address in memory where the char c variable is located.
*ptr dereferences the pointer, returning the actual value of the variable c. In this case, a capital A.
&ptr will give you the address of the memory location that ptr represents. In other words, if you needed to know where the pointer itself was located rather than what the address is of the thing that it points to, this is how you get it.