Why doesn't a pointer to an element in a c-string return just the element?

Viewed 323

I'm trying to understand how pointers work here. The findTheChar function searches through str for the character chr. If the chr is found, it returns a pointer into str where the character was first found, otherwise nullptr (not found). My question is why does the function print out "llo" instead of "l"? while the code I wrote in main return an "e" instead of "ello"?

#include <iostream>
using namespace std;

const char* findTheChar(const char* str, char chr)
{
    while (*str != 0)
    {
        if (*str == chr)
            return str;
        str++;
    }
    return nullptr;
}

int main()
{
    char x[6] = "hello";
    char* ptr = x;
    while (*ptr != 0)
    {
        if (*ptr == x[1])
            cout << *ptr << endl; //returns e
            ptr++;
    }
    cout << findTheChar("hello", 'l') << endl; // returns llo
}
5 Answers

A C-string is a character buffer that is terminated by a '\0' character. Passing them around involves just passing a pointer to the first element.

All the library routines know that they may read characters starting at the address they are given, until they reach '\0'. Since that's how operator<< for std::cout is designed, it assumes you pass it the starting address of a C-string. That's the contract.

If you want to print a single character, you'll need to dereference that pointer.

cout << findTheChar("hello", 'l') << endl; //returns llo

Return type of findTheChar is const char *. When you try to print a const char * with std::cout it would print the character array pointed by the address upto terminating \0 character.

str -> +---+---+---+---+---+---+
       | h | e | l | l | o | \0|
       +---+---+---+---+---+---+
                 ^
                 |
         findTheChar(str, 'l')

If you want just one character, dereference the address (If it is not null). If you want to print the return address, you can typecast it to void *.

while the code i wrote in main return an "e" instead of "ello"

cout << *ptr << endl; //returns e

Here you are explicitly dereferencing the ptr as *ptr and thus you are printing a char and not const char *.

As you are using C++, you would be better with std::string and iterators.

// Returns offset of first occurance if found
// Returns -1 if not found
int findTheChar(const std::string& str, char chr );

My question is why does the function print out "llo" instead of "l"?

Because you are asking it to, when you print what the function returns.

The return value of your function is a string: const char*.

As a result, cout will start printing the string, starting from where the pointer points to (a char), until it meets a null-C-string-terminator ('\0').

If you wanted just the character, you should dereference the returned pointer during the printing phase, like this:

const char* ptr = findTheChar("hello", 'l');
if(ptr)
    cout << *ptr << endl; //prints l
else
    cout << "Character not found" << endl;

BTW, unrelated to your question, did you compile your code with warnings enabled (e.g. by using Wall and Wextra flags)?

In function 'int main()':
21:9: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
         if (*ptr == x[1])
         ^~
23:13: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
             ptr++;
             ^~~

It comes from this part:

if (*ptr == x[1])
        cout << *ptr << endl; //returns e
        ptr++;

A pointer of type char* points to a memory location and the content is interpreted as a single character. So if you write

char* x = "Hallo";

x points to 'H'. If you write

std::cout << *x << std::endl;

the output operator of std::cout is called with the single char.

But if you write

std::cout << x << std::endl;

you have the special case, where the output operator of std::ostream interprets the char* as a pointer to a C like string which is null terminated. So x points to a single char but ostream operator for char* interprets this as a pointer to the first character of a string.

Return *str and change the function return type. This should work just fine.

Related