In the following code, we pass pointer to a string and it works fine but it doesn't works for pointer to an integer. I want to know why ?
#include <stdio.h>
int main(){
char *astring = "afdv";
printf("%s",astring);
int a;
a = 1000;
int *ptr = &a;
printf("\n%d", ptr);
}
In the first printf you did NOT send a pointer. You de-referenced the pointer and hence, you are actually sending a character. Likewise if you want to print an integer, send *ptr, the dereferenced value of the integer pointer.
I'm guessing the source of your confusion to be this-
printf("%s", string_ptr);
perfectly prints the string value instead of the pointer value but
printf("%d", integer_ptr);
prints the pointer value instead of the integer value.
This is because the way printf is implemented. When it sees a %s in the format string, it considers the corresponding parameter as a pointer to a NULL-terminated string. And goes looking for the value of that string at the address contained in the pointer.
But when it sees a %d, it considers the corresponding parameter as an integer value and prints it out directly.
The change in behavior is because types like integer, floats etc are smaller and finite in size and can be passed to printf as values directly. But a string can be arbitrarily large in size. So it makes sense to pass it as a pointer and let printf go find the actual value using the pointer.
Because the language specification says so.
The %s conversion specifier expects its corresponding argument to have type char *; printf will then print out the sequence of characters starting at that address until it sees the string terminator.
The %d conversion specifier expects its corresponding argument to have type int; printf will then print out the text representation of that value as a signed decimal integer.
Check your handy C reference manual for the complete list of conversion specifiers and the types of arguments they expect. If you don't have a handy C reference manual, my preferred one has been C: A Reference Manual since the late 1980s, although the current edition only covers up to C99.
If you use %d and pass something that isn't an integer, then the behavior is undefined. The compiler isn't required to yell at you for passing an argument of the wrong type. If you run the code, anything may happen. In practice, you'll usually get garbled output. If you pass something that isn't a pointer for %s, you may get a runtime error.
Related
This is a program in which a string "6" is passed to an integer variable y
#include<stdio.h>
void main()
{
int x=0;
int y=0;
if(x==1)
y=20;
if(x==4)
y=25;
if(x==0)
y="6"+10+x+y;
printf("y= %d",y);
}
The output of this program is y= 4206638 which means here "6" is equal to 4206628. Can anyone tell me how is "6" equal to 4206628.
If i replace "6" with some other character, the output is unaffected.
y="6"+10+x+y;
With this line of code; the address of the string literal "6" is being assigned in memory to the int object i, which is in most cases undefined behavior because the value of a memory location is in many cases beyond the area an object of type int can hold.
This undefined value is then printed by:
printf("y= %d",y);
Moreover, we you would have observed the value won't be same everytime you run the code.
The only issue is that when it casts a pointer to an integer, C compilers don't regard it as an error because a pointer (address in memory) is also a number (though in most situations "address number" overflows int) and you can print it in whatever format you want: decimal, hexadecimal, and so on.
Also, the compiler must have given you a warning you doing so without an explicit cast; Something like:
warning: initialization of 'int' from 'char *' makes integer from pointer without a cast [-Wint-conversion]
Moral: We shouldn't ignore the warnings given by our smart compiler.
The problem is that you are either using a broken compiler or you are not paying attention to it.
"6" is a string literal in the form of an array placed in read-only memory. This array, like any array, "decays" into a pointer to the first element when used in an expression. So the "6"+10+x+y part is pointer arithmetic (using 1 byte characters), which in turn goes way beyond the end of that array and causes undefined behavior.
Then finally, you try to assign that strange, invalid pointer to an int. This isn't allowed by the C language, see "Pointer from integer/integer from pointer without a cast" issues.
The address will vary between different systems. You can run this well-defined code to see for yourself what's going on:
#include<stdio.h>
#include <stdio.h>
#include <stdint.h>
int main()
{
int x=0;
int y=0;
printf("%p (address of \"6\")\n", (void*)"6");
printf("+ 0x%x\n", 10+x+y);
printf("= 0x%x\n", (uintptr_t)"6"+10+x+y);
}
I get this output:
0x402004 (address of "6")
+ 0xa
= 0x40200e
So why didn't the compiler give you an error for this invalid code? The reason: What must a C compiler do when it finds an error?
If you are a beginner learning C, then I strongly recommend that you compile like this (assuming gcc/clang/icc):
gcc -std=c11 -pedantic-errors -Wall -Wextra -Werror
This will block broken C code from resulting in a confusing, incorrect program getting built.
When you define a string literal expression in C, a string is being created as an array in read only memory and a pointer is being passed back to the application. In this case, the variable stored in memory should be an ASCII number 6 followed by a null terminator (i.e. {0x36, 0x0}). However, in your program, the value used in your expression is actually the memory address for the first element of this array, so seeing a value of 4206638 makes a bit of sense.
If you were looking to use the ASCII value for number 6 (0x36) in your expression, you should use single quotes (i.e. '6'), which would pass back a signed integer 0x36, which is the ASCII representation of the number 6.
If you are looking to directly convert a string to an integer in C, you could use the standard library function atoi(), which receives a string pointer, such as the pointer returned in your application for string "6", and returns a signed integer.
I have a text file with the memory addresses of certain components of a program. For instance part of that text file looks like this:
00400000-0040b000
or
7f9ae612f000-7f9ae62ee000
I have already read the file into my program and assigned a char[] with the first address (00400000).
I also have a structure with a null pointer
struct myStruct
{
void *address;
}
And I would like the pointer *address to have the value of 0x00400000, how would I do this?
Thank you for your help.
Use sscanf() to parse the string as a hex integer and then typecast the resulting integer to a void* pointer. For example:
char str[] = "00400000";
unsigned long ul;
struct myStruct s;
sscanf(str, "%lx", &ul);
s.address = (void*) (uintptr_t) ul;
If the same instance of the program printed "00400000-0040b000" then reading a void* back via scanf("%p"... is possible. Else the result is undefined.
p specifier:
Matches an implementation-defined set of sequences, which should be the same as the set of sequences that may be produced by the %p conversion of the fprintf function. The corresponding argument shall be a pointer to a pointer to void. The input item is converted to a pointer value in an implementation-defined manner. If the input item is a value converted earlier during the same program execution, the pointer that results shall compare equal to that value; otherwise the behavior of the %p conversion is undefined. C11dr §7.21.6.2 12
struct myStruct x;
if (fscanf(stream, "%p", &x.address) == 1) Success();
Source:
First of all %x writes unsigned int. There is no guarantee that pointer size = unsigned int size.
As there is no format specifier which takes uintptr_t, you need to manualy check your pointer size in program and then select correct format specifier.
Therefore, to comply with the standard, you have to manually use the sizeof operator on void * and unsigned int and compare them. If they are equal, you can use %x as the format.
Otherwise, you need to take appropriate action, and use a different format.
Of course, if this is just a test project, it won't matter to do a dynamic check at runtime. Just hardcode it to the correct value. Be sure to leave a FIXME though, so you can come back and add dynamic checking later.
Additionally,
We discussed in the comments about the format specifiers, and you specified that %lx had correct results. Since it is guarenteed that %lx can print a value of at least uint32_t, your void * must be at least the size of uint32_t.
Additionally number 2,
Source.
If you aren't happy with the implementation-defined behaviour of %p, then use C99 <inttypes.h> and uintptr_t instead:
printf("0x%" PRIXPTR "\n", (uintptr_t)your_pointer);
Please note that the above solution requires C99 to work properly.
I've been trying to work through some C fundamentals lately to try and build a basic understanding of lower level languages.
In one of the documents I've encountered (A tutorial on pointers and arrays in C)
the author uses a void pointer in a printf statement:
int var = 2;
printf("var has the value %d and is stored at %p\n", var, (void *) &var);
And states the reason:
I cast the pointers to integers into void
pointers to make them compatible with the %p conversion specification.
However, omitting the (void *) does not result in an error or warning, either compiling and running or running through valgrind.
int var = 2;
printf("var has the value %d and is stored at %p\n", var, &var);
Is casting to void here considered a best practice or standard, or is there something more sinister afoot?
Since printf is a variadic function, its declaration only specifies the type of the first parameter (the format string). The number and types of any remaining parameters are required to match the format string, but it's up to you, the programmer, to make sure they actually match. If they don't, the behavior is undefined, but the compiler isn't obliged to warn you about it. (Some compilers, including gcc, can do some checking if the format string is a literal.)
The %p format specifier requires an argument of type void*. If you pass a pointer of a different type, you have undefined behavior. In many implementations, all pointer types have the same size and representation, and are passed the same way as function arguments -- but the language doesn't guarantee that. By explicitly converting the pointer to void*, you guarantee that it will work correctly. By omitting the cast, you have code that will probably work as you expect it to on almost all implementations.
100% correct is better than 99% correct, especially if the only cost of that extra 1% is typing a few characters.
i just read this short article http://karwin.blogspot.com/2012/11/c-pointers-explained-really.html which describes pointers really well. The author however says that the addresses are just these hex values, so he prints it with %x, but when i do this not only do i get a warning from the compiler saying i am passing a pointer instead of an unsigned int, but sometimes i get something that doesn't resemble an address at all (like 1C). Can somebody clarify the issue please?
%x expects its corresponding argument to have type unsigned int, which is why you get the warning and funky output. Use %p to display pointer values:
T *p = some_pointer_value;
...
printf( "p = %p\n", (void *) p );
%p expects its corresponding argument to have type void *. This is pretty much the only place you should explicitly cast a pointer to void * in C.
Edit
Just looked at the page. Be aware, that code sample is old (written ca. 1990) and uses K&R-style (pre-1989 standard) function definition syntax and implicit int all over the place. It's using %x to display pointer values because the %p conversion specifier wasn't added to the language until the 1989 standard.
It should not be used as a model of modern C programming practice.
His explanation of pointers is pretty decent, though.
%x is used to print a value in hex. While pointers are usually written in hex, there are other considerations for pointers that make %x a bad fit, like that 1C output you saw.
%p is meant for pointers, and is probably what you're looking for. It will format the pointer a bit better, since it knows that it's a pointer.
1C is a perfectly valid hex output, but it's odd for a pointer, since you expect certain special things to happen when displaying pointers, like having the correct length.
Since %x is meant for hex numbers, passing a pointer into it will give you a warning. One reason it gives you the warning is that pointers aren't necessarily the same size as an unsigned int.
%x expects an unsigned int, passing anything else is UB.
For printing a data-pointer, there is %p which can print void-pointers (type void*, the conversion is not optional), which will normally print it with hexadecimal notation.
If that's not satisfying you, consider casting the pointer to uintptr_t and printing that using the format-specifier-macros PRIxPTR or PRIXPTR from <inttypes.h>, for guaranteed hexadecimal output.
You even get to select the case used.
Pointers if manipulated with the intergral formats like %x or %u give undefined results. %p is recommended for pointers.
As far as the warning is concerned, %x expects an unsigned int, and your variable has probably different size or alignment requirement than unsigned int so you are getting the warning.
Values cannot be "hex". Values are just values. Meanwhile, "hex" is a way to represent values for human consumption. "Hex" is a notation.
Using %x directly on pointers is illegal though, since %x format specifier expects an unsigned int argument, not a pointer. A pointer can be cast to unsigned int type, and the result can be used with %x format specifier, but this will not work in general case since unsigned int type can easily be too narrow to properly represent the numerical address value.
In other words, forget about %x. It is hopelessly useless in that application. The author of your article is doing it very wrongly.
If you really want to print a pointer p through its conversion to integral type, the proper way to go would be this
printf("%" PRIxPTR "\n", (uintptr_t) p);
Note the use of uintptr_t type and PRIxPTR macro that stands for an implementation-defined format specifier associated with that type.
Other than that you can use a dedicated format specifier %p, which prints void * pointers and typically uses hex notation for that purpose.
I just saw the signature for printf. it is int printf(const *f). Now, if I declare an int i and do the following:
int i=5;
printf("%d",i);
it displays the correct value of i. I am wondering why is is this so. Since printf accepts a pointer, should it not treat the value of i as an address and print the value stored at that address.
Note that printf("%d", &i) does not work.
printf() is a variadic function. That means that its first argument indicates the number and type of remaining arguments to be pulled from the stack.
The first argument - and the only one that is not affected by the function being variadic - is a string and therefore a pointer (to an array of char, if it matters). The remaining arguments are processed differently and are not listed in the simplistic prototype that you mentioned.
BTW, here's the full prototype of printf() as pulled from my stdio.h header:
extern int printf (const char *format, ...);
The first argument is a format string. When you pass a string to a function, you're essentially passing a pointer.
(Also, the signature is actually int printf(const char *, ...).)
The only parameter required by printf is a format string, which must be convertible to a const char*. That doesn't mean that other parameters must be pointers. printf doesn't really know about the other parameters except by looking at the format string. It parses the format string looking for patterns that start with %. In your case it sees %d and says "there should be a int parameter on the stack", so it goes out and grabs the next parameter and interprets it as an int. If you don't provide a matching parameter or provide a parameter of the wrong type, it will print garbage.
printf(3) is a variadic function. It interprets its additional arguments from the format string.
No - printf just gets a 32bit (or whatever) value, it has no idea what type you think that it is.
The signature of printf is NOT int printf(const *f). Where did you get that strange signature?
The real signature of printf is int printf(const char *, ...) . Note the ... at the end. That ... stands for variadic arguments that you pass to printf after the first argument. The first argument is the format ("%d" in your case). The other arguments are interpreted by printf in accordance with that format. You specified %d as the format, which means that the next argument is interpreted as an int value, not as an address.
Just to add that printf("%d", &i) is indeed working.
Instead of printing the value of the i variable, it prints the memory adress where the variable is kept (& stands for adress off).