Basic program, Interesting output? Explanation - c

I'm learning about pointers, and I'm running this program from the tutorial that gives some interesting output.
#include <stdio.h>
int main () {
int var = 20; /*actual variable declaration */
int *ip; /*pointer variable declaration*/
ip = &var; /*store addres of var in ip variable*/
printf("Address of var variable: %x\n", &var);
/*address stored in ip variable*/
printf("Address of stored in ip variable: %x\n", ip);
/*access the value using pointer */
printf("value of *ip variable: %x\n", *ip);
return 0;
}
And to my understanding, the site says my output should be Two matching memory locations, and the value of 20 for the "Value of *ip variable" part. I have no issue with the memory locations, they both come up as the same just as one would assume however, the last part, its telling me the value of the *ip variable is 14?
Address of var variable: 6d73b8cc
Address of stored in ip variable: 6d73b8cc
value of *ip variable: 14
Whats going on here? Compiled with gcc, which gives one warning about format %x expects an unsigned integer but argument 2 has type of....
MorePointers.c:10:9: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("Address of var variable: %x\n", &var);
^
MorePointers.c:13:9: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("Address of stored in ip variable: %x\n", ip);
Correct me, please, if I am wrong, but could it be due to the format, which when expecting an unsigned integer could cause the number to be one other than 20? being an unsigned integer is within values 0 to 65,535 or 0 to 4,294,967,295, while an integer is within values -32,768 to 32,767 or -2,147,483,648 to 2,147,483,647?

What's happening is that you've printed the integer value 20 as a hexadecimal value, which rightly is displayed as 14. I suspect you were expecting 20 decimal. :)

Some fixes :-
printf("Address of var variable: %x\n", &var);
This is incorrect, a pointer should be printed as a pointer value
printf("Address of var variable: %p\n", &var); /* << ensure pointer value */
When you call printf, it mixes fixed text with parameters in order...
printf( "hello %d world %d today %d\n", 1,2,3 );
Prints hello 1 world 2 today 3
The way a parameter is displayed is based on the format specifier.
%s /* displays as a string */
%d /* displays as an integer in normal decimal */
%x /* displays an integer in hexa-decimal. */
%f /* displays as a floating point */
%p /* displays a pointer address */
Decimal goes 0,1,2,..,8,9,10,11,...,14,15,16,17,...,20
Hexadecimal goes 0,1,2,..,8,9, A, B,..., E, F,10,11,...,14

You are printing the hexadecimal value of var or *ip, which is 0x14.
Use %d for decimal value.

The first two printf() statements have undefined behaviour, as %x requires the corresponding parameter to be of type unsigned, not a pointer. Hence the warnings. Look up the %p format if you want to print the value of pointers (and convert the pointers to (void *) to use that).
%x prints the value in hex, base 16. The value of 20 (decimal) in hex is 14 (1*16 + 4). Strictly speaking, you should convert an int to unsigned to use %x.

