The code snippet is:
char c[]="gate2011";
char *p=c;
printf("%s",p+p[3]-p[1]);
The output is:
2011
Can anyone explain how it came?
-----Thanks in advance-----
Going through each line in turn:
char c[] = "gate2011";
Let's assume that array c is located at memory address 200.
char *p = c;
p is now a pointer to c. It therefore points to memory address 200. The actual content of p is "200", indicating the memory address.
printf("%s", p + p[3] - p[1]);
The value of p is 200 when we treat it like a pointer. However, we can also treat it like an array. p[3] gets the value of the 4th item in the string, which is "e". C stores characters as their ASCII value. The ASCII value of "e" is 101.
Next, we get the value of p[1]. p[1] == "a", which has an ASCII value of 97. Substituting these into the function:
printf("%s", 200 + 101 - 97);
That evaluates to:
printf("%s", 204);
At memory address 204, we have the string "2011". Therefore, the program prints "2011".
I'm not sure why you'd want to do something like this, but anyway, this is what's happening.
p + p[3] - p[1]
Here you are taking a value of one pointer, and adding the value of the char at position 3, and then subtracting the value of the char at position 1. The char values are being implicitly cast to numerical values before doing the addition and subtraction.
If p is location 1000, then the sum 1000 + 101(ASCII for e) - 97(ASCII for a) will be made. Therefore the result is a pointer to location 1004 in memory. The %s in the printf then subsitutes the string that starts at this location, and ends with the special character '\0'. So the string is effectively clipped to "2011" (the first 4 letters are missed because 101 - 97 = 4).
If this still doesn't make sense, I'd suggest you have a good look at how arrays in C work.
What have you expected? Why not?
p[3]-p[1] = 'e'-'a' = 4
p+4 = "2011"
Related
#include<stdio.h>
int main(void)
{
char s[] = "Hsjodi", *p;
for(p=s; *p; p++)
--*p;
puts(s);
return 0;
}
This is a code snippet given in chapter 13 exercise of
K N King
C Programming: A Modern Approach, 2nd Edn 2008. The question asks for the output.
I was not able to understand and depict the output visually so I coded it in editor and executed it.
This code gives Grinch as output. Can anyone explain why? I'm really having hard time understanding pointers and Strings in C.
No worries, with pointers you just need to remember that *p means whatever is inside p
and p alone means the memory address
so with that in mind,
Remember the ASCII TABLE, this program is operating chars, and because a string is a group of chars, every char has an address memory which happens to be next from the other one.
Have in mind that every char has a number asigned, using -- means to rest -1 to the number asigned of that char.
So with the string or char group Hsjodi the for just rests -1 to every character
Let's go through...
H in ASCII means 48, now do --*p which is -1 so now it's 47 the char G
s in ASCII means 115, now do --*p which is -1 so now it's 114 the char r
j in ASCII means 106, now do --*p which is -1 so now it's 105 the char i
o in ASCII means 111, now do --*p which is -1 so now it's 110 the char n
d in ASCII means 100, now do --*p which is -1 so now it's 99 the char c
i in ASCII means 108, now do --*p which is -1 so now it's 107 the char h
which ends up like this Grinch
for(p=s; // P is a pointer to the first character in S ('H')
*p; // Keep the loop going as long as the character at P is not zero (which, in C, marks the end of the string)
p++) // Each pass, move P to the next character s... j... o... etc
--*p; // Take the value at pointer P, and decrease it by one.
// (H ==> G, s ==> r, the previous letter alphabetically)
The --*p means that the pointer p will first be dereferenced and then decremented by 1. At the beginning of the for loop, the pointer p is assigned to the start of the char string s. Dereferencing p will give you H, decrementing that by 1 will give you G.
The loop does this for all the characters in the string, so the decrementing all the characters in the loop by 1 will give you "Grinch" as the final output.
First, s is a char array and p is a char pointer.
In the for loop, the value of s, which is the address of the first element of the array, is assigned to p.
The judgment condition of the loop is the dereference of p. It is worth noting that the s array has 7 elements, including 6 letters and a null character \0. When the loop reaches the end, a null character in p dereference will cause the loop to abort.
After each round of the loop, p will increase automatically, that is, point to the next character.
The statements in the loop body need to be aware that the dereference symbol has a higher priority than the decrement symbol.
In other words, first dereference p as a character in the string, and then decrement it. The object of subtraction is the ascii code of the character, and the corresponding letter is the previous letter. So the output is Grinch.
Here is a small function from the book Head First on C.
This function should display a string backward on the screen.
void print_reverse(char *s)
{
size_t len = strlen(s);
char *t = s + len - 1;
while ( t >= s )
{
printf("%c", *t);
t -- ;
}
puts("");
}
Unfortunately, I don't understand how it reverses
string.
size_t len = strlen(s); // computes the number of
characters in the string
char *t = s + len - 1; // 't' is a pointer to
a type char
I don't understand what values are used for 's' in this equation; I've read that when the name of an array variable is assigned to a pointer, it actually refers to the address
of the fist character, i.e. array [0]; thus does 's'
have the value 0 here, or does it have the integer value
of a particular character?
For example, the word is s[] = "hello". Then if s[0] = 'h'. Adding strlen(s) to s[0] should yield 104 (in decimal), thus s + len - 1 = 104 + 6 - 1 = 109 (-1 because I assume
I have to subtract '\0' character that strlen takes
into account). But 109 is 'm'. I don't see the way
this equation traverses the string.
while (t >= s); I assume this means that while
t is not equal to zero, is it correct?
Thank you!
First things first, s is a pointer and not a normal char variable.
So, when you assign memory address of a string to s, it contains the address of the first location.
Pointer arithmetic: by adding 1 to a pointer, you make it point to the next memory location. Recall that strings are stored in contiguous memory locations.
So, if s points to "Hello",
printf(*s) will print 'H'
printf(*(s+1)) will print 'e'.
Now, we have the length (=5) in len. When we add len - 1 to s, we make it point 5 locations ahead. It now points to 'o'.
Then by doing while(t >= s) we compare two pointers (t and s) and print the value at address pointed by t and decrement it, till it becomes equal to s which is the first element.
Illustration:
Initial condition:
H e l l o
*s *t
Now we print *t and decrement it.
Output: o
H e l l o
*s *t
We continue it further:
Output: lleH
H e l l o
*s
*t
Since now t == s, we stop.
void print_reverse(char *s)
here s is the pointer to the beginning of the string
size_t len = strlen(s);
this is equals to the number of characters of the string (\0 not counted)
char *t = s + len - 1;
At this point, t is a new pointer which points at the last element of the string (read something about pointer arithmetic if this is not clear to you)
while ( t >= s )
{
printf("%c", *t);
t -- ;
}
In this loop t gets decremented at each iteration, so that every time it points at the previous character in the string.
At the last iteration, t==s, which means that you are printing the first element of the string.
s contains the address of the first character of the array, not the first character itself. An address is not an offset from the start of the array, but an arbitrary (to the user) value. So when you add len - 1 to s, the result is a pointer to the character at index len - 1.
Put another way, this:
char *t = s + len - 1;
Is the same as this:
char *t = &s[len - 1];
The condition while (t >= s) evaluates to true as long as t points to a memory location at or after the start of the array.
It reverses the string by setting the pointer t to the last character of the string and then doing the following:
Print the character that t points to.
Decrease t by one (make it move one char to the left)
Goto (1) unless t now points before the first character of the string.
s is a pointer to the first character of the string. A string is simply a sequence of characters in memory terminated by the NUL character ('\0'). When t == s, t points to the first character, when t < s, t points to the first byte before the first character and this byte is no part of the string.
And when the loop terminates, t won't be zero. t and s are pointers, that means their values are memory addresses. The value of s is the memory address of the first character of the string and this address will certainly not be zero.
char alpha[] = "abcdefghi";
char ch[80], *pch = &ch[0];
strcpy(ch, alpha);
putchar(*pch++);
putchar((*pch)++);
putchar(*++pch);
putchar(++(*pch));
printf("\n%s", ch);
Why does the putchar function print 'a' 'b' 'c' and 'd' respectively?
Why does printf("\n%s", ch); print acddefghi?
I am really bad with pointer stuff.
OK, I will try to explain this as simply as I can.
When you do: putchar(*pch++) what you say is 'print that character of the address that pch points to and then increment the pch to point to the next address'. Essentially, before the first putchar(), *pch = 'a' and after *pch = 'b'(because pch points now to ch[1]).
Now, in the second putchar() what you say is: 'print the character in the address that pch points to and then increment the value of the CHARACTER, in that address, by 1'. So, instead of doing what you did in the second putchar(), you could replace this line whith these two lines:putchar(*pch); // 'b'
*pch += 1; // see, you increment the value(notice the *), not the pointer.
However, because as I said, it increments the character AFTER the second putchar(), it just prints what it was which is 'b'. So, just to clear, after the second putchar(), ch[0] = 'a'(we did not change anything in this value)
and ch[1] = 'c'(we incremented the value of the character by 1 and 'b' + 1 = 'c'). The rest is unchanged, so ch[2] = 'c', ch[3] = 'd' and so on.. but pch points to ch[1]
Now, in the third putchar(), you do something similar with the first except that you first increment the address that pch points and then print the value of this address.So, you could replace the third putchar() with these two lines:pch++; // increment the pointer by one, it now points to ch[2], which is 'c'(it remained unchanged)
putchar(*pch); // 'c'
So, after the third putchar(), ch[0] = 'a'(remained unchanged), ch[1] = 'c'(changed in the second putchar()), ch[2] = 'c'(remained unchanged)
Finally, in the last putchar(), what you do is similar to the second except that you increment the value of the CHARACTER that pch points to before you print it.
Remember that pch points to ch[2]
So, you could replace the last putchar() with these two lines:
*pch += 1; // 'c' + 1 = 'd'
putchar(*pch); // 'd'
So, after the 4 putchars, ch[0] = 'a'(it remained unchanged), ch[1] = 'c'(changed in the second putchar()), ch[2] = 'd'(changed in the fourth putchar()) and ch[3] = 'd'(it remained unchanged) and the rest of the string remains unchanged, and I think it is now obvious why you get the result you get from printf().
ch is an array of characters. In C an array is just a pointer to the first element in the array. That makes ch a pointer to a char (char *) as well. putchar prints a single character when you pass it a character to print. *pch++ says 'use the character at this address' then increment the address to point at the next char. printf prints the whole string because of the format specifier "\n%s" which tells printf to print the array of characters (a string if you will) which is found at the address ch. Which we know from above is an array of characters. Hope this helps.
Dereferences the pointer and returns back the value 'a', then the pointer is incremented by 1.
putchar(*pch++);
Same as the first explanation above. Returns back 'b'.
putchar((*pch)++);
Increments the pointer then dereference it, the value returned back is 'c'.
putchar(*++pch);
Same as the previous, returns back the value of 'd'.
putchar(++(*pch));
Pointer increments/decrements are based on the type of the variable that is declared.
Since ch is declared an array of characters, printf prints out the entire contents of that said variable.
strcpy(ch, alpha);
Copy the contents of alpha into an array ch, i.e. "abcdefghi"
All "arrays" decay into pointers pointing to the first element of type T.
(They are not really arrays!)
value of address means address location
value of data means the value in that address
Try to think it in this way:
Whatever follows after * is an address.
Eg: *x, here the value of x is an address.
And when you combine * and x i.e. *x, it represents the value at that address.
Whenever you do *p++, the value of p( which is address value) post increments by depending on the data type of the pointer. So, it will point to the next block of address. It won't increment the value of data.
In C, the char pointer points to address of first array and prints the entire array until a null character is received.
Watch lectures on pointer. You will be clear.
*pch++ print current pointer value and increments pointer
(*pch)++ print current pointer value, and increments that value
*++pch It increments pointer and print value of new pointer
++(*pch) It increments value of current pointer and then print that new value
putchar(*pch++); // It prints ch[0], print and increments pointer
putchar((*pch)++); // It prints ch[1], print and increment value;
putchar(*++pch); // It prints ch[2], pointer increments and print
putchar(++(*pch)); // It prints ch[2]+1, increment value and print
I have code for reversing a string. Let's say I type 'ABC', the output will be 'CBA'. However, there are some code lines I quite don't understand.
1 #include <stdio.h>
2 #include <string.h>
3
4 void print_reverse(char *s) {
5 size_t len = strlen(s);
6
7 char *t = s + len-1;
8 while(t >= s) {
9 printf("%c", *t);
10 t = t-1;
11 }
12 puts("");
13 }
14
15 int main()
16 {
17 char charinput[100];
18 printf("Enter character you want to reverse:");
19 fgets(charinput, 100, stdin);
20 print_reverse(charinput);
21 getchar();
22 }
What does line 7 and 8 do? What would be the output for the pointer t?
The posted code uses the following algorithm:
Line 7: set the pointer t to the last character in the string (note: it will be a newline character if the user entered a string fewer than 99 characters). The -1 is to move one character back from the terminating nil-char
Lines 8-10: This is the core of the reversal reporting loop. The pointer t is repeatedly tested against the address at the beginning of the string. The condition clause checks to see if the t value (an address) is greater-or-equal to the beginning address of the string. So long as it is, the loop-body is entered and the character currently residing at the address held in t is sent to stdout via printf(). The address in t is then decremented by one type-width (one-byte on most-all systems with a single-byte char) and the loop repeats. Only when t contains an address before s does the loop break (and note: this is not within the standard; see below for why).
Something you should know about this loop (and should point out to the author if it isn't you). The final pointer comparison is not standard-compliant. The standard specifies comparison between non-null, like-type, pointers is valid from the base address of a valid sequence (charinput in this code, the address parameterized through s) up to and including one type-element past the allocated region of memory. This code compares t against s, breaking the loop only when t is "less". But as soon as t is less-than-s its value is no longer legally range-comparable against s. In accordance with the standard, this is so because t no longer contains a valid address that falls in the range from charinput through 1-past the size of the charinput memory block.
One way to do this correctly is the following:
t = s + len;
while (t-- > s)
printf("%c", *t);
Edit: after a journey into the standard after prodding from Paul Hankin the prior code has been rewritten to account for an unnoticed UB condition. The updated code is documented below:
t = s + len;
while (t != s)
printf("%c", *--t);
This will also work for zero-length strings. How it works is as follows:
t is set to the address of the terminating nulchar of the string.
Enter the loop, the condition being continue so long as the address in t is not equivalent to the base address of s.
Decrement t, then dereference the resulting address to obtain the current character, sending the result to printf.
Loop around for next iteration.
Let's understand it step by step:
len = strlen(s) will assign size of string s pointing to in bytes to the len (say this len is 10).
s is pointing to the first character of the string. Let's assume the address of first element of this string is 100, then s contains 100.
Adding len-1 to s will give 109.
Now, the line 7
char *t = s + len-1;
tells the compiler that t is pointing to the element at address 109, i.e, last element of string.
Line 8
while(t >= s) {
tells the compiler that loop will continue until t points to something before the first element of the string.
line 7: pointer t is pointing to the last character (s+len-1).
line 8: repeat the step when the address of the t equals or greater than the address of the s. suppose if s pointing to address of the first input string is 1101, the address of the next character is 1101+1=1102 and third is 1102+1=1103 and so on. so t point to 1101 + len-1 in line 7 would be 1101+10-1 (1110) if you input has 10 characters long.
line 9:print the character hold by address pointing by t.
line 10: t is decremented by 1 and now point to the immediate left character.
9 and 10 repeated while the address is greater or equal (1110 in my illustration)
t starts to point at the last character of the string s and in the following loop is decreased until it points to the first character. For each loop iteration the character is printed.
Line 7 sets the pointer t to point to the end of the string s. Line 8 is a while loop (which will go backward through the string, until the beginning). The pointer t is the current position in the string and is output on line 9.
char *t = s + len-1; : To point to the last character of string s
while(t >= s) : To scan all the characters of string s in reverse order (as s points to first character and we have made t point to last character in line 7).
Hope this helps.
This code:
char arr1[20] = "fedcba";
char *ptr;
ptr = &arr1[2];
puts(arr1);
printf("%d\n",*arr1 - *ptr);
printf("%d\n",arr1 - ptr);
I understand that the first printing puts the string.
printf I - what is supposed to print? It says * arr1 - * ptr?
printf II - What is the difference between one and two?
The first prints the difference between 2 chars:
The second prints the difference between 2 pointers.
*arr1 dereferences a char* and returns the first character, which is 'f'.
ptr = &arr1[2]; will make ptr point to "dcba". It takes the address of the third character in arr1. *ptr returns 'd'.
So the first printf returns the difference between characters f and d - which is 2.
The second one is the difference between the two pointers. It's legal since they both point inside the same character array. It's the same as arr1 - &arr[2] which will most likely be -2, since arrays are stored continuously in memory.
printf("%d\n",*arr1 - *ptr);
This prints the result of the first character of arr1 minus the first character of ptr.
Here is clearer version that does the same thing: printf("%d\n",arr1[0] - ptr[0]);
printf("%d\n",arr1 - ptr);
This prints the pointer difference between arr1 and ptr, which is 2.
Essentially the property holds that: (a[x] - a) is equivalent to x
Just add these two lines to your program for better understanding...
printf("\n%d AND %d... %c",arr1, *arr1, *arr1);
printf("\n%d AND %d... %c",ptr, *ptr, ptr[0] ); //ptr[0] == *ptr
Hope this helps...