What is the difference between float pointer and int pointer address? - c

I tried to run this code,
int *p;
float q;
q = 6.6;
p = &q;
Though it will be a warning, but i think &q and p are of same size, so p can have an address of q. But when I print &q and p I am getting different output.
This is my output
*p = 6.600000
q = 0.000000, p = 0x40d33333, &q = 0x7fffe2fa3c8c
What is that I am missing?
And p and &q is same when both pointer and variable type is same.
My complete code is
#include<stdio.h>
void main()
{
int *p;
float q;
q = 6.6;
p = &q;
printf("*p = %f \n q = %f, p = %p, &q = %p \n",*p,q,p,&q);
}

You need to take compiler warnings more seriously.
C doesn't require compilers to reject invalid programs, it merely requires "diagnostics" for rule violations. A diagnostic can be either a fatal error message or a warning.
Unfortunately, it's common for compilers to issue warnings for assignments of incompatible pointer types.
void main()
This is wrong; it should be int main(void). Your compiler may let you get away with it, and it may not cause any visible problems, but there's no point in not writing it correctly. (It's not quite that simple, but that's close enough.)
int *p;
float q;
q = 6.6;
That's ok.
p = &q;
p is of type int*; &q is of type float*. Assigning one to the other (without a cast) is a constraint violation. The simplest way to look at it is that it's simply illegal.
If you really want to do this assignment, you can use a cast:
p = (int*)&q; /* legal, but ugly */
but there's rarely a good reason to do so. p is a pointer to int; it should point to an int object unless you have a very good reason to make it point to something else. In some circumstances, the conversion itself can have undefined behavior.
printf("*p = %f \n q = %f, p = %p, &q = %p \n",*p,q,p,&q);
The %f format requires a double argument (a float argument is promoted to double in this context so float would be ok). But *p is of type int. Calling printf with an argument of the wrong type causes your program's behavior to be undefined.
%p requires an argument of type void*, not just of any pointer type. If you want to print a pointer value, you should cast it to void*:
printf("&q = %p\n", (void*)&q);
It's likely to work without the cast, but again, the behavior is undefined.
If you get any warnings when you compile a program, don't even bother running it. Fix the warnings first.
As for the question in your title, pointers of type int* and float* are of different types. An int* should point to an int object; a float* should point to a float object. Your compiler may let you mix them, but the result of doing so is either implementation-defined or undefined. The C language, and particularly many C compilers, will let you get away with a lot of things that don't make much sense.
The reason that they're distinct types is to (try to) prevent, or at least detect, errors in their use. If you declare an object of type int*, you're saying that you intend for it to point to an int object (if it's not a null pointer). Storing the address of a float object in your int* object is almost certainly a mistake. Enforcing type safety allows such mistakes to be detected as early as possible (when your compiler prints a warning rather than when your program crashes during a demo for an important client).
It's likely (but not guaranteed) that int* and float* are the same size and have the same internal representation. But the meaning of an int* object is not "a collection of 32 (or 64) bits containing a virtual address", but "something that points to an int object".

You're getting undefined behaviour, because you're passing the wrong types to printf. When you tell it to expect a float, it actually expects a double - but you pass an int.
As a result it prints the wrong information, because printf relies entirely on the format string to access the arguments you pass it.

In addition to what is said by teppic,
Consider,
int a = 5;
int *p = &a;
In this case we indicate to the compiler that p is going to point to an integer. So it is known that when we do something like *p , at runtime, the no. of bytes equal to size of an int would be read.
If you assign address of a datatype occupying x number of bytes to a pointer of which is declared to hold the address of datatypes of fewer bytes than x, you read the wrong number of bytes when using the indirection operator.

Related

Whats the difference between int *p=10 and int *p = (int *)10?

Do both statements mean the same thing that p is pointing at address location 10?
On compilation, the first initialization gives some warning. What's the meaning of that?
#include <stdio.h>
int main()
{
int *p = 10;
int *q = (int *)10;
return 0;
}
output:
warning: initialization of ‘int *’ from ‘int’ makes pointer from integer without a cast [- Wint-conversion]
Both cases convert the integer 10 to a pointer type which is used to initialize an int *. The cast in the second case makes it explicit that this behavior is intentional.
While converting from an integer to pointer is allowed, the assignment operator (and by extension, initialization) does not specifically allow this conversion, so a cast it required to be conforming. Many compilers however will still allow this and simply issue a warning (as your apparently does).
Note however that actually attempting to use a pointer that is assigned a specific numeric value will most likely cause a crash unless you're on a embedded system that supports reading or writing specific memory addresses.
int *p = 10; is incorrect (constraint violation), and the compiler must produce a diagnostic message. The compiler could reject the program, and there is no behaviour defined if it doesn't. The rule is that the initializer for a pointer must be a compatible pointer value or a null pointer constant.
int *q = (int *)10; means to convert the integer 10 to a pointer. The result is implementation-defined and it could be a trap representation, meaning that the initialization causes undefined behaviour if execution reaches this line.
int and pointer to an integer int* are different types. The 10 on the first line is an int that you are trying to assign to a pointer to int type. Hence the warning. (on X86 both share the same size, but consider that mostly coincidence at this point).
By casting the int to a pointer, like you do on the second line, you are telling the compiler "Hey, I know these are different types but I know what I'm doing, so go ahead and just treat the value 10 like a pointer because I really do want to point at the memory with an address of 10". (in almost every case the memory address of 10 is not going to be usable by you)

Addition of a number to a pointer

#include<stdio.h>
int main()
{
float a=10;
float* p=&a;
printf("%u\n",p);
p=p+3;
printf("%u",p);
}
After execution of this program I got 2 memory addresses as an output, thelatter with a value greater by 12 than the former.
#include<stdio.h>
int main()
{
float a=10;
float* p=&a;
printf("%u\n",p);
p=p+3.5;
printf("%u",p);
}
I tried changing 3 to 3.5 but I got an output with equal values of both the addresses. I expected that the value would increment at least by 12 in either cases.
What could be the reason ?
That's how pointer arithmetic works. It's designed to work on arrays.
float array[4];
float *q;
q = array; /* Now q points to the first element of the array: q == &array[0] */
printf("%p\n", q);
q += 3; /* Now q points to the fourth element of the array: q == &array[3] */
printf("%p\n", q);
When you add an integer to a pointer, it points that many elements further into the array. If the size of the array elements is N bytes, then adding x to a pointer adds x*N to the address.
On your machine, it appears that sizeof(float) is 4: you see that x*N=12, with x=3, so N=4.
Note that there are several errors in your code. In your program, p=p+3 has undefined behavior because p points to a single float (which has the same memory layout as an array of 1 float). It is an error to make a pointer point outside the boundaries of an object. On a typical PC compiler you just silently get an invalid pointer; a rare few implementations would detect the invalid pointer as soon as it's computed and abort the program with an error.
Printing the pointer value with %u is also an error. In practice it may work, print garbage, or crash, depending on your compiler and on whether pointers have the same size as unsigned int. Any halfway decent compiler would warn you that printf("%u", p) is incorrect; if yours doesn't, make sure to enable its useful warnings (e.g. gcc -O -Wall if you're using GCC).
There is only three types of pointer arithmetic is allowed in C:
Adding an integer to a pointer.
Subtracting an integer from a pointer.
Subtracting one pointer from another (they should point to same array).
Standard says that:
C11:6.5.6 Additive operators:
2 For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type. (Incrementing is equivalent to adding 1.)
3 For subtraction, one of the following shall hold:
— both operands have arithmetic type;
— both operands are pointers to qualified or unqualified versions of compatible complete object types; or
— the left operand is a pointer to a complete object type and the right operand has integer type.
Any other arithmetic operation is invalid and will invoke undefined behavior. Note that the correct specifier for printing address is %p.
the program contains several errors and poor programing practices
#include<stdio.h>
int main()
{
float a=10; // init floats with float values, so use '10.0f'
float* p=&a;
printf("%u\n",p); // print addresses with '%p' not '%u'
p=p+3; // now 'p' is pointed to some unknown area
printf("%u",p); // print addresses with '%p' not '%u'
}
good thing the code did not 'de-reference' 'p' after 'p'
was modified, because that would have been undefined behaviour
possibly leading to a seg fault event

