Given this loop, why is there a semi colon at the end?
for(s = string; *s == ' '; s++)
;
thanks
edit * so is it possible to reverse this procedure so it starts at the end of a string and checks for a space and decreases until it finds a charachter?
It is an empty statement, which is a no-op in C. It's as if you had said:
for(s = string; *s == ' '; s++)
{
// do nothing
}
You use this when everything can be done in the for( ... ) construct itself - the C grammar requires that there be a controlled statement, but there is nothing for it to do.
The semicolon makes an empty statement in the loop. This loop searches for the first non-blank char in string.
The semicolon means that nothing is done inside the loop. In your code the loop just loops until the character in the string is not a space. That is, after that line s points to the first character in the string that is not a space.
Because in C (and others) for grammar is:
for (init; condition; step)
body
Where body can be a closure ( a block of code in {}), but body can also be a empty with ;
I'd like to point out that the loop could be written like this to make it more explicit what is going on and increase readability:
for(s = string; *s == ' ';)
s++;
Or using a while loop:
s = string;
while(*s == ' ')
s++;
But I think the first approach with the empty body is more "c-idiomatic" (and harder to read).
It causes the loop to do nothing. All that happens is that the pointer is advanced.
There has to be a statement or block as the "body" of the for loop. This is what is executed each time through the loop (as long as s is still pointing to a space).
A semicolon on its own is the empty statement -- that is, nothing happens in the loop body, just the s++ on the for loop line.
Related
i've stumbled upon an assignment in a piece of code, in which we add a null character to an array line[i] = '\0' to explicitly declare it's a string, the latter rose in me the question: as the null character is exactly at the end of any string, well how do we know that adding \0 to the i-th element of line would be added to the last position in it, in my eyes i in line, could be any element with any index ,so do the i-th index of any array refer to the last position or what ?
Code like this usually appears just after code that has used the same index variable i to construct the string.
For example:
char string[10];
int i = 0;
string[i++] = 'a';
string[i++] = 'b';
string[i++] = 'c';
string[i] = '\0';
Or, more realistically:
char line[100];
int i = 0;
int c;
while((c = getchar()) != EOF && c != '\n')
line[i++] = c;
line[i] = '\0';
This second example reads one line of text from standard input and stores it in the line array as a proper, null-terminated string.
(In real code, of course, you also have to worry about the possibility of overflowing the array.)
To make things really clear, you can imagine writing code like this more explicitly, with a separate variable to hold the length of the string. For example:
i = 0;
while((c = getchar()) != EOF && c != '\n')
line[i++] = c;
int length_of_string = i;
line[length_of_string] = '\0';
When you see that line
line[length_of_string] = '\0';
it makes it more obvious that the \0 terminator is being stored at a spot in the string that someone has actually determined to be the length of the string. But as you can see, since the variable length_of_string has just been set based on the value of i after the loop, it's perfectly equivalent to just write
line[i] = '\0';
There's sort of an academic-sounding term called loop invariant, but code like this ends up being a perfect example of what it means, and it's worth thinking about for a moment. A loop invariant is something you can say about a loop that's true at all times, for every trip through the loop, at the beginning or the end or in the middle of the loop. For the read-a-line loop I've just shown, the loop invariant is:
i always contains the number of characters that have been read into the string line.
Let's look at all of the ways this "loop invariant" is true. To make things very clear, I'm going to write the loop again, with some comments to make it clear what I mean by the "top" and "bottom" of the loop:
i = 0;
while((c = getchar()) != EOF && c != '\n') {
/* top of loop */
line[i++] = c;
/* bottom of loop */
}
Before the loop runs, the string is empty, so i starts out as 0.
At the top of the loop, before the line[i++] = c step, i still has the value it did last time through the loop.
In the middle of the loop, the line line[i++] = c simultaneously stores the character c into the line array (and at the right spot!), and increments i.
At the bottom of the loop, after the line[i++] = c step, i contains the updated number of characters in the string.
After the loop (and this was your question), since i still contains the number of characters that have been read and stored into line, it's precisely the right index to use to null-terminate the string, with the line line[i] = '\0'.
The other thing that's worth paying attention to here is that the line in the middle of the loop, that simultaneously stores the next character into the line array, at the right spot, and increments i at the same time, is, once again:
line[i++] = c;
My question for you to think about is, what if I had instead written
line[++i] = c; /* WRONG */
It can be hard, at first, to really understand the difference between i++ and ++i, to understand why you would care, to understand why you might pick one over the other. This code here, I think, is an example that really makes the point.
(For extra credit, think about this: What if arrays in C were 1-based, instead of 0-based? What parts of the read-one-line loop would change, and is it still possible to maintain all facets of the loop invariant?)
If you have an already existing string and you just want it to be terminated with \0 on the last+1 index with a correct value, write a function to determine this position. E.g. check the char on the current position and check if the next position contains a legit value. You can then go trough the whole string and determine the last position, then return a pointer to the last position+1 and set your terminator. If you work with a variety of predefined strings this would be the most scalable approach for me.
So I was reading some code from my C-programming course, and came across to this question asking:
Trim the string: " make trim " into "make trim".
This was the code:
#include <stdio.h>
#include <string.h>
#define MAX 100
void trim(char *s) {
char *d = s;
while (isspace(*s++))
;
s--;
while (*d++ = *s++)
;
d--;
while (isspace(*--d))
*d = 0;
}
int main() {
char s[MAX];
gets(s);
printf("[%s] -> ", s);
trim(s);
printf("[%s]", s);
return 0;
}
So, what I want to ask is, what are
while (isspace(*s++))
;
s--;
while (*d++ = *s++)
;
d--;
while (isspace(*--d))
*d = 0;
the incremented string (*s++), the ; after the while() loop doing, and how do they work?
Thanks in advance
The empty body is simply because the condition of the while has a side effect so the whole loop is encapsulated in the condition and there is nothing to put in the body.
So:
while (isspace(*s++))
;
Is the same as:
while (isspace(*s)) { s++; }
They put the semicolon on the extra line to make it clearer that the loop is empty (otherwise you might think the next real statement is part of the loop). Other people might put a comment there as well, or even rewrite it to avoid the body being empty.
Code with some descriptive comments:
This loop picks up each character in turn, increments s to point to the next and continue doing that until the character we picked up is not a whitespace character. Note that because it increments before the test it will increment s one time too many, so that's why there's a decrement after the loop ends.
while (isspace(*s))
;
s--;
This would have been equivalent and doesn't need the separate decrement:
while (isspace(*s)) { s++; }
This loop copies each character from s so starting at the first non-whitespace character to d which points initially at the start of the string. If there was no leading whitespace it copies the character directly on top of itself. The loop ends after we copied a null character, i.e. the end of the string. As before there is one increment too many so we have to decrement d to endpointing at the null character:
while (*d++ = *s++)
;
d--;
This loop decrements d and then picks up whatever character it now points at. If it is a whitespace character then it replaces it with a null character. Note that there is no check for hitting the start of the string, so if the initial string was empty (i.e. a single null character) it will happily work backward through memory corrupting bytes outside the string as long as they are whitespace:
while (isspace(*--d))
*d = 0;
You can rewrite:
while (condition);
as follows:
while (condition) { /* empty block */ }
If the condition contains statements to be executed these will be executed and evaluated as long as the condition meets, this is the case in your example.
1.
In your case the first while loop:
while (isspace(*s++));
loops until it founds the first character being no space (which is the m of make in this case). As there is a postfix increment it will point to a of make:
" make trim \0"
^ ^
d| s|
2.
After that s is decremented (s--;) pointing at the start (m of make).
" make trim \0"
^ ^
d| s|
3.
The second while loop writes the string beginning with make to the beginning of the character buffer because d is pointing to the beginning due it's set at the beginning of the function (char *d = s;). This is done until the null terminator '\0' is reached:
while (*d++ = *s++)
could be rewritten as:
while ((*d++ = *s++) != '\0')
and will result in (note that null terminator '\0' is also written):
"make trim \0 \0"
^ ^
d| s|
4.
Now d will be decremented (d--;) pointing at the space before the null terminator '\0'.
"make trim \0 \0"
^ ^
d| s|
5.
The last while loop will search for the first character being no space (with d) but in reverse order:
while (isspace(*--d))
*d = 0;
It will write multiple null terminator '\0' until it find a character being no space.
"make trim\0\0\0\0 \0"
So the resulting string will be:
"make trim"
It isn't necessary to write multiple null terminator '\0' here but instead one null terminator '\0' would be enought after m of trim.
while (isspace(*s++))
;
is just equal to
while (isspace(*s++));
Don't let ; at a new line confuse you. All in all it is just a way to emphasize that this while loop does not have a body. And a while loop that has no body is performing until it's isspace(*s++) condition is false. Also isspace(*s++) it is an only calculation that should be done for this loop, so that is why there is no need to have a body for this loop.
When you read code like this it is easy to miss this ; and then you can make a wrong assumption that expression directly below the loop is a loop body, but just not surrounded by {}:
while (isspace(*s++));
s--;
while (isspace(*s++))
s--;
See the difference? In second example s-- is a while loop's body. To attract attention programmer can write:
while (isspace(*s++))
;
s--;
to clarify and emphasize his real intentions.
I want to copy a string and want to stop copying either the next character is '\0' or '.'
so I wrote
while((dest[i]=src[i])!='\0'||src[i]=='.');
i++;
when the character is '\0' the while loop works perfectly
but in case of '.'
must I write a separate "if condition" for the second part ?and why?
You have an infinite loop there.
while((dest[i]=src[i])!='\0'||src[i]=='.'); // This is the end of the loop,
// with an empty statement.
Also, you need to change the conditional a little bit.
(dest[i]=src[i]) != '\0' && src[i] != '.'
To avoid the empty statement problem after while and if statements, you can change your coding standard so that you always use the {}.
while ( (dest[i]=src[i]) != '\0' && src[i] != '.' )
{
++i
}
I am trying to count the number of letters of a word before the space. For eg. "Hello how" is my input string and I am trying to count the number of letters in the first word.
#include<stdio.h>
#include<string.h>
int main()
{
char a[30];
int count = 0;
printf("Enter the string.\n"); // Enter hello how as string here.
gets(a);
for ( i = 0; a[i] != '\0'; i++ )
{
while( a[i+1] != ' ' )
count++;
}
printf("%d\n",count);
}
This is a small part of a bigger code, I am actually expecting the value of count to be 5 but it gets into some sort of infinite loop which I am unable to figure out. If I use if instead of while , I get the expected answer. I know gets is not very reliable and I will not use once I get better at programming so it will be kind of you to post your answer about the loop instead of gets. Thank You.
The NUL character is written with a backslash (\), not forward slash (/).
for (i = 0; a[i] != '\0'; i++)
Furthermore, the inner loop will not terminate because you're not incrementing i.
while (a[i] != ' ') {
i++;
count++;
}
Actually, you should not really have two loops. One loop is all you need.
for (i = 0; a[i] != '\0' && a[i] != ' '; i++) {
count++;
}
The expression within the while statement does not depend on count. So with every iteration of the while loop the count gets incremented, but that has no influence on the while conditional, hence it will loop ad infinitum or never, depending on the character at a[i+1].
In addition to that, the conditional statement for the for loop is not written correctly either. The string escape for a NUL character is \0 (backslash). Or you can just compare against a 0 literal, which has exactly the same outcome (though when it comes to the subtleties of C it does not mean exactly the same, but that's splitting hairs).
Use '\0' instead of '/0' in the for loop condition and also the while loop condition will never be false because i remains the same
I am trying to remove spaces from the end of a char array (string).
This is the pseudo code of what I am doing, but it keeps deleting the whole string:
if(string length - 1 != a space)
return
Otherwise, it must equal a space, so
while *mypointer-- != a space
//This should loop back to where there is a character.
Outside of the while loop, I now add one to the pointer by doing
mypointer ++;
and then set mypointer '\0' to signal the end of the string.
I am doing something fundamentally wrong inside of my while, but I cannot seem to figure it out. What could it be?
A little clairvoyance:
while(*mypointer == a space) {
--mypointer;
}
mypointer[1] = '\0';
Notice that it is == a space not != a space.
Edit:
If I were going to write this, I'd probably really use something like:
#include <string.h>
...
char *mypointer = strrchr(string, ' ');
if (mypointer) *mypointer = '\0';
You're probably setting mypointer to \0, which sets the pointer to NULL. You need to set mypointer[1] to \0. Also, make sure you do the right thing for the following edge-cases:
when a string is all spaces,
when string length is 0.
Without the code we can just guess:
How is mypointer initialized?
Are you sure about the while loop condition? Should it be while 'last character is space'?
A slight improvement perhaps:
while(*mypointer == a space) {
*mypointer-- = '\0';
}
Have a look at this code that does the exact job to strip spaces from the end of the string...this is from the Snippets archive - it's an educational thing to watch what's going on when stepping through the debugger and very useful collection of C code also...