If i were to instantiate an int with a string what does the value of that int actually hold?
e.g. for the following code:
#include <stdio.h>
int main(void) {
int a = "abcd";
printf("a as string witn & = %s\n", &a);
printf("a as int witn no & = %d\n", a);
printf("a as int witn & = %d\n", &a);
}
I get values that differ with each execution such as:
a as string witn & = "?????W?
a as int witn no & = 130694946
a as int witn & = 1475726188
or
a as string witn & = "?O?Kp\?
a as int witn no & = 55557922
a as int witn & = 1550863212
what are these values? Why are they always different? And what is 'a' actually storing?
int a = "abcd";
This is illegal in C.
Well, sort of. The C standard doesn't actually use the term "illegal" for this kind of thing. To be painfully precise, it's a constraint violation, which means that any conforming compiler must issue a diagnostic message (which might be a non-fatal warning).
The expression "abcd" is an array expression, of type char[5] (4 for the letters plus 1 for the terminating \0'). In most contexts, including this one (if it were valid), an array expression is implicitly converted to a pointer to the array's first element. After that conversion, the value is of type char*, and it's a pointer to the 'a'.
There is no implicit conversion from char* to int, which is why this initialization is invalid. You could add a cast, which is an explicit conversion:
int a = (int)"abcd";
This would store in a the memory address of the string, converted from char* to int. On many systems, this conversion, though it's legal, yields garbage; for example, on the system I'm typing this on, a char* is 64 bits and an int is only 32 bits.
Compilers for older versions of the C language (prior to 1989) were more lax about implicit conversions, often allowing integers and pointers to be assigned to each other. More modern compilers, even though they'll diagnose this error if you ask them to, might (or might not) still generate code to perform the implicit conversion. (Strictly speaking the behavior is undefined, but an implicit conversion is common.)
If your compiler rejects
int a = "abcd";
it's doing its job. If it merely warns you about it, it's still doing its job as far as the C standard is concerned, but it's really not doing you any favors by generating that implicit conversion.
Bottom line: The value assigned to a is garbage, and if your compiler doesn't complain about it, find out what options you need to give it to make it do so.
As for the output of your printf calls:
printf("a as string witn & = %s\n", &a);
%s requires a char* argument that points to a string. &a is of type int*, and does not point to a string. The behavior is undefined. Most likely printf will print garbage bytes starting at the beginning of a until it happens to encounter a null byte (or crashes).
Don't do that.
printf("a as int witn no & = %d\n", a);
If your program hasn't already crashed at this point, this prints the value of a. That value is garbage, which might typically be the converted value of the address of the string literal, or just the low-order 32 bits of that address.
printf("a as int witn & = %d\n", &a);
%d requires an argument of type int. &a is of type int*. Undefined behavior. This might print the memory address of a as a decimal integer. Don't do that. If you really want to print the address of a, the correct way to do it is:
printf("&a = %p\n", (void*)&a);
Perhaps the most efficient way to answer the question is to stroll through the question code:
#include <stdio.h>
int main(void) {
int a = "abcd";
The above line declares an int called a, and initializes a with the address of the string "abcd". This line will cause a compiler to become a little grumpy, in that it will complain something like: warning: initialization makes integer from pointer without a cast.
printf("a as string witn & = %s\n", &a);
The object of the above line seems to b to print a string. Unfortunately, &a is the memory address of where the variable is stored in memory, which appears it was something like 1550863212 or 0x93E6DF1 on your system. This value is not an ASCII or UTF-8 string; hence it appears to print out garbage: "?????W?, "?O?Kp\?, or some other nonsense string, depending on what the address of a happens to be. Of course, this line will make the compiler even more grumpy; format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int *’
printf("a as int witn no & = %d\n", a);
The above line attempts to print the value of a as a signed integer. It will also appear as nonsense, Since the value of a is the address of the string "abcd". Hence, the value of a (as a signed integer) will be the signed integer representation of the address where the string "abcd" is stored in memory.
printf("a as int witn & = %d\n", &a);
The above line attempts to print the memory address of a as a signed integer. As with the others, this will most likely appear as nonsense again.
printf("a as a string[%s]\n", a);
For your viewing pleasure, I added the above line, which outputs: "a as a string[abcd]". This proves that the variable a was successfully initialized, although (again) the compiler thinks us insane: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
}
Related
I am currently doing pointers. I have been programming for a long time, but not in C/C++. With that being said, my pointer knowledge is abysmal.
Currently, I am following a guide on YouTube and he prints the code below.
int main() {
int a = 5;
int *p;
p = &a;
printf("%d\n", p);
}
This prints successfully for him, and he sees a memory location. For me, I see the error
warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *'
From this, I expect I need to put an & in front of the p to make it print the value. But then I receive this error,
int main() {
int a = 5;
int *p;
p = &a;
printf("%d\n", &p);
}
'int', but argument 2 has type 'int **'
Where is the hole in my knowledge? Any key tips or strategies when working with this, I don't know why I find this so abstract.
Thanks,
I was expecting the value to print as expected, but instead am greeted with the error.
%d is the wrong format specifier for pointers. That may work on a more lenient or noncompliant implementation, but you should use %p to print pointer values.
Warnings are not errors. You're receiving a warning, which is not stopping your program from working, because the print specifier %d (ie printf("%d")) is for displaying integers, and you're giving it a non-integer argument of type int*.
The problem here is not with the argument, it's with the print specifier. Your attempt at a fix just changes the int* to an int**, which still does not match the format specifier %d. Use %p instead, which is the specifier for pointers, and will fix the warning, and print the address in hexadecimal notation.
You could also suppress the warning with a series of explicit casts from int* to int, but integer representations of memory addresses are generally much less used than hexadecimal representations in the first place.
Note that using wrong format specifier in printf() lead to undefined behaviour1).
The correct format specifier to print a pointer is %p format specifier.
Remember, format specifier %p expect that the argument shall be a pointer to void, so you should type cast pointer argument to void *. The correct statement to print pointer p would be:
printf("%p\n", (void *)p);
C11#7.21.6.1p9 [emphasis added]
9 If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
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.
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.
I'm trying to learn how to use the pointer in a C program; my example is as follows:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int * tab = (int*)malloc(sizeof(int)*5);
int a = 10;
int *p;
p = &a;
printf("the address of a is %d \n",&a);
printf("the address of a using the pointer is %p \n",p);
printf("the address of tab is %d \n",tab);
}
I'm trying to print the address of a, the address value inside of p and where the first byte of the tab begins.
I can get hexadecimal values when using "%p", but I'm willing the decimal value of the addresses.
Edit : On this Video image, someone has used "%d" to print a decimal value for a pointer address, and it has confused me.
To print a decimal version of an object pointer, 1st convert the pointer to an integer. Best to use the optional type uintptr_t.
The following type (uintptr_t) designates an unsigned integer type with the property that any valid pointer to void can be converted to this type (uintptr_t) ... C11dr §7.20.1.4 1
#include <inttypes.h>
uintptr_t d = (uintptr_t)(void *) &a;
Then print it.
Some info on PRIuPTR
printf("%" PRIuPTR "\n", d);
For pre-C99 code, consider a direct cast to unsigned long. #Barmar
OP later commented
"... i will try to manipulate the tab variable , and i will test if every cell in the tab is 4 byte , so may be i will do tab+8 bytes to get the value of a specific cell , here it's a simple example , with decimal it will be easy for me ."
This is a questionable approach as the decimalization of a pointer may not provide the continuous numeric model expected. This post this may be good for learning, but with OP providing more details in another post, even better ideas could be given for the higher level problem.
First, be aware that addresses are often "number-like" but might not be (e.g. remember the segment+offset notion of far addresses on 1980-era 16 bits x86 PCs).
Then, the integral type the most similar to pointers is intptr_t (signed) or uintptr_t (unsigned) - both from <stdint.h>.
You might cast that to a long long (hoping that they are not smaller than pointers), e.g.
printf("address of a in decimal is %lld\n", (long long) (intptr_t) (&a));
But really, why do you want to show an address in such a fashion? I see no need for it (e.g. debuggers or linkers are generally showing addresses in hexa, which is probably what %p does).
Notice that the C11 standard (see n1570, §7.21.6.2, p315) does not say much about %p for printing pointer:
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.
I'm understanding the above in a way where printing Hello ⭔ for any pointer would be an acceptable and standard conforming behavior. In practice, implementations print pointers in a way similar to what linkers and debuggers do, and don't behave in a silly way (but I understand they could).
At last, the actual concrete "numerical" value of a pointer is not really important and can vary greatly from one execution to the next (e.g. because of ASLR).
For printing an "address" (actually a pointer) "%p" is the most common method (note the necessary cast to void*). If you need the address in decimal instead of hexadecimal, you can convert the pointer into an integral value; this is well defined in C (cf. this online C standard draft):
6.3.2.3 Pointers
(6) Any pointer type may be converted to an integer type. Except as
previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type, the behavior is
undefined. The result need not be in the range of values of any
integer type.
So the code could look as follows:
int main(int argc, char *argv[]) {
int a =10;
int *p = &a;
p = &a;
unsigned long long addrAsInt = (unsigned long long)p;
printf("the adress of a is %llu \n",addrAsInt);
printf("the adress of a using the pointer is %p \n",(void*)p);
}
If you want to see the pointer as a decimal integer, cast it to unsigned long and print it with %lu format. While this isn't guaranteed by the standard, it should work in most implementations.
printf("the address of a is %lu\n", (unsigned long)&a);
I'm a beginner in C, today I'm studying the pointer part, I found that I can print an address directly, when using the right type escaper, I can even print the intended value stored in that memory address.
Later, I did some experiments:
##### CODE PART ######
#include <stdio.h> // Define several variable types, macros, and functions about standard input/output.
int main () {
char my_string[] = "address test";
printf("%s\n", &my_string);
printf("%p\n", &my_string);
printf("%d\n", &my_string);
printf("%x\n", &my_string);
printf("\n");
char *p = "pointer string test";
printf("%s\n", p);
printf("%p\n", p);
printf("%d\n", p);
printf("\n");
char *p2 = 'p';
printf("%c\n", p2);
printf("%p\n", p2);
printf("%d\n", p2);
return 0;
}
##### OUTPUT #####
address test
0x7fff58778a7b
1484229243
58778a7b
pointer string test
0x107487f87
122191751
p
0x70
112
I'm not quite understand the behavior of %d format output at first, But after more observations and experiments. I found that %d is converting part of the hex value of the memory address.
But for address of my_string it omitted the 0x7fff part, for address of p it omitted 0x10 part, for p2 it omitted the 0x part. In my cognition, 0x is the head sign of a hex value.
But how should I know how much digits will be omitted by C when converting a memory address to int, as it does in the sample of my_string and p?
PS: My system version is OSX10.10
The C standard (ISO/IEC 9899:2011) has this to say about converting between pointers and integers:
6.3 Conversions
6.3.2.3 Pointers
¶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.67)
¶6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.
67) The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to
be consistent with the addressing structure of the execution environment.
Note that the behaviour of converting between pointers and integers is implementation defined, not undefined. However, unless the integer type used is uintptr_t or intptr_t (from <stdint.h> — or <inttypes.h>), you are likely to see truncation effects if the sizes of the pointer and the integer types do not match. If you move your code between 32-bit and 64-bit systems, you will run into problems somewhere.
In your code, you have 64-bit pointers (because you're on Mac OS X 10.10 and you need to specify explicitly -m32 to get a 32-bit build, but your results are consistent with a 64-bit build anyway). When you pass those pointers to printf() with the %d and %x conversion specifications, you are requesting printf() to print a 32-bit quantity, so it formats 32 of the 64 bits you passed. The behaviour is ill-defined; you aren't getting a conversion, per se, but the calling code (in main()) pushes a 64-bit pointer onto the stack and the called code (printf()) reads a 32-bit quantity off the stack. If you requested that a single call to printf() should print several values (e.g. printf("%d %x\n", p, p);), you'd get more surprising results.
You should compile with options like:
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror …
With those options, your code would not compile; the compiler would complain about mismatches between the format strings and the values passed. When I saved your code into a file noise.c and compiled it with clang (from XCode 7.2, running on Mac OS X 10.10.5), I got:
$ /usr/bin/clang -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror noise.c -o noise
noise.c:5:20: error: format specifies type 'char *' but the argument has type 'char (*)[13]'
[-Werror,-Wformat]
printf("%s\n", &my_string);
~~ ^~~~~~~~~~
noise.c:7:20: error: format specifies type 'int' but the argument has type 'char (*)[13]' [-Werror,-Wformat]
printf("%d\n", &my_string);
~~ ^~~~~~~~~~
noise.c:8:20: error: format specifies type 'unsigned int' but the argument has type 'char (*)[13]'
[-Werror,-Wformat]
printf("%x\n", &my_string);
~~ ^~~~~~~~~~
noise.c:14:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%d\n", p);
~~ ^
%s
noise.c:17:11: error: incompatible integer to pointer conversion initializing 'char *' with an expression of
type 'int' [-Werror,-Wint-conversion]
char *p2 = 'p';
^ ~~~
noise.c:18:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%c\n", p2);
~~ ^~
%s
noise.c:20:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%d\n", p2);
~~ ^~
%s
7 errors generated.
$
Compile with stringent warnings, and pay heed to those warnings.
There is no such thing like "hex value". A number is an amount. Decimal and hex are just representations of the number using different conventions. One can, as well, represent the number using roman numerals and its value still remains the same.
The address of a variable is a concept, not a physical thing. It usually happens to be a (large) number on the current OSes and CPU architectures but this is not set in stone.
Depending on the compiler and the code it compiles, a variable can be stored in memory (it has an address that looks like a large integral number) or not. The compiler can optimize the code and store a temporary variable in a CPU register; in this case it doesn't have an address.
Back to your code. &my_string is the address of variable my_string. It looks like a number. You probably run the code on a 64-bit processor. Memory addresses in this situation are 64-bit unsigned numbers.
printf("%p\n", &my_string); - prints a 64-bit unsigned number (the most appropriate representation of a pointer on the hardware architecture you are using).
printf("%d\n", &my_string); - you pass a 64-bit number to printf() but because of the %d specifier it thinks the value is 32-bit. It grabs only half of the passed value (4 out of the 8 bytes) and represents it as a signed integer. But which half? It depends on the architecture where the code runs. The behaviour of this code is undefined.
printf("%x\n", &my_string); - similar with %d, it prints only (the same) half of the passed value using the hexadecimal notation. The behaviour of this code is, again, undefined.
The 0x prefix is not part of the hex representation; it is just a marker that signals to the C compiler that a number in the hexadecimal representation follows. While the hex representation is universal, different languages use different ways to encode them. Even the C language uses two different markers for them; 0x is used to prefix the numbers and \x is used to prefix the hex representation of a character.
There's no rule. This is not covered by the C standard. Your code causes undefined behaviour. Any results you observe for this entire program are meaningless.
With printf you must convert the arguments to the right type yourself.
printf("%d\n", &my_string);
printf("%x\n", &my_string);
is cause for undefined behavior. The format specifier and the argument type must match for printf to work correctly. For a list of valid format specifiers and data types to which they apply, take a look at http://en.cppreference.com/w/c/io/fprintf.
The following lines suffer from the same problem.
printf("%d\n", p);
printf("%c\n", p2);
printf("%d\n", p2);
The line
char *p2 = 'p';
assigns the integer value that represents the character 'p' to p2. However, that is not a valid address.
The integral types that can be used to hold a pointer are intptr_t and uintptr_t. Hence, you can use:
char my_string[] = "address test";
intptr_t ptr = &my_string;
However, you cannot use %d format specifier to print that value. You will need to use:
printf("%" SCNdPTR "\n", ptr);
to print that.
Take a look at http://en.cppreference.com/w/c/types/integer for more details.