why to cast pointers?

I have a little basic question about C pointers and casting.
I didn't understand why should I cast the pointers?
I just tried this code and I got the same output for each option:
#include <stdio.h>
int main(void)
{
int x = 3;
int *y = &x;
double *s;
option 1: s = (double*)y;
option 1: printf("%p, %d\n", (int*)s, *((int*)s));
option 2: s = y;
option 2: printf("%p, %d", s, *s);
return 0;
}
My question is why do I have to do: s = (double*)y?
Intuitively, the address is the same for all the variables. The difference should be about how many bytes to read from this address. Also, about the printing - if I use %d it will take automatically as an int.
Why do I need to cast it as an int*?
Am I wrong?
There is a great deal of confusion in your question. int and double are different things: they represent numbers in memory using different bit patterns and in most cases even a different number of bytes. The compiler produces code that converts between these representations when you implicitly or explicitly require that:
int x = 3;
double d;
d = x; // implicit conversion from integer representation to double
d = (double)x; // explicit conversion generates the same code
Here is a more subtle example:
d = x / 2; // equivalent to d = (double)(x / 2);
will store the double representation of 1 into d. Whereas this:
d = (double)x / 2; // equivalent to d = (double)x / 2.0;
will store the double representation of 1.5 into d.
Casting pointers is a completely different thing. It is not a conversion, but merely a coertion. You are telling the compiler to trust you know what you are doing. It does not change the address they point to, not does it affect the bytes in memory at that address. C does not let you store a pointer to int into a pointer to double because it is most likely an error: When you dereference the pointer using the wrong type, the content of memory is interpreted the wrong way, potentially yielding a different value or even causing a crash.
You can override the compiler's refusal by using an explicit cast to (double*), but you are asking for trouble.
When you later dereference s, you may access invalid memory and the value read is definitely meaningless.
Further confusion involves the printf function: the format specifiers in the format string are promisses by the programmer about the actual value types he passes as extra parameters.
printf("%p,%d",s,*s)
Here you pass a double (with no meaningful value) and you tell printf you passed an int. A blatant case of multiple undefined behaviour. Anything can happen, including printf producing similar output as the other option, leading to complete confusion. On 64 bit Intel systems, the way doubles and ints are passed to printf is different and quite complicated.
To avoid this kind of mistake in printf, compile with -Wall. gcc and clang will complain about type mismatches between the format specifiers and the actual values passed to printf.
As others have commented, you should not use pointer casts in C. Even the typical case int *p = (int *)malloc(100 * sizeof(int)) does not require a cast in C.
Explicit pointer casting is necessary to avoid compiler warnings. And compiler warnings on pointer type conflict exist to show possible bugs. With pointer casting you tell the compiler: "I know what I am doing here..."

