Warnings in a very basic Pointer Program in C - c

I've just started with pointers in c. This program gives the desired output but I am getting the below warnings when I compile it, What am I doing wrong?
pointer.c:3: warning: initialization makes pointer from integer without a cast
pointer.c:5: warning: incompatible implicit declaration of built-in function ‘printf’
pointer.c:8: warning: assignment from incompatible pointer type
pointer.c:12: warning: assignment makes pointer from integer without a cast
And my code is:
int main (int argc, char *argv[])
{
int *x=2, *ampx, *starampx, starx;
printf("x=");
printf("%d\n",x);
ampx=&x;
printf("&x=");
printf("%d\n",&x);
starampx=*ampx;
printf("*&x=");
printf("%d\n",starampx);
return 0;
}

Here is why:
initialization makes pointer from integer without a cast - int *x = 2, ... should be int x = 2, ...
incompatible implicit declaration of built-in function ‘printf’ - You need to add an #include <stdio.h> line at the top
assignment from incompatible pointer type - This will be fixed by the #1 change
assignment makes pointer from integer without a cast - *starampx should be starampx in the declaration.
In addition, printing pointers should be done with %p specifier, not %d:
printf("%p\n",&x);
Here is your fixed program on ideone: link.

int *x=2
is actually causing your program to have undefined behavior. It tells the compiler to point at an address 2, which may or may not be valid and derferencing the pointer will causes an undefined behavior.
Whenever you are using pointers, You need to make the pointer point to a valid memory big enough to store a int before you can store anything. So you either need:
int i = 2;
int *x = &i;
or you simply use:
int x = 2;
Considering, how you use x later in the program the latter is what you need.
You need to include stdio.h which tells the compiler that printf is an standard c library function.

In your code, in this statement, you have a problem.
int *x=2, *ampx, *starampx, starx;
^ ^
| |
*x is a pointer. To store the value of 2, you would need to allocate space for the same. Instead of the current implementation, please try with
int x=2, *ampx, starampx, starx;

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)

Why I can't printf value of pointer in C?

I have a simple questions. I am new in pointers in C and I don't understand why this is working and I can change value of the pointer
int main()
{
int x = 7;
int *aptr = &x;
printf("%d",*aptr);
*aptr = 21;
printf("%d",*aptr);
}
But this won't print any number
int main()
{
int x = 7;
int *aptr = 21;
printf("%d",*aptr);
}
Thanks for help!
int *aptr = 21; does not store 21 in *aptr. When = is used in a declaration, it sets the initial value for the thing being declared (which is aptr), not for the “expression picture” used for the declaration (*aptr).
In C declarations, we use pictures of a sort to describe the type. Generally, in a declaration like int declarator, declarator gives a picture of some expression we will use as an int. For example, int *foo says *foo will be an int, so it declares foo to be a pointer to an int. Another example is that int foo[3] says foo[i] will be an int, so it declares foo to be an array of int. Note that these are declaring foo, not *foo or foo[i], so, when an initial value is given, it is for initializing foo, not *foo or foo[i].
21 is not a proper value for a pointer, so the compiler complains. (Integers can be converted to pointers by using casts, but this is a special use case that requires ensuring the integers represent addresses made available in the C implementation.)
While others provided correct answers to your question, the best way to have obtained that answer was to let the compiler tell you what the problem is. When you compile your program using, say, gcc - the default compiler on most Linux machines - you get:
$ gcc -o prog prog.c
prog.c: In function ‘main’:
prog.c:6:17: warning: initialization of ‘int *’ from ‘int’ makes pointer
from integer without a cast [-Wint-conversion]
6 | int *aptr = 21;
| ^~
... and this is basically what #EricPostpischil has told you :-)
Microsoft's Visual C++ will also say something similar (godbolt.org).
So, reading the warnings your compiler generates is very important!
Also, you should consider compiling with additional compiler warning flags enabled. Read about that here:
Why should I always enable compiler warnings?
Pointer store address of variable not value.
Here , you are declaring int *aptr as an integer pointer which means that it will store the address of any integer variable not an integer.
int x = 7; // x is an integer variable.
int *aptr = 21; // aptr is an integer pointer.
you should write :
int *aptr = &x;
1X
____ ____
aptr | 1X | ----------> x | 7 |
aptr is pointing to 1X which is address of integer variable x.
So you are currently setting the address stored in aptr to 21.
This would be equivalent to setting :
int a = 7;
int *aptr = 0xFFFFFFFF //this could be a memory address
You have simply assigned what aptr points to as the memory address 7, but you don't know what is being stored at this address (or if it's in scope) so this is why you are getting an error.
To learn more about pointers try taking a look at this article : https://www.tutorialspoint.com/cprogramming/c_pointers.htm

Store function address into global variable

