#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.
Related
This is a part of code in an arduino SPI communication instance.
char c;
for (const char* p = "Hello, world!\n"; c = *p; p++){
SPI.transfer(c);
Serial.print(c);
}
it will output “Hello,world!” in serial port and SPI. But why c = *p can judge whether this char string is ended or not? Normally we use the
int k;
char p[]="hello world!";
for (k=0; k < strlen(p); k++){
SPI.transfer(p[k]);
Serial.print(p[k]);
}
Before explaining, you have to understand a few things:
Characters (i.e., a char type) can be treated as a number without any cast based upon its ASCII encoding
Strings in C always end with a NUL terminator. Importantly, this character has a numerical value of 0 (i.e., when you treat it as a number, it's equal to zero).
Boolean values don't really exist in C independant of an integer representation. Zero is treated as "false" and anything else is treated as "true".
With this out of the way, let's look at what's happening in the loop.
First, we have a pointer p that points at the first character of the string "Hello world!\n" (this is coming from the statement const char* p = "Hello, world!\n").
At the top of the loop, we check our loop condition, which is c = *p. Note that this assigns the value pointed at by p into c, and assignments in C evaluate to the value that's been assigned. What that means in this context is that our test is essentially just *p.
Since booleans don't exist in C, *p is false only when the character pointed at by p has a value of zero. This can only happen when p is pointing to a NUL terminator, which is always at the end of a string in C. Therefore, our loop will stop when we've hit the end of our string.
When I recently look at some passage about C pointers, I found something interesting. What it said is, a code like this:
char var[10];
char *pointer = &var;
while(*pointer!='\0'){
//Something To loop
}
Can be turned into this:
//While Loop Part:
while(*pointer){
//Something to Loop
}
So, my problem is, what does *pointer means?
while(x) {
do_something();
}
will run do_something() repeatedly as long as x is true. In C, "true" means "not zero".
'\0' is a null character. Numerically, it's zero (the bits that represents '\0' is the same as the number zero; just like a space is the number 0x20 = 32).
So you have while(*pointer != '\0'). While the pointed-to -memory is not a zero byte. Earlier, I said "true" means "non-zero", so the comparison x != 0 (if x is int, short, etc.) or x != '\0' (if x is char) the same as just x inside an if, while, etc.
Should you use this shorter form? In my opinion, no. It makes it less clear to someone reading the code what the intention is. If you write the comparison explicitly, it makes it a lot more obvious what the intention of the loop is, even if they technically mean the same thing to the compiler.
So if you write while(x), x should be a boolean or a C int that represents a boolean (a true-or-false concept) already. If you write while(x != 0), then you care about x being a nonzero integer and are doing something numerical with x. If you write while(x != '\0'), then x is a char and you want to keep going until you find a null character (you're probably processing a C string).
*pointer means dereference the value stored at the location pointed by pointer. When pointer points to a string and used in while loop like while(*pointer), it is equivalent to while(*pointer != '\0'): loop util null terminator if found.
Let's start with a simple example::
int a = 2 ;
int *b = &a ;
/* Run the loop till *b i.e., 2 != 0
Now, you know that, the loop will run twice
and then the condition will become false
*/
while( *b != 0 )
{
*b-- ;
}
Similarly, your code is working with char*, a string.
char var[10] ;
/* copy some string of max char count = 9,
and append the end of string with a '\0' char.*/
char *pointer = &var ;
while( *pointer != '\0' )
{
// do something
// Increment the pointer 1 or some other valid value
}
So, the while loop will run till *pointer don't hit '\0'.
while( *pointer )
/* The above statement means the same as while( *pointer != '\0' ),
because, null char ('\0') = decimal value, numeric zero, 0*/
But the usage can change when you do, while(*pointer != 'x'), where x can be any char. In this case, your first code will exit after *pointer hits the 'x' char but your second snippet will run till *pointer hits '\0' char.
Yes, you can go for it.
Please note that *pointer is the value at the memory location the pointer point to(or hold the address of).
Your *pointer is now pointing to the individual characters of the character array var.
So, while(*pointer) is shorthand usage of the equivalent
while(*pointer!='\0').
Suppose, your string is initialized to 9 characters say "123456789" and situated at an address say addr(memory location).
Now because of the statement:
char *pointer=&var;
pointer will point to first element of string "1234567890".
When you write the *pointer it will retrieve the value stored at the memory location addr which is 1.
Now, the statement:
while(*pointer)
will be equivalent to
while(49)
because ASCII Value of 1 is 49, and condition is evaluated to true.
This will continue till \0 character is reached after incrementing pointer for nine times.
Now, the statement:
while(*pointer)
will be equivalent to
while(0)
because ASCII value of \0 is 0. Thus, condition is evaluated to false and loop stops.
Summary:
In while(condition), condition must be non-zero to continue loop execution. If condition evaluates to zero then loop stops executing.
while(*pointer) will work till the value at memory location being pointed to is a non-zero ASCII value.
Also you can use:
if(*ptr){ //instead of if(*ptr!='\0')
//do somthing
}
if(!*ptr){ //instead of if(*ptr=='\0')
//do somthing
}
*pointer means exactly what it says: "Give me the value that's stored at the place that the pointer points to". Or "dereference pointer" for short. In your concrete example, dereferencing the pointer produces the one of the characters in a string.
while(*pointer) also means exactly what is says: "While the expression *pointer yields a true value, execute the body of the loop".
Since C considers all non-zero values as true, using *pointer in a condition is always equivalent to using the expression *pointer != 0. Consequently, many C programmers omit the != 0 part in order to practice boolean zen.
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.
I am trying to print int array with %s. But it is not working. Any ideas why?
#include<stdio.h>
main() {
int a[8];
a[0]='a';
a[1]='r';
a[2]='i';
a[3]='g';
a[4]='a';
a[5]='t';
a[6]='o';
a[7] = '\0';
printf("%s", a);
}
It prints just a.
I tried with short as well, but it also does not work.
This is because you are trying to print a int array, where each element has a size of 4 byte (4 chars, on 32bit machines at least). printf() interprets it as char array so the first element looks like:
'a' \0 \0 \0
to printf(). As printf() stops at the first \0 it finds, it only prints the 'a'.
Use a char array instead.
Think about the way integers are represented - use a debugger if you must. Looking at the memory you will see plenty of 0 bytes, and %s stops when it reaches a 0 byte.
It prints just a.
That's why it prints just a. Afterwards it encounters a 0 byte and it stops.
Because you declared a as an integer, so those signle characters you initialized would result in an error. You must change it to a char variable. However to save time, just make the variable a pointer using the asterisk character, which then allows you to make a single string using double quotes.
int a[8] means array of 8 ints or 8*(4 bytes) - Say 32 bit architecture
a[0] = 'a' stores in the first int index as 'a''\0''\0''\0'
a[1] = 'r' as 'r''\0''\0''\0' and so on . . .
%s represents any C-style string ie. any string followed by a '\0' character
So
printf("%s", a);
searches for trailing '\0' character and just prints "a" assuming it is the entire string
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"