Why typecasting between char *ptr to int and int *ptr to char works completely fine? when they are designed to point to specific datatyped variables

I have just started learning pointers. I have some questions regarding pointers typecasting. Consider below program.
int main(){
int a = 0xff01;
char *s = &a;
char *t = (int *) &a;
printf("%x",*(int *)s);
printf(" %x",*(int *)t);
return 0;
}
The statement char *s = &a gives
warning: incompatible pointer conversion type.
But noticed that the two printf() statements works fine they give me the right output. The question is
char *t , char *s both are pointers to character type.
Why does 'C' compilers lets me to assign integer variable to char *p ? why dont they raise an error and restrict the programmer?
We have int *ptr to point to integer variables, then why do they still allow programmer to make char *ptr point to integer variable?
// Another sample code
char s = 0x02;
int *ptr = (char *)&s;
printf("%x",*(char *)ptr); // prints the right output
Why does an int *ptr made point to character type? it works. why compiler dont restrict me?
I really think this leads me to confusion. If the pointer types are interchangeable with a typecast then what is the point to have two different pointers char *ptr , int *ptr ?
when we could retrieve values using (int *) or (char *).
All pointers are of same size 4bytes(on 32bite machine). Then one could use void pointer.
Yes people told me, void pointers always needs typecasting when retrieving values from memory. When we know the type of variable we go for that specific pointer which eliminates the use of casting.
int a = 0x04;
int *ptr = &a;
void *p = &a;
printf("%x",*ptr); // does not require typecasting.
printf("%x",*(int *)p); // requires typecasting.
Yes, I have read that back in old days char *ptrs played role of void pointers. Is this one good reason? why still compilers support typecasting between pointers? Any help is greatly appreciated.
Compiling with GCC 4.9.1 on Mac OS X 10.9.5, using this mildly modified version of your code (different definition of main() so it compiles with my preferred compiler options, and included <stdio.h> which I assume was omitted for brevity in the question — nothing critical) in file ptr.c:
#include <stdio.h>
int main(void)
{
int a = 0xff01;
char *s = &a;
char *t = (int *) &a;
printf("%x",*(int *)s);
printf(" %x",*(int *)t);
return 0;
}
I get the compilation errors:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror ptr.c -o ptr
ptr.c: In function ‘main’:
ptr.c:6:15: error: initialization from incompatible pointer type [-Werror]
char *s = &a;
^
ptr.c:7:14: error: initialization from incompatible pointer type [-Werror]
char *t = (int *) &a;
^
cc1: all warnings being treated as errors
$
So, both assignments are the source of a warning; my compilation options turn that into an error.
All pointers other than void * are typed; they point to an object of a particular type. Void pointers don't point to any type of object and must be cast to a type before they can be dereferenced.
In particular, char * and int * point to different types of data, and even when they hold the same address, they are not the same pointer. Under normal circumstances (most systems, most compilers — but there are probably exceptions if you work hard enough, but you're unlikely to be running into one of them)…as I was saying, under normal circumstances, the types char * and int * are not compatible because they point to different types.
Given:
int data = 0xFF01;
int *ip = &data;
char *cp = (char *)&data;
the code would compile without complaint. The int data line is clearly unexceptional (unless you happen to have 16-bit int types — but I will assume 32-bit systems). The int *ip line assigns the address of data to ip; that is assigning a pointer to int to a pointer to int, so no cast is necessary.
The char *cp line forces the compiler's hand to treat the address of data as a char pointer. On most modern systems, the value in cp is the same as the value in ip. On the system I learned C on (ICL Perq), the value of a char * address to a memory location was different from the 'anything else pointer' address to the same memory location. The machine was word-oriented, and byte-aligned addresses had extra bits set in the high end of the address. (This was in the days when the expansion of memory from 1 MiB to 2 MiB made a vast improvement because 750 KiB were used by the O/S, so we actually got about 5 times as much memory after as before for programs to use! Gigabytes and gibibytes were both fantasies, whether for disk or memory.)
Your code is:
int a = 0xff01;
char *s = &a;
char *t = (int *) &a;
Both the assignments have an int * on the RHS. The cast in the second line is superfluous; the type of &a is int * both before and after the cast. Assigning an int * to a char * is a warnable offense — hence the compiler warned. The types are different. Had you written char *t = (char *)&a;, then you would have gotten no warning from the compiler.
The printing code works because you take the char * values that were assigned to s and t and convert them back to the original int * before dereferencing them. This will usually work; the standard guarantees it for conversions to void * (instead of char *), but in practice it will normally work for anything * where anything is an object type, not a function type. (You are not guaranteed to be able to convert function pointers to data pointers and back again.)
The statement char *s = &a gives
warning: incompatible pointer conversion type.
In this case, the warning indicates a constraint violation: A compiler must complain and may refuse to compile. For initialization (btw, a declaration is not a statement), the same conversion rules as for assignment apply, and there is no implicit conversion from int * to char * (or the other way round). That is, an explicit cast is required:
char *s = (char *)&a;
Why do C compilers let me assign an integer variable to char *p? Why don’t they raise an error and restrict the programmer?
Well, you’ve got a warning. At the very least, a warning means you must understand why it is there before you ignore it. And as said above, in this case a compiler may refuse to compile.*)
We have int *ptr to point to integer variables, then why do they still allow programmer to make char *ptr point to integer variable?
Pointers to a character type are special, they are allowed to point to objects of every type. That you’re allowed to do so, doesn’t mean it’s a good idea, the cast is required to keep you from doing such a conversion accidently. For pointer-to-pointer conversions in general, see below.
int *ptr = (char *)&s;
Here, ptr is of type int *, and is initialized with a value of type char *. This is, again, a constraint violation.
printf("%x",*(char *)ptr); // prints the right output
If a conversion from a pointer to another is valid, the conversion back also is and always yields the original value.
If the pointer types are interchangeable with a typecast then what is the point to have two different pointers char *ptr, int *ptr?
Types exist to save you from errors. Casts exist to give you a way to tell the compiler that you know what you’re doing.
All pointers are of same size 4bytes(on 32bite machine). Then one could use void pointer.
That’s true for many architectures, but quite not for all the C standard addresses. Having only void pointers would be pretty useless, as you cannot really do anything with them: no arithmetic, no dereferencing.
Yes, I have read that back in old days char *ptrs played role of void pointers. Is this one good reason?
Perhaps a reason. (If a good one, is another question…)
When pointer-to-pointer conversions are allowed:
C11 (N1570) 6.3.2.3 p7
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned×) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
×) In general, the concept “correctly aligned” is transitive: if a pointer to type A is correctly aligned for a pointer to type B, which in turn is correctly aligned for a pointer to type C, then a pointer to type A is correctly aligned for a pointer to type C.
Pointers to character types and pointers to void, as mentioned above, are always correctly aligned (and so are int8_t and uint8_t if they exist). There are platforms, on which a conversion from an arbitrary char pointer to an int pointer may violate alignment restrictions and cause a crash if executed.
If a converted pointer satisfies alignment requirements, this does not imply that it’s allowed to dereference that pointer, the only guarantee is that it’s allowed to convert it back to what it originally pointed to. For more information, look for strict-aliasing; in short, this means you’re not allowed to access an object with an expression of the wrong type, the only exception being the character types.
*) I don’t know the reasons in your particular case, but as an example, where it’s useful to give implementations such latitude in how to treat ill-formed programmes, see for example object-pointer-to-function-pointer conversions: They are a constraint violation (so they require a diagnostic message from the compiler) but are valid on POSIX systems (which guarantess well-defined semantics for such conversions). If the C standard required a conforming implementation to abort compilation, POSIX had to contradict ISO C (cf. POSIX dlsym for an example why these conversions can be useful), which it explicitly doesn’t intend to.
Pointers are not having any types, types described with pointer in program actually means that to which kind of data pointer is pointing. Pointers will be of same size.
When you write,
char *ptr;
it means that is is pointer to character type data and when dereferenced, it will fetch one bytes data from memory
Similarly,
double *ptr;
is pointer to double type data. So when you dereference, they will fetch 8 bytes starting from the location pointed by pointer.
Now remember that all the pointer are of 4 bytes on 32 bit machines irrespective of the type of data to which it is pointing. So if you store integer variable's address to a pointer which is pointing to character, it is completely legal and if you dereference it, it will get only one byte from memory. That is lowest byte of integer on little endian pc and highest byte of integer on big endian pc.
Now you are type casting your pointer to int type explicitly. So while dereferencing it will get while integer and print it. There is nothing wrong with this and this is how pointers work in c.
In your second example you are doing the same. Assigning address of character type variable to pointer which is pointing to integer. Again you are type casting pointer to character type so by dereference it will get only one byte from that location which is your character.
And frankly speaking, i dont know any practical usage of void pointer but as far as i know, void pointers are used when many type of data is to be dereferenced using a single pointer.
Consider that you want to store an integer variable's address to pointer. So you will declare pointer of integer type. Now later in program there is a need to store a double variable's address to pointer. So instead of declaring a new pointer you store its address in int type pointer then if you dereference using it, there will be a big problem and result in logical error which may get unnoticed by you if you have forgot to type cast it to double type. This is not case with void pointer. If you use void pointer, you have to compulsarily type cast it to particular type inorder to fetch data from memory. Otherwise compiler will show error. So in such cases using void pointer reminds you that you have to type cast it to proper type every time otherwise compiler will show you error. But no error will be shown in previous case

