This question already has answers here:
Pointer Arithmetic [closed]
(7 answers)
Closed 5 years ago.
#include<stdio.h>
void main()
{
char *str="CQUESTIONBANK";
clrscr();
printf(str+9);
getch();
}
The output is BANK. what the printf statement does. Can anyone please explain that?
A string in C is defined as a sequence of char terminated by a '\0'. A string isn't a type in C. So, functions handling strings accept a pointer to the beginning of the string (a pointer to char).
You can do arithmetics on pointers. + x means increase the pointer by x elements pointed to. So, str+9 in your example points to the character B. This pointer is passed as the start of the string to printf().
str gives the base address of the pointer to the string.
So normally if you just use printf(str) it should output CQUESTIONBANK.
But in this case you are printing str+9, ie. printf(str+9), so in this case it refers to string starting from the 9th index. In this case the 9th index is B,(C follows 0 indexing), so the string printed is BANK.
printf will always print the string from the passed pointer as starting position till the end of the string, which is stored as '\0' known as Null Character. If you try printf(str[13]), it should print '\0'
#include<stdio.h>
void main()
{
char *str="CQUESTIONBANK";
/* clrscr() function will clear the console.*/
clrscr();
/* printf() function, outputs the data. The name of the string, in your case
it is 'str' always points first element of the string which is 'C'. Adding 9 will
'str' point to 'B' character in the string. That's why printf is printing from B on wards.
Similarly adding 10 to 'str' will print from 'A' and so on.*/
printf(str+9);
/* getch() function waits for you to enter any character.*/
getch();
}
str points to a location (address). You can move in any direction over these addresses using + and -. So, if str points to some address, say 0x1002, then str+1 points to 0x1003 and str-1 points to 0x1001. (assuming str is char*. With other pointer types you move in bigger steps - sizeof(*str))
In your example - str points to an address that holds CQUESTIONBANK so if you move the pointer 9 steps forward, you move past C,Q,U,E,S,T,I,O,N and you now point to BANK. Now using printf will print from that location resulting in BANK
Related
#include<stdio.h>
int main()
{
char *s = "Abc";
while(*s)
printf("%c", *s++);
return 0;
}
I have seen this (on a site) as a correct code but I feel this is undefined behavior.
My reasoning:
Here s stores the address of the string literal Abc. So while traversing through the while loop :
Iteration - 1:
Here *(s++) increments the address stored in s by 1 and returns the non-incremented address (i.e the previous/original value of s). So, no problem everything works fine and Abc is printed.
Iteration - 2:
Now s points to a completely different address (which may be either valid or not). Now when trying to perform while(*s) isn't it undefined behavior ?
Any help would be really appreciated!
No. There's no undefined behaviour here.
*s++ is evaluated as *(s++) due to higher precedence of postfix increment operator than the dereference operator. So the loop simply iterates over the string and prints the bytes and stop when it sees the null byte.
Now s points to a completely different address (which may be either valid or not). Now when trying to perform while(*s) isn't it undefined behavior ?
No. In the first iteration s points to the address at the char A and at b in the next and at c in the next. And the loop terminates when s reaches the null byte at end of the string (i.e. *s is 0).
Basically, there's no modification of the string literal. The loop is functionally equivalent to:
while(*s) {
printf("%c", *s);
s++;
}
Iteration - 1:
Here *(s++) increments the address stored in s by 1 and returns the non-incremented address (i.e the previous/original value of s). So, no problem everything works fine and Abc is printed.
No, “Abc” is not printed. %c tells printf to expect a character value and print that. It prints a single character, not a string. Initially, s points to the first character of "Abc". s++ increments it to point to the next character.
Iteration - 2:
Now s points to a completely different address (which may be either valid or not). Now when trying to perform while(*s) isn't it undefined behavior ?
In iteration 2, s is pointing to “b”.
You may have been thinking of some char **p for which *p had been set to a pointer to "abc". In that case, incrementing p would change it to point to a different pointer (or to uncontrolled memory), and there would be a problem. That is not the case; for char *s, s points to a single character, and incrementing it adjusts it to point to the next character.
Now s points to a completely different address
Indeed, it is a completely different but well defined address. s referenced the next char of the string literal. So it just adds 1 to the pointer.
Because string literal is nul (zero) terminated the while loop will stop when s will reference it.
There is no UB.
This question already has answers here:
How is printf statement interpreted?
(5 answers)
Closed 5 years ago.
#include<stdio.h>
void main()
{
printf(5+"good morning");/*need explanation for this line
return 0;
}
The output of the program is - morning
can anyone explain how?
Prototype of printf
int printf(const char *format, ...);
Here format is a type of const char* and point to address of first element of string literal. When you pass 5+"Good morning" in printf, what you are really passing is the memory address of the string plus 5. The plus 5 means printing will start 5 chars beyond the start of the string, and the space after the word "Good",counts as a char.
when you call with 5+"good morning" parameter is converted to pointer. That means there is string constant "good morning" stored somewhere in the executable and compiler pass its pointer. something like this:
const char txt[]="good morning\0";
printf(5+txt);
So the printf will obtain the evaluated pointer txt+5 which bypassed first 5 characters in the string (as one char is single BYTE and single memory address on 8bit WORD addressing machines).
The output of the program is - morning
printf(5+"good morning");
prints the string inside the " ", overpassing the first five characters. So the first four characters g, o, o, d and the fifth character, the space, will be overpassed and the rest of the string will be printed.
Printf() method, is used to print the text in ()
It prints only "morning" and 5+ bypassed the initial 5 characters that is "g" "o" "o" "d" and a " " (space)
#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.
What actually happens when I do this?
{
char * str = "%d\n";
str++;
str++;
printf(str-2,300);
return 0;
}
Intuitively, it appears that the number on the screen will be 300, but I want to know, what gets stored in str.
Edit: It will be great if someone can tell me, when do we actually do this?
Thanks!
str is a memory address, initially the address of the % sign of the string literal %d\n. This literal is created because it is in your code.
Two increments make str point to the character \n and when this is the case, str - 2 is the address of the % sign. So printf sees the format string %d\n, and as usual it prints the first argument after the format string as an integer. The fact is, printf does not care about the origins of the format string. It doesn't matter if you can create it on-the-fly, or hard code it.
We don't do this generally. Sometimes you need to fiddle with a character pointer to scan a string, extract something out of a string, or to skip some prefix of a string.
str is a pointer on the stack. It initially points to (ie, holds the address of) the start of the string literal "%d\n" (this is probably stored in a read-only section of your program by the compiler).
Let's say for example the string literal (the "$d\n") is stored at 0x5000. So (assuming UTF-8 or ASCII) the byte at 0x5000 is %, the byte at 0x5001 is d, 0x5002 is \n (the newline) and at 0x5003 it is \0 (the terminating null character)
str is initially holding the address 0x5000. str++ would increase it to 0x5001, meaning it now points to the string "d\n", ie one character into the string literal "%d\n". Likewise, str++ again moves it to 0x5002, ie the string "\n", two characters into the string literal "%d\n". Note that all of these are still terminated by the null character at 0x5003 (how C knows when the string ends).
The printf call has the format string as the first argument. str at this point holds 0x5002, so the call is saying 'Use the format string starting at 0x5002 - 2 = 0x5000', which turns out to be the same string that we started with.
Thus it will be the same as calling
printf("%d\n",300)
and will print out 300.
Well you are declaring a char pointer. This pointer will hold a RAM address from where you will write the following bytes: % (1 byte) d (1 byte) \n (1byte on UNIX, 2 bytes on windows) and \0 the null terminating byte that ends your string.
Then you increment by two your pointer value (which is the address of the first byte) then decrement by two. So basically you do nothing. Thus when calling printf() src-2 will point to %d\n and the null terminating byte will make it exactly pass %d\n.
So at the end of the day what you are doing is:
printf("%d\n", 300); Hence the 300 output.
#include <stdio.h>
#define slice(bare_string,start_index) #bare_string+start_index
#define arcane_slice(bare_string,start_index) "ARCANE" #bare_string+start_index
int main(){
printf("slice(FIRSTA,0)==> `%s`\n",slice(FIRSTA,0));
printf("slice(SECOND,2)==> `%s`\n",slice(SECOND,2));
printf("slice(THIRDA,5)==> `%s`\n",slice(THIRDA,5));
printf("slice(FOURTH,6)==> `%s`\n",slice(FOURTH,6));
printf("slice(FIFTHA,7)==> `%s`\n",slice(FIFTHA,7));
printf("arcane_slice(FIRSTA,0)==> `%s`\n",arcane_slice(FIRST,0));
printf("arcane_slice(SECOND,2)==> `%s`\n",arcane_slice(SECOND,2));
printf("arcane_slice(THIRDA,5)==> `%s`\n",arcane_slice(THIRDA,5));
printf("arcane_slice(FOURTH,6)==> `%s`\n",arcane_slice(FOURTH,6));
printf("arcane_slice(FIFTHA,7)==> `%s`\n",arcane_slice(FIFTHA,7));
return 0;
}
OUTPUT:
slice(FIRSTA,0)==> `FIRSTA`
slice(SECOND,2)==> `COND`
slice(THIRDA,5)==> `A`
slice(FOURTH,6)==> ``
slice(FIFTHA,7)==> `slice(FIFTHA,7)==> `%s`
`
arcane_slice(FIRSTA,0)==> `ARCANEFIRST`
arcane_slice(SECOND,2)==> `CANESECOND`
arcane_slice(THIRDA,5)==> `ETHIRDA`
arcane_slice(FOURTH,6)==> `FOURTH`
arcane_slice(FIFTHA,7)==> `IFTHA`
I have the above C code that I need help on. I am getting weird behaviour from
the function-like macro slice that is supposed to 'slice' from a passed index
to the end of the string. It does not slice in the real sense but passes
a pointer from a certain point to printf which starts printing from that
address. I have managed to figure out that in arcane_slice the strings
are concatenated first then 'sliced'. I also have figured out that when start_index
is equal to 6 printf starts printing from the null byte and that is why
you get the 'empty' string. The strange part is when start_index is 7. It prints
the first argument to printf(interpolator string) concatendated with the passed bare string in both.
arcane_slice and slice(as shown in the 5th and 10th lines in the output)
Why is that so?
My wildest guess is that when the start_index exceeds the length of the strings,
the pointer points to the start of the data segment in the program's address space. But
then you could counter that with "why didn't it start printing from FIRSTA"
Not any "data segment", the stack. This is what I remember: when C calls a function it first puts data on stack, first variable arguments, then the format, all being the addresses to the memory sequentially allocated with your text. In that block of memory, the last argument (c-string) goes first, and the first goes last, thus:
Memory:
"FIFTHA\0slice(FIFTHA,7)==> `%s`\n\0"
Arguments:
<pointer-to-"FIFTHA"> <pointer-to-"slice...">
Since you overincrement the first one it skips the '\0' character and points at the format as well.
Try to experiment with this with more placeholders, like
printf("1: %s, 2: %s\n", slice(FIFTHA,7), slice(FIFTHA,6));
slice(bare_string,start_index) #bare_string+start_index
you are passing a string and bare_string stores the starting address of string which you have passed and then you returning changed pointer location which is bare_string+start_index
char str[6]="Hello";
char *ptr =str;
printf("%s\n",str);//prints hello
printf("%s\n",str+1);//prints ello
printf("%s\n",str+2);//prints llo
printf("%s\n",str+3);//prints lo
printf("%s\n",str+4);//prints o
printf("%s %c=%d \n",str+5,*(str+5),*(str+5));//prints Null
printf("%s %c=%d \n",str+6,*(str+6),*(str+6));//prints Null or may be Undefined behavior
printf("%s %c=%d \n",str+7,*(str+7),*(str+7));//prints Null or may be Undefined behaviour
the same scenario is happing in your case.
Test Code:
#include<stdio.h>
main()
{
char str[6]="Hello";
char *ptr =str;
printf("%s\n",str);//prints hello
printf("%s\n",str+1);//prints ello
printf("%s\n",str+2);//prints llo
printf("%s\n",str+3);//prints lo
printf("%s\n",str+4);//prints o
printf("%s %c=%d \n",str+5,*(str+5),*(str+5));//prints Null
printf("%s %c=%d \n",str+6,*(str+6),*(str+6));//prints Null or may be Undefined behavior
printf("%s %c=%d \n",str+7,*(str+7),*(str+7));//prints Null or may be Undefined behaviour
}
You have answered your question yourself. "FIFTHA"+7 gives you a pointer outside the string object, which is undefined behavior in C.
There's no easy way to get a more Python-like behavior for such "slices" in C. You could make it work for indexes up to a certain upper limit by adding a suffix to your string, full of zero bytes:
#define slice(bare_string,start_index) ((#bare_string "\0\0\0\0\0\0\0")+(start_index))
Also, when using macros, it's good practice (and avoids bugs too) to use parentheses excessively.
#define slice(bare_string,start_index) ((#bare_string)+(start_index))
#define arcane_slice(bare_string,start_index) (("ARCANE" #bare_string)+(start_index))