简体   繁体   中英

String gets chopped when converted to char* c++

As suggested by the title I'm having some trouble converting a string to char array.

First off let me clear the reasons why I'm needing to do this, because if my approach is wrong, I'll gladly take a different course. (though I'd prefer if the answers could focus on the problem at hand directly)

I have a file with several lines. Each line has the format

b 12 3 4

d 4 1 5.71

...

What I'm trying to do is read each line (with a getLine and save it on a string variable) and split them by the empty space in order to get each letter/number separated.

To accomplish this I took the strtok method which takes as argument a char*

This conversion is where things went wrong.

I took several approaches but always end the same:

attempt #1 - .data()

const char *converted = new char[(line.size()+1)];
//The sentence is complete in this cout!
cout << line << " -printed string\n";
converted = line.data();
converted[line.size()] = '\0';
//sentence no longer complete!
cout << converted << " -printed char array\n";

attempt #2 .c_str()

char *converted;
//The sentence is complete in this cout!
cout << line << " -printed string\n";
converted = (char*)line.c_str();
//sentence no longer complete!
cout << converted << " -printed char array\n";

attempt #3 copy()

char *converted = new char[(line.size()+1)];
//The sentence is complete in this cout!
cout << line << " -printed string\n";
copy(line.begin(), line.end(), converted);
//sentence no longer complete!
cout << converted << " -printed char array\n";

I may have some syntax error in the previous code. I'm doing this from memory since I erased code as I tried different methods. The point is, using .data(), copy() and .c_str() they all compiled, and all gave the same output:

b 12 3 4 -printed string

b -printed char array

Now I've done my homework, and apparently this isn't a complete first. I think I've read somewhere that what's probably happening is that all these methods are interpreting the empty space " " as a "\\0", so it halts after just reading "b". One of the ways to fix it would be to use the boost library.

Unfortunately this is not an option to me. I'm working on a deliverable which can't rely on external libraries. Some help would be much appreciated.

Thanks in advance.

EDIT

The code:

(...)
if (fh.is_open()){
    while (fh.good()){
        getline(fh,line);
        char *converted = new char[(line.size()+1)];
        cout << line << " -printed string\n";
        strcpy(converted, line.c_str());

        cout << converted << " -printed char array\n";
(...)

Same mistake in #1 and #2, you have to copy the characters, all you are doing is copying the pointer.

Replace

converted = line.data();
converted[line.size()] = '\0';

with

strcpy(converted, line.c_str());

Attempt #3 is better but forgets to add the null terminator.

Perhaps you should look into methods of tokenizing that work with std::string, then you wouldn't have all this messing about.

Now that the problem with your code is pointed out

If you are going to split the string(line) by empty spaces then you might want to use formatted input instead of tokenizing. something like (this is not tested)

#include <sstream>
#include <string>
while (std::getline(infile, line))
{
    std::istringstream iss(line);
    string token;
    while(iss >> token) { 

       // Do your thing on token

    }
}

Modify it to your needs.

Problems in attempt #1 for example:

  • Leaking memory: At first you set your pointer to a freshly allocated chunk of memory and then reset the pointer to line.data()

  • Undefined behaviour: You're not allowed to modify the content the pointer returned by std::string::data() or std::string::c_str() points to. It may be an internal copy of the actual buffer held by your string object.

In order to split the string into its parts which are separated by blank you could try the following approach:

split(const std::string &line, char &letter, std::vector<double> &numbers) {
    typedef std::string::size_t size_t;
    size_t n = line.find(' ');
    if (n == std::string::npos || n > 1) {
        // there aren't any spaces or the first part contains
        // more than one letter!
        // bad case? throw something or return an error code
    }
    letter = line[0];
    size_t n2 = line.find(' ', n);
    while (n2 != std::string::npos) {
        numbers.push_back(str2double(line.substr(n, n2 - n)));
        n = n2;
        n2 = line.find(' ', n);
    }
}

I did not test the code. It could be that you have to write n + 1 into find 's calls or something similar. And you have to write the str2double function by yourself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM