But seriously, use whichever is easier to read and requires the least reasoning to interpret, for and while loops are functionally equivalent, in fact, a for loop or the form
I should say, though, that the code can be shortened a little through the use of for, because you can put the initialization, termination, and decrement all in a single line:
#include <stdio.h>
#include <string.h>
int main() {
char my_string[] = "This string has spaces at the end. ";
char no_spaces[] = "This string has none";
char *p = NULL;
for (p = &my_string[strlen(my_string) - 1]; *p == ' ' && p != my_string; --p) ;
*(p+1) = '\0';
printf("%s#
", my_string);
for(p = &no_spaces[strlen(no_spaces) - 1]; *p == ' ' && p != no_spaces; --p)
;
*(p+1) = '\0';
printf("%s#
", no_spaces);
return 0;
}
Well, unless “remove_last_char()” does other magic like push the characters to another buffer, a one line for loop removes trailing whitespace very easily. Maybe that’s what your friend meant, a general preference for using for loops instead of while loops because of the ability to add initialization and increment/decrement commands all in one line of code. After all, if there’s anything “real C programmers” like to do it’s compressing code into as few lines as possible (usually in terms of compiled object code, but a close second is the aesthetic for compact lines of C code).
So if your C string is pointed to by “strbuf”, something like this (not tested):
This will replace all trailing whitespace characters in strbuf with zero (null) chars.
Old Man Rant: Of course when I learned C programming you had to declare “char *lc” outside the loop first, this declaration-cum-initialization feature was only introduced with ANSI C in 1989, just as I was learning it. I spent over $40 (that’s 1989 dollars, mind you) buying a course book on C only to learn it was the older “K&R Edition” and eventually had to shell out another $40 or so to get the newer one.
Ahh, I missed the addition to strbuf for the initialization. Goes to show even one-liners of a sort I’ve written a gazillion times are not immune to first-pass coding bugs
Curiously, my first college programming professor forbade us from using FOR loops. We were basically learning C++, but he had written an obfuscation layer on top of it in order to make everything as generic as possible so that he could pitch it as a language-agnostic programming course. And, like Jragon said, the WHILE loop is the underlying structure of a FOR loop and was more universal at the time, so that’s all we had to work with.
It made it difficult later in life when I learned languages that seemed to prefer FOR loops.
More importantly though, the memory in the nulled-out characters is still pointed to by the original strbuf pointer. Just because you’ve nulled out the characters doesn’t mean they’re not on the heap (if dynamically allocated).
I don’t know if you’re just learning C programming or not (so please excuse me if this is old news to you), but the elegance or efficiency of how you’re removing whitespace from strings is less important in the big picture than learning to code for a stable system. If only because you can always go back and optimize inefficient code, but it’s incredibly painful to hunt down memory leaks or pointer bugs in a large program.
While fun, rather than ask “can I code trailing whitespace removal in one line?” you may find it much more enlightening to describe what else is going on here… I have to say it smells a lot like a memory leak, or at worst something inefficient going on (like if “remove_one_char()” is calling reallloc() with every character removed).
Im sorry, but I hate this style of coding.
It’s too compact and difficult to interpret.
I find it far better to have the code grouped in logical blocks, separated with braces. In general, the difference in object code is nil, and the source code is that much more maintainable.
I don’t disagree, just giving an example of what the OP’s friend may have had in mind. In particular the “pointer postcrement operator happens after dereferencing and use of a left-hand assignment” bit is a perfect example of an unnecessarily compact C programming aesthetic.
*lc-- = ‘\0’;
Is two, even three lines of code in one. It’s great if you can read the shorthand quickly, which is great when all your programmers are veteran C coders… But after 10 years, when the majority of the folks maintaining it have C as their 4th language that they maybe only ever use to maintain the legacy code base, all those fun pointer shorthands are going to cause problems.
At the same time, appreciating that an inline postcrement is evaluated after an assignment while precrement happens before it is necessary for certain patterns of C++ STL programming (like removing entries of a set or map while iterating through it without corrupting the container traversal). But when I do that in Real Life, I put a couple of lines of comments there explaining what’s going on (in one case, even citing a page number in the book “Effective C++” by Scott Meyers :)).
The problem with while loops is that if you screw up the conditional they never ever exit. At least with a for loop you are guaranteed to exit the loop. The for loop would be better in this case, but the idea that real programmers don’t use while loops is just silly. Breaks get confusing too sometimes, especially if you’ve got complicated nested conditionals. IMHO your “real” programmer’s code isn’t any better.
That’s starting to look way too much like line noise. Stuff like this is cute, but it’s a pain in the backside for anyone who ever has to do software maintenance.
The OP’s while loop is simple, clear, and to the point. IMHO, you should keep writing code like that.
Thanks everyone for the comments. I managed to convince folks that a WHILE loop is perfectly acceptable. Being folks are getting into coding details, I’ll fill in a bit more.
The project is Objective-C for an iOS app. The code using the WHILE loop is
The variable textInputField is declared as UITextField and space is defined as 32 (ACSII space). Unless you’re familiar with Objective-C syntax, this probably does not make much sense. That’s why I used the pseudo code in the OP.
I DON’T know Objective-C (any longer; I used to) but this does smell a little like you are copying the string each pass through the loop, which I would regard as…suboptimal.
Whatever you do, it should be put in a function. It is simple and can easily be re-written to optimize. As long as the input and output of the function is well defined, no one working on code outside the function should be concerned with how it is coded.
That said, a WHILE is going to be inefficient. Strings are arrays of characters ideally suited for FOR loops.
Modern compilers do pretty cool stuff to loops. Unrolling them to get better use of pipelining of instructions. Changing around conditions to use hardware native instructions. Stuff like that.
Unless you know the specifics of your architecture and your compiler, I wouldn’t suggest one style as more efficient than the other for the general case.
-D/a
It may be possible a compiler can optimize a WHILE to match the performance of an optimized FOR, but unlikely to exceed it. But the WHILE would have to be written to allow that. Incrementing FOR loops, even without optimization, compile into very dense rapidly executing code.