-2

I'm working on an exercise to calculate the length of a string using pointers. Here's the code I've written below:

int main() {

    std::string text = "Hello World";
    std::string *string_ptr = &text; 
    int size = 0;

   //Error below: ISO C++ forbids comparison between pointer and integer [-fpermissive]
    while (string_ptr != '\0') {
        size++;
        string_ptr++;
    }
    std::cout << size;
}

In a lot of examples that I've seen, the string is often a char array which I also understand is a string. However, I want to try calculate it as a string object but I'm getting the error below.

Is it possible to calculate it where the string is an object, or does it need to be a char array?

  • 3
    `std::string` has a `size` method. – tkausl Mar 27 '22 at 19:24
  • using pointer will be `string_ptr->size()` :) – E. Shcherbo Mar 27 '22 at 19:24
  • 1
    `std::string` has a method called `c_str` which returns a null terminated array. Use your logic on that instead – asimes Mar 27 '22 at 19:29
  • note that `string_ptr++` will increase the address in the `string_ptr` pointer by `sizeof(std::string)` – E. Shcherbo Mar 27 '22 at 19:32
  • Useful additional reading is [What are the mechanics of short string optimization in libc++?](https://stackoverflow.com/questions/21694302/what-are-the-mechanics-of-short-string-optimization-in-libc) which shows how the bytes of the std::string (which is of constant size) can be laid out in memory and details of how it stores a pointer to heap data when the string gets large. – Wyck Mar 27 '22 at 19:51

3 Answers3

6

If you just want the size of the string, well, use std::string::size():

auto size = text.size();

Alternatively, you can use length(), which does the same thing.

But I'm guessing you're trying to reimplement strlen for learning purposes. In that case, there are three problems with your code.

First, you're trying to count the number of characters in the string, and that means you need a pointer to char, not a pointer to std::string. That pointer should also point to constant characters, because you're not trying to modify those characters.

Second, to get a pointer to the string's characters, use its method c_str(). Getting the address of the string just gets you a pointer to the string itself, not its contents. Most importantly, the characters pointed to by c_str() are null terminated, so it is safe to use for your purposes here. Alternatively, use data(), which has been behaving identically to c_str() since C++11.

Finally, counting those characters involves checking if the value pointed to by the pointer is '\0', so you'll need to dereference it in your loop.

Putting all of this together:

const char* string_ptr = text.c_str(); // get the characters
int size = 0;

while (*string_ptr != '\0') { // make sure you dereference the pointer
    size++;
    string_ptr++;
}

Of course, this assumes the string does not contain what are known as "embedded nulls", which is when there are '\0' characters before the end. std::string can contain such characters and will work correctly. In that case, your function will return a different value from what the string's size() method would, but there's no way around it.

For that reason, you should really just call size().

Etienne de Martel
  • 34,692
  • 8
  • 91
  • 111
  • 1
    Using c_str is an invalid approach. An object of the type std::string can contain embedded zero characters. – Vlad from Moscow Mar 27 '22 at 19:44
  • And using `strlen` with such a string would also give you invalid results, anyway. There's no way around it. For the purpose of this answer, I assumed the string did not contain embedded zero characters (and if it does, well, then you have to use `size()`, which kinda defeats the point of writing our own `strlen`, does it?) – Etienne de Martel Mar 27 '22 at 22:28
  • You are wrong. In C strings are defined such a way that any zero character ends a string by the definition of the notion string. – Vlad from Moscow Mar 27 '22 at 22:33
  • Yeah, sure, but this is an issue with the algorithm presented here, not `c_str()` itself. Do you have a better proposal, then, to get the length of a string without using `size()` or `length()`? – Etienne de Martel Mar 27 '22 at 22:36
  • Such an algorithm with objects of the type std::string does not make a sense. – Vlad from Moscow Mar 27 '22 at 22:43
2

First things first, the problem is irrelevant. std::string::size() is a O(1) (constant time) operation, as std::string's typically store their size. Even if you need to know the length of a C-style string (aka char*), you can use strlen. (I get that this is an exercise, but I still wanted to warn you.)

Anyway, here you go:

size_t cstrSize(const char* cstr)
{
    size_t size(0);
    while (*cstr != '\0')
    {
        ++size;
        ++cstr;
    }
    return size;
}

You can get the underlying C-style string (which is a pointer to the first character) of a std::string by calling std::string::c_str(). What you did was getting a pointer to the std::string object itself, and dereferencing it would just give you that object back. And yes, you need to dereference it (using the * unary operator). That is why you got an error (which was on the (string_ptr != '\0') btw).

Debaug
  • 452
  • 4
  • 14
0

You are totally confused here.

“text” is a std::string, that is an object with a size() method retuning the length of the string.

“string_ptr” is a pointer to a std::string, that is a pointer to an object. Since it is a pointer to an object, you don’t use text.size() to get the length, but string_ptr->size().

So first, no, you can’t compare a pointer with an integer constant, only with NULL or another pointer.

The first time you increase string_ptr it points to the memory after the variable text. At that point using *string_ptr for anything will crash.

Remember: std::string is an object.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • "_you can’t compare a pointer with an integer constant_": Comparing a pointer with an integral literal with value `0` is exactly what _is_ possible (`NULL` is probably defined as just that). It fails here because it is a _character literal_ rather than an _integer literal_. – user17732522 Mar 27 '22 at 19:38