String constant and Character constant - c

int main(){
printf("the value is %d \n " ,'x'+ "x");
return 0;
}
Output
4196024
But the former one ('x') is an integer and latter one ("x")is a string .
Can I know how ? Or is it giving me a garbage value.

Literal strings have type char [N] where N is just large enough for all characters in the literal plus the terminating '\0' (namely "x" has type char[2]).
In the context of the expression 'x' + "X", the array gets converted to a pointer to its first element, then that address is added with the int value 'x'. The resulting address is passed on to printf() with an invalid conversion specification.
You have invoked Undefined Behaviour!
Try this
printf("the valus is %p\n", (void*)('x' + "x"));
Also note that the address 'x' + "x" is not part of any object in your program. Merely evaluating it is already Undefined Behaviour.

Basically,
printf("the value is %d \n " ,'x'+ "x");
invokes undefined behaviour. What you need is %p format specifier here.
Otherwise, in general,
"string" gives you the base address of the string literal
'p' gives you the ASCII value of the char representation.
So, what essentially is being done here is to print the address of the member in 'x'th element of the string "x" (which does not make much sense, practically).
For better understanding, you can re-write the print statement as
printf("the pointer is %p\n", (void *) ("x"+ 'x'));
which is equivalent to
printf("the pointer is %p\n", (void *) &("x"['x']));
Note that you don't need spaces before or after the newline in the print format.

What you are asking for in the formatted string is an integer so it is printing the integer value of the character 'x' added to the base address of the string literal "x".
'x' is 120 so if you use a memory viewer to peek at the outputted value minus 120 bytes, you will probably find an 'x' followed by a '\0' (= 0).

Related

Output of the following

Code snippet
int main(){
printf(5 + "GeeksQuiz");
return 0;
}
Output is Quiz
Can you tell me how this output is coming.
Whats the logic behind it.
Addition is commutative. a + b is equal to b + a.
Adding an integer to a pointer increments follows pointer arithmetic. Adding an integer to a pointer increments it by so many elements as the integer count. So (int*)a + b is equal to (int*)((uintptr_t)a + b * sizeof(int))
sizeof(char) is always equal to 1.
"GeeksQuiz" is a string literal. strlen("GeeksQuiz") is equal 9. Accounting for the string terminating null byte, the type of the literal is char[10]. It's an array of 10 characters with the content {'G','e','e','k','s','Q','u','i','z','\0'}.
The C rules say, that an array of type is converted into a pointer to the first element of that array in most contexts. That happens here: (char[])"GeeksQuiz" is converted into a char* pointer to the first character 'G' in the string.
5 + "GeeksQuiz": "GeeksQuiz" is converted to the pointer to the first character. Then that pointer is incremented by 5. So the result of 5 + "GeeksQuiz" will be char* pointer that will point to the character 'Q' inside the string literal.
printf prints the null terminated string passed to it as the first character, except for conversions that start with %, which does not apply here.
To the printf function is passed the address of a pointer that points to the letter 'Q' inside the "GeeksQuiz" string literal.
printf increments the pointer until it will find the string terminating null byte. So it will print {'Q','u','i','z'}, as after z character it will find the null byte.

Simple single char array encryption needs an artificially long array to work?