C Syntax Explanation

I am studying C Language I need some explanation about a code segments,
int *p;
p = (int *) malloc(sizeof(int));
What does the (int *) means and whats really happening when you execute the above Code?
(int *) is a so called cast operator. It is used to convert the value on the right side of the operator to the type enclosed in parenthesis.
Here, it is used to convert the void * pointer returned by malloc() to an int *, i.e. a pointer to an integer.
This is a very bad usage, and you should not do it.
malloc has return type void*, which reads as pointer-to-void which means pointer-to-something.
p has type int*, so pointer-to-int. In order to assign the result of malloc into p, you need to convert int* into void* somehow.
If you write:
int* p = malloc(...)
the conversion happens automatically ("implicit conversion").
If you, for some reason, decide to write:
int* p = (int*) malloc(...)
the result is the same, but the conversion is explicit (i.e. a "cast").
Here's the documentation on malloc.
You're allocating a block of memory the size of an int (this value may change depending on the system/compiler combo).
The (int *) casts the right hand side as an int *, which isn't necessary in C, you just need the malloc.
int *p; // pointer to an integer
p = (int *) malloc(sizeof(int)); // assignment of enough memory for an integer
The (int *) part is called typecasting, you're telling the compiler:
"I know malloc() gives me a void *, but I'm going to assign it to something else".
There are useful reasons to typecast, but it can be dangerous too. In this case since malloc() returns a void * you don't need to typecast because it's automatically and safely converted to other pointer types.
Try this link man malloc
In C, there is no need of typecasting in mallocso write directly
p = malloc(sizeof(int));
FYI , this (int *) is nothing but the typecast. Since many functions return void*
so it needs to typecast in the respective type for further manipulations with pointers.
In case of malloc it's implicitely taken care of
(type) is called type cast operator in C.
suppose for example,
int a;
float b = 11.4;
You want to put the integral value of bin a. Use type casting
a = (int)b
Unwind already gave you the answer, but I want to expand on it a bit.
In C, some types are not compatible; you can't directly assign a value of type T to a variable of type Q; for example, you can't assign a pointer to int to a variable that's type pointer to double:
double *q;
int *p;
...
q = p; // will cause a diagnostic to be issued
If you really need to make that assignment, though, you can use a cast expression, which converts the value to the target type:
q = (double *) p;
This tells the compiler to convert the value of p to pointer to double and assign the result to q.
In the original, K&R version of C, malloc returned char *, so if you wanted to assign the result of malloc to a pointer of a different type, you had to apply the cast:
int *p = (int *) malloc(SIZE);
That changed in 1989, when the first C standard was introduced. That version introduced a void * type to act as a "generic" pointer type. Values of type void * can be assigned to other pointer types directly, without need of a cast. So, as of C89 and later, you can simply write
int *p = malloc(SIZE);
This was not only cleaner, it was also safer; if you forgot to include stdlib.h or otherwise didn't have a declaration for malloc in scope, the compiler would assume that malloc returned an int value and generate code accordingly. Since an int value can't be directly assigned to a pointer type, you would get a diagnostic. If you added the cast, however, that warning would be suppressed, and you would potentially have issues at runtime.
The 1999 standard got rid of the implicit int assumption, so that's no longer a real danger, but it's still better style to leave the cast off of a malloc call.

Resources