printing addresses with printf() should be done with '%p' not '%x'.
If you compiled with all the warnings enabled (for gcc, at a minimum use: -Wall -Wextra -pedantic )
then the compiler would have told you, for line 10 and line 13:
warning: format: '%x' expects argument of type 'unsigned int', but argument two has type 'int*' [-Wformat=]`
The last call to printf() is passing a type of 'int' but the '%x' is expecting a unsigned int.
suggest declaring 'ip' and 'var' as unsigned int rather than int
or change the last printf() to:
printf("value of *ip variable: %d\n", *ip);
you can read.learn about the format specifiers for printf() at:
<http://www.codingunit.com/printf-format-specifiers-format-conversions-and-formatted-output>
or reading the printf man page

Related

Format specifier int * warning message

I wrote simple C program with scanf & printf like:
int n;
scanf("%d", &n);
int result = 7 - n;
printf("%d", &result);
and got this warning message:
warning: format '%d' expects argument of type 'int', but argument 2
has type 'int *' [-Wformat=]
printf("%d", &result);
I dont understand why argument 2 has type int * instead of int? How can I solve this?
result is a integer variable. If you want to print its value then use %d format specifier & provide the argument as only result not &result.
This
printf("%d", &result);
replace with
printf("%d", result);
If you want to print the address of result variable then use %p format specifier.
printf("%p", &result); /* printing address */
Edit : %p format specifier needs an argument of void* type.
So to print the address of result cast it as void*. for e.g
printf("%p", (void*)&result); /* explicitly type casting to void* means it works in all cases */
Thanks #ajay for pointing that, I forgot to add this point.

format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’

Each time I submit a program on hackerrank the following error occurs.
solution.c: In function ‘main’:
solution.c:22:14: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d", &sum);
It would be very helpful if someone could tell me what this means?
I assume that you have declared sum as an int. So the correct call to printf is :
printf("%d", sum);
as %d specifier means that you are going to print an int, but you are passing the int's address, which is a pointer to int, or int *.
NOTE : Do not confuse printf with scanf, as the second does require a pointer. So, for reading variable sum, you would use :
scanf("%d", &sum);
but for printing, the correct way is without &, as written above.
If you want to print the address of sum you can use printf( "%p", &sum )
Int is a primitive, primitives are data stored in memory. each data chunck is set in a specific memory block, those blocks has "memory addresses" that refer to them.
If you define int i = 1 your computer allocates an integer in memory (in a block, with a memory address f.e. 0xF00000) and sets its value to 1.
When you refer to this integer as i, you are accessing the value stored in 0xF00000, that happen to be 1.
In C you can also get the i reference (the memory address it's allocated in) by prefixing it with & (ampersand), by doing this you will get the memory address of the variable rather than its value.
i === 1; // true
&i === 1; //false
&i === 0xF00000; //true
This memory address can be assigned to a pointer (a variable that 'points' to a memory address, thus, have no it's own value) so it can be accessed directly too dereferencing it so you can gather the value inside that memory block. This is achieved using *
int i = 1; //this allocates the
int *ptr = &i; //defines a pointer that points to i address
/* now this works cause i is a primitive */
printf("%d", i);
/* this works also cause ptr is dereferenced, returning the
value from the address it points, in this case, i's value */
printf("%d", *ptr);
In your example, you are passing a reference to printf (printf asks for a value and is receiving a memory address) so it doesnt work.
Hope this helps you understand C and pointers better
#include<stdio.h>
int main(){
int var = 10;
int* a = &var;
printf("%d", a);
return 0;
}
First i Used "%d" and it shows error that format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’
then I replace "%d" with "%p" and it Works.
#include<stdio.h>
int main(){
int var = 10;
int* a = &var;
printf("%p", a);
return 0;
}
you have to use "%p" to print address of a variable. Thank you

Warning C4477 in Visual Studio 2015

When I compile the following code, Visual studio shows warning of C4477. Why this warning generated by visual studio? And How can I fix this code?
warning : warning C4477: 'printf' : format string '%d' requires an argument of type 'int', but variadic argument 1 has type 'int *'
#include <stdio.h>
int main(void) {
int num = 0;
int *pi = &num;
printf("Address of num: %d Value: %d\n", &num, num);
printf("Address of pi: %d Value: %d\n", &pi, pi);
return 0x0;
}
Because you are using incorrect format specifier. %d is to print an int. To print pointers use %p and cast to void*:
printf("Address of num: %p Value: %d\n", (void*)&num, num);
printf("Address of pi: %p Value: %p\n", (void*)&pi, (void*)pi);
The cast to void* is needed because variadic functions don't do any type conversions from type * to void * as required for %p. Quoting the standard:
7.21.6 Formatted input/output functions (C11 draft)
p The argument shall be a pointer to void. The value of the pointer is
converted to a sequence of printing characters, in an
implementation-defined manner.
Said another way, your argument &num (or in the form (void *) &num) is telling the compiler that you wish to pass in to the function the address of num, not the value of num. The printf function with it's %d format specifier is expected a value, not an address. The complaint is the compiler realizing this difference.
Note: in the 32 bit work, an address and an int are both 32 bits and so things (i.e. the %d) would just work. But, in the 64 bit world, an int is still 32 bits long but an address is 64 bits. I.E. you can't accurately represent the value of the pointer with a %d. That's why %p got created. It (the compiler) is smart enough to handle a %p parameter as a 32 bit quantity when compiled for 32 bits and a 64 bit quantity when compiled for 64 bits.
Read up on computer architecture, hardware stacks and their bit sizes. While you're at it you may also wish to understand the difference between little endian and big endian.

Why is my printf formatting not working with GCC but is running on Windows

We just did a lesson of C on pointers and I had trouble running the example code on my linux machine (Mint 17 64 bit) though it's running fine on Windows 7 (32 bit). The code is as follows:
#include <stdio.h>
int main() {
int var = 20; //actual variable declaration
int *ip; //pointer declaration
ip = &var; //store address of var in pointer
printf("Address of var variable: %x\n", &var);
//address stored in pointer variable
printf("Address stored in ip variable: %x\n", ip);
//access the value using the pointer
printf("Value of *ip variable: %d\n", *ip);
return 0;
}
The program runs as expected on windows with the code blocks ide, but on linux trying to compile in the terminal using GCC I get the following error:
pointers.c: In function ‘main’:
pointers.c:9:2: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("Address of var variable: %x\n", &var);
^
pointers.c:12:2: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("Address stored in ip variable: %x\n", ip);
^
I'd like to know what's going on and how I can get the code to run on linux.
The %x format specifier requires unsigned int value, otherwise it's undefined behaviour (so anything could happen, you can't be sure what it does on any other compiler or maybe different moon phase). According to latest C99 draft, 7.19.6.1 The fprintf function p.8, 9 (emphasis mine)
o,u,x,X The unsigned int argument is converted to unsigned octal (o),
unsigned decimal (u), or unsigned hexadecimal notation (x or X)
If any argument is not the correct type for the corresponding
conversion specification, the behavior is undefined.
Note that for pointers you should use %p format specifer rather than %x or %d, e.g.:
printf("%p\n", (void *) ip);

Data type warning when initializing pointers

I'm currently trying to wrap my head around pointers in C, coming from front-end developing this not an entirely easy endeavour. I'm following this tutorial, and everything is running smoothly until I try to compile the following example:
#include <stdio.h>
int main(int argc, char *argv[]) {
int **ramon;
int *paul;
int melissa = 5;
paul = &melissa;
ramon = &paul;
printf("ramon = %d\n", ramon); // <- warning: format '%d' expects type 'int'...
printf("&paul = %d\n", &paul); // <- warning: format '%d' expects type 'int'...
printf("*ramon = %d\n", *ramon); // <- warning: format '%d' expects type 'int'...
printf("&melissa = %d\n", &melissa); <- warning: format '%d' expects type 'int'...
printf("**ramon = %d\n", **ramon);p1); <- warning: format '%d' expects type 'int'...
return(0);
}
From the first printf line I get this error: "warning: format '%d' expects type 'int', but argument 2 has type 'int **'"
I reckon this has to do with the way I initialize my pointers, but standing at the bottom of a steep learning curve I don't know how to progress. What is wrong, how do I initialize pointers to avoid the warnings?
Your pointer initialization looks correct. The problem is that you are trying to print a variable of type int** (i.e. a "pointer to a pointer to an int") using the %d format specifier which is for int values.
Print int value
If you want to print the value of melissa (i.e. 5) which is essentially what ramon is indirectly pointing to, you need to de-reference the pointer value the correct number of times.
De-referencing pointers is done via the * operator, and it essentially means "the value at which this pointer is pointing to".
De-referencing it once (i.e. *ramon) will get the int* value which ramon is pointing to.
De-referencing it a second time will get the int value which the de-referenced int* value is pointing to.
You can chain together de-reference operators like so to get what you want:
printf("ramon = %d\n", **ramon);
Print pointer value
If you want to print a pointer (i.e. memory location) value, you can use the %p format specifier. This will print the memory address out in hex:
printf("ramon = %p\n", ramon); // Print the "pointer to the pointer to melissa"
printf("ramon = %p\n", *ramon); // Print the "pointer to melissa"
ramon isn't an int, it's a pointer to a pointer to an int. **ramon would be an int. You're trying to print a bunch of ints with %d, but you're mostly trying to print pointers which uses the format %p.
read man printf. It is not clear whether you want to print the value pointed to by ramon or the actual value of ramon which is an address of an pointer to an int. Same for other warnings as well.
The type of the expression ramon is an int **, and the %d specifier expects an int. *ramon will be of type int *, and **ramon will be the desired int.
If you want to print the pointer itself, use the %p specifier.
ramon and paul are pointers and the printf format specifier for printing values of pointers themselves (not what they're pointing to) is %p. Try
printf("ramon = %p\n", ramon);
The warning has nothing to do with how you are initializing your pointers, it has to do with the mismatch in types between printf's %d specifier and the types you are passing to it.
If you want to print a pointer, use %p.
You declared ramon of type "pointer to pointer to type int". i.e. it holds an address to a "pointer to type int". %d on the other hand is the format specifier for int which is why you are getting the errors. Instead try the following:
printf("&paul = %p\n", ramon); //print the address that ramon points to
printf("&melissa = %p\n", *ramon); //print the address that paul points to
printf("&melissa = %p\n", paul); //same as above
printf("melissa = %d\n", **ramon); //print the contents of melissa
printf("melissa = %d\n", *paul); //same as above
printf("melissa = %d\n", melissa); //same as above
Output
&paul = 0xbf8072f4
&melissa = 0xbf8072f0
&melissa = 0xbf8072f0
melissa = 5
melissa = 5
melissa = 5
I reckon this has to do with the way I initialize my pointers
Why would you reckon that when the error message says nothing about initialization? Read it again:
"warning: format '%d' expects type 'int', but argument 2 has type 'int **'"
You have %d in the format string for your printf() call, as a placeholder for the value that you want to print. %d is used as a placeholder for values that are int s. The value you want to print is ramon. That variable has the type int**. The type int and the type int** are not the same.
If you want to print a pointer, then you should write the format string so as to expect a pointer. We format pointers with %p.
but standing at the bottom of a steep learning curve I don't know how to progress.
The way to progress is to read the error and/or warning messages and attempt to understand them. The error messages are talking about types. You should not be trying to do anything with pointers if you haven't first got your head around the concept that values have a type (i.e., what kind of thing they are).

Resources