Strlen() always returns 6 or 0!

Hello All,
I am trying to count the number of characters in a user entered string. Here is my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <string.h>
using namespace std;

const char *get_c_string();

int main()
{
    const char *user_string;
    cout << setw(3) << "Enter a string: ";
    user_string= get_c_string();

    cout << strlen(user_string) << endl;

    return 0;
}

const char *get_c_string()
{
    string str;
    getline(cin, str);

    const char *s= str.c_str();
    return s;
}


No matter what I enter, I strlen() returns 0 or 6! And it seems to be random. "Hello world" might return 6 one time, and 0 another.
Please help if you can. Thanks


Edit:
I found a work-around, but I am not sure why this works and the original does not. Here is my new code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <string.h>
using namespace std;

int main()
{
    string user_string;
    const char *user_c_string;
    cout << setw(3) << "Enter a string: ";
    getline(cin, user_string);

    user_c_string= user_string.c_str();

    cout << strlen(user_c_string) << endl;

    return 0;
}

Last edited on
Your code mixes C-style strings (char* etc) with C++ strings. Unless there is some reason to mix these completely different datatypes suggest you stick to one or the other. In C++ that'd be:
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <string>
using namespace std;
int main()
{
    cout<<"Enter a string: \n";
    string str;
    getline(cin, str);
    cout<<str.length();
}

For C-style strings: http://www.codeforwin.in/2015/04/c-program-to-calculate-length-of-string.html
It's actually part of a larger program. I'm working on a dynamically allocated stack, and by switching the string to a c-style string i can easily tell when i've reached the string's end (i.e when the pointer -> data = '\0').
Your program runs fine here http://cpp.sh/
works fine on cpp.sh
cpp.sh/2ctg2
Oh man. That's not good news. Any ideas as to what might be causing the issue?
http://www.cplusplus.com/forum/general/202907/

please stick to one post only

what compiler are you using?
My bad. Won't happen again. I am using G++
version?
First, this problem is a bit harder then you might be thinking it is.

But, let's make your program work correctly first:
1
2
const char *s= str.c_str();
return s
;

What happens to str.c_str() after str is no longer in scope (i.e., doesn't exist any more)? Your program is exhibiting undefined behavior, since it is accessing a value that no longer exists. On my system, your code crashed the first time and printed 424 the second time.

The punchline is that std::string has a size member function, which returns the length in constant time; it's both quicker and safer then strlen(). Do not manipulate C-strings or pointers unless you're forced to.

1
2
3
4
5
int main() { 
  std::string user_string;
  std::getline(std::cin, user_string);
  std::cout << user_string.size() << "\n";
}


Now to answer the question correctly:
Because of the way string encoding works, the number of bytes the string container contains (std::string::size()) or the number of bytes from a pointed-to-address until a zero-byte (strlen()) does not correspond necessarily to the number of characters in the string. This is because there are more possible characters than values in a byte -- so, for character encodings which support more than 256 characters, there must be at least some characters that compose more than a single byte -- and so, strictly speaking, your program's output will be wrong.

This article has been circulated quite a lot, but it's worth reading if you're unfamiliar with the idea of character encoding:
http://www.joelonsoftware.com/articles/Unicode.html

If you are using Unicode UTF-8, then here's a function which will count the number of characters contained in a string. ASCII is compatible with UTF-8, so if you're using an English locale, you'll probably not notice a difference.

Here is an example program. The single test case I've included here uses a random Arabic phrase copied from internet search results:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# include <string>
# include <iostream>

template <typename Allocator>
std::size_t u_strlen(std::basic_string<char, Allocator> const& s) {
  auto cnt = std::size_t{0};
  for (char c: s) cnt += (c & 0xC0) != 0xC0;
  return cnt;
}

int main (int, char **) {
  std::string s{R"(لوحة المفاتيح العربي)"};
  std::cout << s.size() << "\n";
  std::cout << u_strlen(s) << "\n";
}
The original code has a problem with the local object str
20
21
22
23
24
25
26
27
const char *get_c_string()
{
    string str;
    getline(cin, str);

    const char *s= str.c_str();
    return s;
}


At line 25, the function c_str() return a pointer to the c-string representation of the std::string str declared at line 22. However, when the function get_c_string() ends, that local variable str is destroyed. Hence the pointer user_string in main() is now pointing to an object which doesn't exist. That memory location could be re-used for some other purpose and the pointer is no longer valid.
Here's one way to make use of a c-string and strlen. Note this code is not particularly robust, it's possible that the user could enter a string too long to fit in the buffer. There are ways round that, but I omitted that here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <iomanip>
#include <cstring>
#include <string>

using namespace std;

void get_c_string(char *);

int main()
{
    char user_string[1024];
    cout << setw(3) << "Enter a string: ";
    get_c_string(user_string);

    cout << strlen(user_string) << endl;
}

void get_c_string(char * buffer)
{
    string str;
    getline(cin, str);

    strcpy( buffer, str.c_str() ) ;
}
The problem is the memory holding the string is released, and at the moment you strlen on it, it has garbage data.

There're a few ways to make it right based on your program.

a) Pass a large enough buffer to get_c_string(), and get_c_string() will copy user input to the buffer
b) Allocate memory dynamically in get_c_string(), and copy user input to the buffer. Be sure to release the memory after use.
c) Return std::string directly, and use str.length() instead.
Last edited on
Topic archived. No new replies allowed.