Running a simple encryption on a single char array. It doesn't seem to work when the array size is less than or equal to 1, even though only a single char is changing.
The below works because yesCrypto[10] is set to 10 (or > 1).
char noCrypto[] = "H"; //sets an array to hold unencrypted H
char yesCrypto[10]; //sets array to hold encrypted H
yesCrypto[0]=noCrypto[0]+1;
//takes 'H' from noCrypto and turns it into an 'I' and moves it into yesCrypto.
printf("Encrypted string is '%s'\n", yesCrypto);
//prints Encrypted version of 'H', 'I'
The below does not work because yesCrypto[0] is set to 0, also does not work when set to 1.
char noCrypto[] = "H"; //sets an array to hold unencrypted H
char yesCrypto[1]; //sets array to hold encrypted H
yesCrypto[0]=noCrypto[0]+1;
//takes 'H' from noCrypto and turns it into an 'I' and moves it into yesCrypto.
printf("Encrypted string is '%s'\n", yesCrypto);
//prints 'IH'
Side question: why is it printing IH when it is not working probably.
Code is attempting to print a character array that is not a string using "%s".
yesCrypto[] is not certainly null character terminated.
char yesCrypto[10];
yesCrypto[0] = noCrypto[0]+1;
printf("Encrypted string is '%s'\n", yesCrypto); // bad
Instead, limit printing or append a null character.
// 1 is the maximum number of characters to print
printf("Encrypted string is '%.*s'\n", 1, yesCrypto);
// or
yesCrypto[1] = '\0';
printf("Encrypted string is '%s'\n", yesCrypto);
OP's 2nd code is just bad as object arrays of length 0 lack defined behavior.
// bad
char yesCrypto[0];
OP's edited post uses char yesCrypto[1];. In that case use
yesCrypto[0] = noCrypto[0]+1;
printf("Encrypted string is '%.*s'\n", 1, yesCrypto);
// or
printf("Encrypted character is '%c'\n", yesCrypto[0]);
Fundamentally, printing encrypted data as a string is a problem as the encrypted character array may contain a null character in numerous places and a string requires a null character and ends with the first one.
In the first case, you're supplying an array (as an argument to %s) which is not null-terminated.
Quoting C11, chapter §7.21.6.1,
s
If no l length modifier is present, the argument shall be a pointer to the initial
element of an array of character type.280) Characters from the array are
written up to (but not including) the terminating null character. If the
precision is specified, no more than that many bytes are written. If the
precision is not specified or is greater than the size of the array, the array shall
contain a null character.
In this case, yesCrypto being an automatic local array and left uninitialized, the contents are indeterminate, so there's no guarantee of a null being present in the array. So the usage causes undefined behavior.
What you're seeing in the second case is undefined behavior, too.
Quoting C11, chapter §6.7.6.2
In addition to optional type qualifiers and the keyword static, the [ and ] may delimit
an expression or *. If they delimit an expression (which specifies the size of an array), the
expression shall have an integer type. If the expression is a constant expression, it shall
have a value greater than zero. [...]
So, the later code (containing char yesCrypto[0];) has Constraints violations, it invokes UB.
A note on why this might not produce a compilation error:
gcc does have an extension which supports zer-length arrays, but the use case is very specific and since C99, the "flexible array member" is a standadized choice over this extension.
Finally, for
...also does not work when set to 1....
will lack the space for a null-terminator, raising the same issue as in the very first case. To put it in simple words, to make a char array behave like a string containing n elements, you need
size of the array to be n+1
index n to contain a null character ('\0').

What will be the output of the following C program

