tags:

views:

226

answers:

4

I have this function:

void ToUpper(char * S)
{
    while (*S!=0)
    {
       *S=(*S >= 'a' && *S <= 'z')?(*S-'a'+'A'):*S;
       S++;
    }
} 

What does it mean for *S != 0, should it be null instead?

+9  A: 

That is checking for the end of the string which is a character which has the value of zero. It is not connected to NULL pointers in any way.

tyranid
That's the correct answer, but as it happens 0 is the same as a NULL.
Donal Fellows
Also, I think it's clearer to use `'\0'` when you mean an end-of-string marker and `NULL` when you mean a non-pointing pointer. Yes, they're all zero in a sense but it is better to keep the *concepts* separate.
Donal Fellows
NULL is implementation specific I don't think the specification mandates NULL to equal 0
John Nilsson
@John: The C++ standard requires NULL to be #defined as 0. However, the actual bits stored in a null pointer don't have to be zero.
dan04
@John: I'm quite sure the literal 0 in the code, when used with pointers, has to signify a NULL pointer (if the actual address is any different from 0, this has to be completely transparent to the user).
UncleBens
@dan04 The standard requires that `NULL`, as defined in <cstddef> be an implementation defined null-pointer constant. Probably 0, but it could also be 0L or some other value. More to the point, it does *not* require that `NULL` not be defined in other headers to be whatever you want. While comparing to `NULL` is more expressive, it is also more error prone.
Dennis Zickefoose
@Dennis: While `NULL` could be something else, I really can't see any sane compiler writer wanting to go that way given that interconversion with 0 *is* mandated. (Some big-iron compilers are clearly not written by sane folks. They also break the assumption that a `void*` and a `char*` are the same size. It's easiest to just pretend that such horrors don't exist, to be honest.)
Donal Fellows
Confusingly, ASCII character 0 *is* named `NUL`.
Daniel Newby
Wouldn't you just write "while (*s)" ?
Martin Beckett
@Donal: It doesn't have to be compiler writers. `NULL` is not a reserved word; anybody can `#define NULL (void*)0` if they feel so inclined. I've worked with libraries that did just that, and its annoying.
Dennis Zickefoose
@Martin: You can do that. I prefer to use `'\0'` for clarity. (Naturally it makes no difference to the generated code.)
Donal Fellows
+4  A: 

I would write it *S != '\0' as I feel that is more idiomatic, but that is really just personal style preference. You are checking for the null character (ASCII NUL).

You might also consider checking S != 0 before any of that code as the pointer itself may be null, and you don't want to dereference a null pointer.

Brian Neal
A: 

I like algorithms better than loops:

#include <algorithm>
#include <cstring>
#include <cctype>

void ToUpper(char* p)
{
    std::transform(p, p + strlen(p), p, toupper);
}

This solution also works for character encodings where a to z aren't sequential.

Just for fun, here is an experiment that only does one iteration with algorithms:

#include <algorithm>
#include <cassert>
#include <cstring>
#include <cctype>
#include <iostream>
#include <iterator>

struct cstring_iterator : std::iterator<std::random_access_iterator_tag, char>
{
    char* p;

    cstring_iterator(char* p = 0) : p(p) {}

    char& operator*()
    {
        return *p;
    }

    cstring_iterator& operator++()
    {
        ++p;
        return *this;
    }

    bool operator!=(cstring_iterator that) const
    {
        assert(p);
        assert(!that.p);
        return *p != '\0';
    }
};

void ToUpper(char* p)
{
    std::transform(cstring_iterator(p), cstring_iterator(),
                   cstring_iterator(p), toupper);
}

int main()
{
    char test[] = "aloha";
    ToUpper(test);
    std::cout << test << std::endl;
}
FredOverflow
I like algorithms better too, in general. But here you are actually looping over the length of the string twice.
Brian Neal
This question is marked C++, so why is Mike using `char*` in the first place? `std::string` to the rescue! Anyway, looping over an array twice is still linear complexity ;)
FredOverflow
Sorry, but your iterator implementation is wrong; it misses many random_iterator operations, and the inequality operator is really brain-damaged.
jpalecek
@jpalecek That's why I preceded the code by *Just for fun, here is an experiment*
FredOverflow
A: 

NULL is a pointer while *S is the value stored at the pointer. Thankes to Dennis Ritchie, the digit 0 is acceotable as both.

Xolve