- 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
Its great to make them, but the problem is that people come out of the program redesigning very common functions. Its great to learn it at first, to understand it, but if you're supposed to be teaching the next generation of programmers, its more than just teaching the code - its teaching the standards and the thought process. And part of the thought process is - "Has this been done before and if so, can I use it?"
Once again, I totally agree with learning it at first, but there comes a point to say "Hey, really, don't use that anymore."
Admin
You can get it to two lines if you use recursion.
Admin
Admin
Except its not needed. Would you write code like
if (i != 2) i = 2;
and call it "defensive programming"?
Admin
Let me guess... It's called strcmpi because it gives you strings with a butter and garlic sauce?
(okay, it's weak :-)
Admin
That was cute I thought.
I believe the classic strcmpi recipe is strings, lemon, butter, garlic, white wine, and parsley.
Admin
Here's a quick re-enactment as I was reading along:
Admin
His code isn't memory-leak bulletproof, one exception thrown by the 2nd new[] and bam you have it.
Admin
Admin
I think code like this is great! Let's rewrite every well known publicly available function to not make sense!
It's like art. What good is half a cow in formaldehyde? As good as this:
Can you see the beuaty?
Admin
Hey, not everything legal is a good idea :)
NULL is sometimes defined as (void *)0, which should at least make you rcompiler complain.
Admin
There still environments where you have to force the compiler to NOT throw std::bad_alloc, because that exception will crash whatever you're doing.
Yes, even if you catch it. :(
Admin
Well i think this function:
looks nicer than the while(...) stuff posted above, since it's easier to read and comment.
Admin
In our libs we have two implementations of stricmp (in fact they are used for Unicode but I have modified it here for standard srings)
int stricmp(char* s1, char * s2) { for ( ; toupper(*s1) == toupper(*s2); s1++, s2++ ) if ( *s1 == EOS ) return 0;
}
The return code looks WTFy but is in fact the real portable way of writing it in Ansi-C.
int strcmpi(char *sz1, char *sz2) { while(*sz1 && (*sz1==*sz2 || toupper(*sz1)==toupper(*sz2))) { sz1++; sz2++; } return *sz2-*sz1; }
This one is not bad because our implementation of toupper is quite expensive (turkish I and Greek Sigma problem) so it is a bit faster when the strings start is identical. We do no checking of pointers, because if it gets called with a null pointer it is a bug in the caller.
Admin
Admin
Don't know about C++, but in C, the ctype.h functions only take character arguments in the range of unsigned char, plus EOF. So the toupper calls should be toupper((unsigned char)*str).
Admin
According to the language standard yes - sometimes in practice no. IIRC, an old Borland compiler would sometimes generate code that crashed on "delete []p;" if p was null.
Admin
Erm ... what? Do you even know what SEGV means? SEGment Violation. You have accessed an invalid memory segment, i.e. one that isn't allocated to your process. This could, in fact, be 0, or it could be 0x000043f1 or any other random number that isn't a valid, allocated address. It does NOT mean "somebody passed in NULL and they weren't supposed to so I'm going to crash now".
Admin
I got paid for re-writing the C string library. We'd just switched from CodeWarrior to Xcode, and needed versions of wstrlen and friends that worked with 16-bit wchar_t -- the system libraries only work with 32-bit wchar_t.
Admin
Even more problems with this one is the potential for SEGV:
Admin
Admin
Admin
With this implementation stricmp("a", "B") will return 31. It should return -1.
Admin
Same bug in this one. strcmpi("a", "B") return 31 instead of -1.
Admin
I see this pattern every day, and it drives me nuts. Obviously, someone, somewhere back in their education was told to make sure variables are initialized so they don't have random values, but what's wrong with initializing it to the value you want?
(Not to mention, I personally, hate definining multiple variables in one statement -- too many opportunities to forget whether the * binds to the variable or the type.)Admin
Admin
Ideally, you'd never have to do a check for null since you should always know beforehand. However, I've found that putting in what should be redundant checks and tossing an error saying "such and such should never have happened - find out how you f'd up" usually cuts down on the crap I need to debug.
Admin
You completely miss the point though. It doesn't matter if it's 0 or not (we C++ programmers use 0, not the weird macro "NULL"), you can delete it either way. It's just like checking if i is 2 before setting it to 2, as per above. It's retarded.
Admin
Not to mention that stricmp("a", "a") (and most other inputs) recurses endlessly.
Admin
Admin
Why is it that everyone assumes they need to check both strings for the zero terminator?
You already KNOW *s1 == *s2. So you only need to check to see if one of them isn't 0. Guess what value *s2 is when *s1 != 0?
Admin
If your strings are "JAN" and "JAo" it returns positive. If your strings are "JAn" and "JAO" it returns negative.
That is not the intended behavior.
Admin
I think his point was that it's bad to swallow errors, so let the segfault happen and then debug (using electric fence or however the kids are doing it these days) to find the actual problem.
Admin
Here's my slightly modified version of one posted above by Tim.
int stricmp(char* s1, char* s2) { while (toupper(*s1) == toupper(*s2) && *(s1++)) s2++;
}
Admin
Incorrect if both strings are not the same length.
Admin
If they're not the same length, then the while loop will end and it will return toupper(*s1) - toupper(*s2)
I haven't looked at the internals, but I expect toupper(0) = 0, right? So then at the end of s1, you have 0-(some positive value), which will return negative (correct), and at the end of s2, you have (some positive value)-0, which will return positive.
Admin
Admin
Admin
Admin
Admin
Well done. And now try implementing suffix tree construction in the same style (its also O(n)).
Admin
Two lines, accepts NULL for either argument, and it's even readable! Do I get the caek? (Don't give me any crap about repeatedly checking for NULL -- it's two freaking lines!)
Admin
Your recursive call should be stricmp(s1 + 1, s2 + 1), otherwise it recurses endlessly.
Admin
This is nicer: return *s1 ? !!*s2 : -1;
Admin
Errr, i meant:
return *s1 ? -1 : !!*s2;
Admin
You can define equality in terms of the less-than operator, it's a common implementation.
!(foo < bar) && !(bar < foo)
Admin
For those of you making wiseass statements about null-checking before deleting a character pointer, there are in fact compilers out there that will generate code that attempts to dereference the pointer when deleting it (HP-UX's compiler is notorious for this, as well as several custom compilers for embedded processors).
It is generally considered good practice to perform a NULL check before deletion when writing vastly cross-platform code. Considering that testing for NULL is only marginally slower than performing a NOOP, it's not likely to hurt anything.
Admin
I see the usual slew of wrong comments posted, whenever there is a C or C++ snippet. Here's the definitive answers. Note that I may have omitted some -- every time I look at this code I see more problems!!
Major WTFs
Minor WTFs
WTFs in the Comments
Admin
Admin
Yikes, better hope that none of the following conditions occur: (1) s1 is null (2) s2 is null (3) strlen(s1) < len (4) strlen(s2) < len