- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Also, for the input "What The F \0", the original code will return "What The F\0\0" whereas this code will return "What\0The\0F\0\0", or just "What" if you print it out or something.
Admin
And in a nutshell that's why we have functioning exploits in the wild!
Admin
You just made it worse. Now the compiler hasn't even the chance to give you the warning of the downcast. The correction to your code is to declare your i as a size_t. That's what it was invented for. It's in the standard, even built-in language operators like sizeof use that type (that is imho one of the few wtf of the C language, an operator returning a type, which has its definition in an external header file "stddef.h").
As for systems where sizeof (size_t) > sizeof (int) you can count all 64 bit systems (Solaris, Linux, *BSD and Windows). Microcontrollers with Harvard architecture also often have int in the size of the RAM address size (16 bits) and size_t in the size of the ROM address size (24 bits)
Admin
Apart from the buffer underwrite described above, I think tail recursion optimization would make this an acceptable solution.
Admin
[code] void trim_right( char * str ) { char * p = NULL; while( *str ) { if( p && !isspace(*str) ) p = NULL; if( !p && isspace(*str) ) p = str; }
}
Admin
and twice the readability!
Admin
It would be problematic if this were coming from a columnar data feed where the data has 300 columns, and the content is the word "hi". But then again, as long as the stack is big enough, no problem right?
Admin
Maybe they also learned about compilers that do tail recursion optimisation.
But I would agree that unless you are knowingly coding for a specific compiler for a good reason you shouldn't rely on this, and that this function isn't a good example of why you might want to do so.
Admin
I'd just like to point out that tail recursion is fine for Haskell programmers for a number of reasons:
The entire point of Haskell, as a functional language, is to allow recursion and other similarly functional constructs.
Haskell will handle long chains of recursion gracefully, without spitting stack overflows at you.
They chose Haskell, because they're not hugely worried about performance.
None of these are appropriate reasons to use tail recursion in C++ however.
Admin
Admin
You forgot a -- somewhere and I don't think that overwriting p with NULL after you found your first non blank is a good idea either. Your code to write 0 would then not trigger.
But in a code review, I would reject it because it is too complicated for what it does. The multiple writes when blanking a lot of trailing spaces will hit the "write coalescing buffers and caches" that every modern CPU has nowaday. Only in the extreme case were writes were order of magnitudes more costly than reads would I consider such an approach.
Admin
if strlen() returns a wider type than int (e.g. 64-bit size_t, 32-bit int), and the string's length exceeds the width of int (e.g. a 65KB string on 16-bit int), then you only look at the remainder when dividing by 2<<bitsof(int) (e.g. 1K for a 65K string on 16-bit).
Regardless of the width of strlen() and int, if the string is INT_MAX+2 or more (but less than UINT_MAX+1) characters, you will not modify the string at all because i will be immediately negative.
As pointed out above by someone else, your function stomps on all spaces, even the ones with non-spaces to the right, thus turning your function into an inefficient version of truncateToFirstWord().
Admin
Not sure I see the wtf. This works, and (knowing the financial world fairly well) will be called at most 2-3 times in recursion. Much better than iterating over the entire string to find the first space in the last group of spaces.
At least he didn't do a mem copy every time or something retarded like that.
Admin
The worst "multiple interpretations of undefined code" I ever saw was this:
All the compilers we had in the company, for various architectures and operating systems, produced the superficially expected result (look up the values, shift and combine them, store the result, increment the pointer).
All the compilers, except one, that is.
The x86-hosted to-MIPS cross-compiler I was using to bring this code to the controller CPU of an ATM switch (Asynchronous Transfer Mode, not Automated Teller Machine) evaluated bp++ completely (and stashed the before-increment value) before evaluating anything else, then evaluated the right-hand side using the incremented value of bp, then stored the result using the stashed before-increment value.
The contents of the table were designed so that the calculation reversed the bit-order of the bytes, so if it was working correctly and you did it twice to the same memory, there was no net result.
This stuff all added up to something that looked like a symptom of something else, and I was expecting to have that other problem, so it took me three days to track down what was happening.
Fixed:
Undefined behaviour: Just say, "No."
Admin
This comments section looks like it has mostly been written by a bunch of non programming former programmer trolls all pointing and laughing while desperately trying to be offended by the slightest little edge case scenario.
But the fact remains that the world isn't ending and the code is executing with good performance in real time. A minor bug that has probably never manifested has been noticed and should be fixed.
As for recursion; anyone who thinks pushing to a stack is a slow and inefficient operation... now there is the real wtf.
Admin
For most RW solutions, yes, because most of them are pretty simple and really don't justify recursion. It's just that recursion is such an amusing hammer.
Factorial, for instance, is often shown in recursive form but is faster, uses less memory, and isn't really more difficult to understand in simple loop form.
But there are RW algorithms where recursion is very useful; one that comes to mind right off is quicksort.
And, of course, there is the inimitable "Towers of Hanoi". A toy problem, yes, but if you want a "head hurts" experience try implementing that without recursion sometime.
Admin
Besides the mentioned bugs, they've made a O(n) algorithm into an O(n^2) algorithm.
Also, if you ported this to a small embedded computer with limited resources, you could easily run into a stack overflow. This type of thing happened to me years ago when I ported some 32-bit Unix code to 16-bit Windows.
Admin
One without file system?
Admin
He changed their trim_right routine!
Admin
Wrong on the bunch of non programming former programmer trolls, I'm a still C programming programmer troll.
As for the code, first a little context. I work on a project for a big organisation doing translation work, we have a huge system with a lot of components written in several languages (Java, perl, VBA, python, C++) but the core code of the backend was written in plain C. Mostly C90, now modernized in C99 were possible. The codebase was written around 1997 and put in production around 2000. The system runs since then rather successfully.
Now to my example. Last september we got one document that didn't crash in production but returned an erroneous output file. I tracked the error and it was in the part of the code a colleague wrote several years ago (around 2004). It was exactly the same bug as in the WTF of today. The use of an int instead of a size_t in return of strlen, a loop condition that made the program overwrite str[len-1] with len==0. The result was in some extreme conditions, the output file was a little bit garbled. Had my colleague used the size_t, the writing of str[len-1] would have resulted in a "segmentation fault" directly (because len-1 would have yielded ULONG_MAX) and we would have found the bug in 2004 and not delivered crappy files for 8 years. (to counter directly the naysayers who will say that our quality control failed bla bla bla, an erroneous file wouldn't be noticed by the end user, it would be comparable to a missing blank in a book).
Admin
Admin
Yes, but Lisp and other functional languages do things like "tail call elimination", to turn a recursive scheme into a loop for the machine to run in constant space.
The Real WTF is that C compilers aren't guaranteed to do tail call elimination. Recursion is too good (expressive) a scheme to ignore.
Admin
Recursion can be more elegant if the domain you're working in has objects defined in a "recursive" way, or at least a way which lends itself to recursive operations.
Admin
I wouldn't trust code written by the programmer in ANY language.
Back, in the .com boom, I was tasked with giving technical interviews to prospective Java programmers. After a half dozen Java questions to judge their skill level, I put in some C questions.
The guys who were "thanked for their time" usually asked a question like this:
"That's C! Why are you asking that in a Java interview!?"
"If you can't write good C, how the hell can you write good Java?"
The ones who nailed the interview didn't need to ask the question -- they knew why. Three weeks later, I got a memo from the exec in charge of software development observing the technical quality of the hew hires.
The bad news is that the company was sucked down the toilet in the .com crash -- but my experience is far from unique in that respect....
Admin
It's tail recursive. gcc -O2 compiles it into a loop.
Admin
At any point, there are at most two legal moves. It is always legal to move the smallest disk, because no disk is smaller (and therefore blocking). The other two exposed disks are different sizes, by definition, and you can move the smaller of them onto the larger.
The non-recursive solution is, therefore:
Every other move moves the smallest disk. All the other moves make the other legal move.
The only question, then, is which way to move the smallest disk.
If the goal is to use peg B to move the stack from peg A to peg C, then:
Example: Four disks (15 moves)
Admin
Frankly, my cat loves the dogs breakfast when the it comes up. He really meows in pleasure.
Admin
I see no real problem with that. According to http://llvm.org/demo/index.cgi it produces
vs
generated by
Admin
I don't disagree with you exactly, but as a statically typed, compiled language, Haskell is several times faster than dynamic scripting languages, and reaches performance comparable to tuned C.
I know that specific domains require high performance. But Haskell is finding a lot of use in "high performance" industries like finance specifically because correctness is easy to program, performance is good, and the tight inner loops can be written in C when it isn't good enough.
GHC is getting very good at performance, even without going to the FFI.
That said, stay away from Haskell. You guys don't want your minds blown. You want to sit in your cubicle and treat your work like an assembly line. Your bosses want you to type out buggy code which will be fixed "later" (i.e., if it ever becomes a problem customers care about).
http://lukeplant.me.uk/blog/posts/why-learning-haskell-python-makes-you-a-worse-programmer/ http://stackoverflow.com/questions/2704652/monad-in-plain-english-for-the-oop-programmer-with-no-fp-background/13656209#13656209
Admin
Admin
All these comments about recursion is evil, he's calling strlen() twice, blah blah blah, and no one is pointing out the more serious problems like the lack of checking for a null pointer on entry or how passing an empty string causes the routine to write to invalid memory?
Jeez, it's like griping about how they used Comic Sans to spell "Titanic" on the side of your ship...
Admin
Hopefully they're using a standard version, which is more like
or at least a tail-recursive version.
Admin
When you have a nail in your head, everything becomes a unicorn.
Admin
Most C compilers nowadays will do tail/sibling recursion ok, but either need a high enough -O or a specific flag.
It's reasonable to rely on this, but you have to the right the flags to make sure it happens. Last I looked up it up (back around 2008 I think) the current gcc and microsoft C compiler supported it.
I would assume that LLVM handles it fine.
Admin
You should read the comments before posting. I mentioned the invalid memory overwrite in the second comment.
Admin
No, the order in which the lvalue and the rvalue are evaluated are undefined. The only thing defined is that the assignment is done after these evaluations.
see http://stackoverflow.com/questions/4362501/any-good-reason-why-assignment-operator-isnt-a-sequence-point for a detailed explanation.
Admin
Written by somebody who normally writes Scheme code. It is, after all, tail recursive. Doesn't that result in an optimal loop? Most Scheme interpreters or compilers will replace the call with a goto.
Oh, wait. This isn't Scheme. This is C.
Admin
The order of that evaluation is very well defined, for any conforming C compiler.
Admin
It does iterate over the entire string, twice for each recursive call, to find the length. With a single pointer to keep track of the last non-space found, it could be finished after the first iteration over the string.
Admin
Actually . . .
Once there was a programmer who had a problem. He decided to use recursion. Then he had two midget programmers each whom had a problem. They decided to use recursion...
Admin
Ha ha! He's using a programming pattern that his language wasn't designed for!
That's funny.
Admin
I do see it there; my apologies, good sir.
Admin
Also it doesn't trim strings that contain only a single space. Although that might be by... "design", to put it politely.
Admin
I have a buddy who's taking CS right now. All he's been talking about for the last 3 months is recursion recursion recursion. He said his professor wants him to do things this way.
I've been wondering WTF is up with that, so I'm glad to hear I'm not the only one.
I tried to explain to him that "recursion is dead simple, and just one way of solving something that you'll probably not use very often in practice". He responded with a question about recursion.
Admin
Admin
Words cannot express the weird gut-wrench I felt when my eyes alighted on this code in my RSS feed. I think it may have given me norovirus.
I don't have anything constructive to add (sorry) because when I try to focus on the code my vision starts to blur, presumably in self-defense.
Suffice it to say the real WTF may be that this is the first code snippet ever to make me feel the need to comment on it, even if that comment is little more than a howl of anguish.
Admin
Except that if he had used a simple, straightforward loop it would have obviated the more serious problems he introduced. A string (or another array) is a loop-friendly data structure. Use the right tool for the job. What makes this TDWTF-worthy is the novel (hopefully) use of recursion as an anti-pattern. Everything else is just plain poor quality.
Admin
As long as we're playing Code Golf...
void trim_right(char *str) { char *end = str; while (*str) { if (*str++) != ' ') { end = str; } } *end = 0; }
Why worry about size_t?
Admin
If you are optimizing, why replace all the white space with NUL instead of only the 1st space character on the right? In C a string ends with the 1st NUL. String function don't check the whole buffer looking for another string.
Admin
All you people yelling "tail recursion" don't understand what you're talking about.
The problem isn't the lack of iteration -- TCO solves that nicely. The problem is that every recursive call is going to do another strlen() call. TCO does nothing to eliminate that.