Consider the following code:
void f() {};
void* v = f;
int i = f;
int main() { }
Why storing function address into int variable gives me an error:
error: initializer element is not a compile-time constant
But for void* variable doesn't?
Variables declared at file scope ("global") have static storage duration.
All variables with static storage duration must be initialized to a compile-time constant. In C, other variables (not even const ones) don't count as compile-time constants, hence the error.
In addition, you cannot assign a pointer to an integer, doing so is not valid C. You have to manually convert the pointer to an integer type first, by casting it.
In addition, the cast void* v = f; is not well-defined. The C standard only specifies casts between void* and pointer to object type.
Now what you should do to get a function's address is this:
#include <stdint.h>
uintptr_t i = (uintptr_t) f;
int main (void)
{ ...
uintptr_t is guaranteed to be large enough to contain the address of any pointer.
When I compile this, I get:
$ gcc foo.c
foo.c:3:5: warning: incompatible pointer to integer conversion initializing 'int' with an expression of type 'void ()' [-Wint-conversion]
int i = f;
^ ~
foo.c:3:9: error: initializer element is not a compile-time constant
int i = f;
^
1 warning and 1 error generated.
Really, I think that warning ought to be an error. You're trying to put an address into an integer, and that's generally bad form.
That said, if the compiler goes ahead and makes the conversion, the result is not a compile-time constant (because it's a converted value). Thus the error.
Although you're not asking about C++, I was curious as to how the two languages differ, so I checked how my compiler behaved. In that language, both assignments from f are illegal, for good reason. void* is not a pointer to a parameter-less function, and int isn't either.
$ g++ foo.c
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
foo.c:2:7: error: cannot initialize a variable of type 'void *' with an lvalue of type 'void ()'
void* v = f;
^ ~
foo.c:3:5: error: cannot initialize a variable of type 'int' with an lvalue of type 'void ()'
int i = f;
^ ~
2 errors generated.
The initializations of both v and i are illegal.
However, some compilers allow conversion from a function pointer to a void* as a compiler extension.
Try compiling with your warnings cranked up (as you should by habit), and you may get warnings on the void* v = f; line as well.
A correct way to store a pointer to the function f would be
void (*p)() = f;
If you really wanted to put the underlying bits of a pointer into an int you could try this:
typedef union _UPTRINT
{
void *ptr;
int i;
} UPTRINT;
Then assign the function pointer to UPTRINT::ptr and access it as i (assuming that pointers and ints are the same size on your platform; adjust the type of i as necessary).

Pointers in C : assigning a literal to int *

What is really happening here when we provide a definition like below?
int * a = 2;
What is really happening behind the scenes?
SOLVED
Here a will point to memory address 2.
The result of conversion from integer to a pointer is implementation-defined in C, quoting C99 Section 6.3.2.3:
5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
So you shouldn't rely on such conversion except when the literal is 0 which will give you a null pointer.
In practice you are likely to find that the pointer will hold the memory address specified by the integer constant:
#include <stdio.h>
int main(void) {
int * a = 2;
printf("%p", a); /* prints 0x2 in gcc */
return 0;
}
Most compilers will also warn about this unsafe cast :
$ gcc test.c test.c: In function ‘main’: test.c:4:13: warning:
initialization makes pointer from integer without a cast [enabled by
default] int * a = 2;
^
In here the memory for "a" will not be allocated. So, it gives the segmentation fault error.
It will try to take the 2 as a address and pointer a will try to point the address 2. But it may be our system does not have that address or it may be allocated for some other process.
So, in the compiling time it will give the one warning message.
Warning: initialization makes pointer from integer without a cast [enabled by default]

Redefinition of a pointer in global scope

In this question I am thoroughly confused about this seemingly basic aspect of C. Consider these two lines of code:
int *ptr;
*ptr = 2;
gcc will emit the following warnings:
main.cpp:4:1: warning: data definition has no type or storage class [enabled by default]
*ptr = 2;
^
main.cpp:4:2: warning: type defaults to 'int' in declaration of 'ptr' [enabled by default]
*ptr = 2;
^
main.cpp:4:8: warning: initialization makes pointer from integer without a cast [enabled by default]
*ptr = 2;
^
What type is ptr being defaulted to, int or int* (as in, is ptr a pointer, or an int)? If so, does this mean that ptr is pointing to address 2, or is that unchanged? I would assume that it's changed because it crashes unless you give ptr a valid address.
int i = 5;
int *ptr;
*ptr = &i;
int main(){
printf("%d", *ptr); // 5
}
I am aware of the possibility of undefined behavior and that you shouldn't ignore warnings, but I'm trying to see what actually happens here.
For context, see the comment chain under this answer.
Here is what's going on: since the two lines that you are showing are in the file scope (as opposed to a local scope) both lines are treated as declarations, not as a declaration and an assignment statement. This is because there could be no statements at the file scope - only declarations and definitions are allowed.
Old C rules allowed declarations of type int to omit type altogether. Therefore, the second line is
A declaration / definition of ptr
...which is a pointer, because it has an asterisk
...and it is also a pointer to int, because the type is missing.
That last rule is very archaic, and it has been deprecated in the ANSI version of the language standard. That is why you get a warning. If you change your code to
int *ptr;
int *ptr = &i;
your code is going to compile and run (demo).
Now one question remains: how come the compiler does not complain about duplicate declarations? It turns out that the compiler will treat multiple identical declarations as one and the same, as long as they are entirely identical to each other.

Resources