#include<stdio.h>
int main()
{
char *p;
p="%d\n";
p++;
p++;
printf(p-2, 400);
return 0;
}
When I am running above code, I am getting output 400. But why 400?
The p is assigned the formatting string first. Then it's decrement by 1 two times. Finally its value minus two is passed to the printf with additional parameter 400.
Subtracting 2 from latest value of p moves it back to the original formatting string. And therefore printf prints value 400.
printf()'s first parameter is a format string. The variable p is a pointer to a character array which is also how strings are represented.
When p is assigned a string "%d\n" it says format an integer to print its value and then print the carriage return character.
Since p is a char pointer p++ means move the pointer forward 1 character. This is done twice to move p forward 2 characters so it points to the beginning of the carriage return character. p-2 says do pointer math to give a char* 2 characters in front of where p points.
This is the beginning of the %d carriage return string. This becomes the format string and the second parameter 400 replaces the %d and prints itself followed by the carriage return.
You declared a pointer to a string and assigned it the value "%d\n". This pointer holds an address in memory.
For example, lets say it points to address 6 when you add two to it (which you shouldn't do you you always have to know where your pointers are pointing) you change the address to 8.
Now when you do printf you're replacing it with the current value of the address p points to (8) minus 2 which is 6.

Pointer and character array

Hello Everyone I just want to clarify a doubt regarding pointers.So that I can know whether I understood it correctly or not.
void main ()
{
char c[10]="COMPUTERS";
printf("The first is %d\n",c); //1
printf("The second is %f\n",c); //2
printf("The third is %u\n",c); //3
printf("The fourth is %s\n",c); //4
printf("The fifth is %c\n",c); //5
}
The first printf will print the address of first location of character array 'c',
Similarly second printf will also try to print the address in float form.
The third printf will print the address again.
While the fourth printf will print the character array.
My doubt is associated with the 5th printf. It is printing random values or sometimes no values is it because the value of 'c' is memory address of first character of array 'c' and I am trying to print that value as a character?
all of those prints are undefined behavior except the %s one. the weird behavior you are seeing with %c format specifier is due to underlying casts on the adress of the pointer which can change from running it one time to the next.
if you want to print out the adress the pointer points to use %p like this:
printf("address: %p\n", (void *)c);
(These are not "doubts", they are questions or uncertainties perhaps).
All of those except %s are undefined behavior, since they all mis-match the actual type of the value provided (char *) with the formatting specifier.
printf("The fifth is %c\n",c[0]);
This makes sense. Printing the first character of the array.
Trying to print the address just as a character makes no sense.
Only this printf() is good
printf("The fourth is %s\n",c);
The rest of the printf()'s have undefined behavior.
The first printf will print the address of first location of character array 'c',
Strictly speaking, the first printf will invoke undefined behavior since you are using the wrong format specifier to print a pointer. But yeah it will probably print the address on most systems.
Similarly second printf will also try to print the address in float form.
No it will just give you some binary goo. You never convert the address to a float format, you only attempt to print it as if it was. This is completely undefined behavior.
The third printf will print the address again.
Same as 1. Undefined behavior, but yeah, it will probably print the address...
While the fourth printf will print the character array.
Yes.
My doubt is associated with the 5th printf. It is printing random values or sometimes no values is it because the value of 'c' is memory address of first character of array 'c' and I am trying to print that value as a character?
Again, undefined behavior. It can print anything.
Theoretical analysis:
printf("The first is %d\n",c); // undefined behavior by the standard
printf("The second is %f\n",c); // undefined behavior by the standard
printf("The third is %u\n",c); // undefined behavior by the standard
printf("The fifth is %c\n",c); // undefined behavior by the standard
Practical analysis:
printf("The first is %d\n",c); // requires sizeof(void*) == sizeof(int)
printf("The second is %f\n",c); // requires sizeof(void*) == sizeof(double)
printf("The third is %u\n",c); // requires sizeof(void*) == sizeof(unsigned int)
printf("The fifth is %c\n",c); // different between big-endian and little-endian
Detailed practical analysis:
sizeof(void*) < sizeof(...) will potentially yield a memory access violation during runtime
sizeof(void*) > sizeof(...) will yield different printout between big-endian and little-endian

String #define returns a random integer

As far as I know #define is just a string replacement and it's not a variable, so it doesn't have any memory address or something.
Suppose this code:
#include <stdio.h>
#define ONE "a"
main() {
printf("the number is: %d\n", ONE);
}
Then when I compile and run this program, I get a random string each time:
the number is: 8179551
the number is: 21127007
the number is: 57114463
...
If the #define doesn't have any memory address, then what's this value and why it's changed every time?
In your code
printf("the number is: %d\n", ONE);
is equivalent to
printf("the number is: %d\n", "a");
In fact you are printing the address of the string "a" as a decimal.
And you are getting random value in each execution that's because the address of "a" is got random address in each execution
The string "a" is a literal string and it's stored in the read only memory. The printf is printing the address of this memory
MOHAMED is right, you printing the adress of a string
what you what to do this
#define ONE 'a'
everything between two ''s are characters, only one character is allowed
This program invokes undefined behavior because the format specification doesn't match the type of argument (int versus char *).
C99, 7.19.6.1 # 9 (fprintf)
If a conversion specification is invalid, the behavior is
undefined.239) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
The correct way to print an address is with %p and via a (void *) argument:
printf("the address is: %p\n", (void *)ONE);

Resources