C ++ Как преобразовать строку в символ * - PullRequest
4 голосов
/ 07 октября 2009

Мне нужно преобразовать строку в символ * для использования в strtok_s, и я не смог понять это. c_str () конвертируется в const char *, что несовместимо.

Кроме того, если бы кто-то мог объяснить мне, почему необходима вторая функция strtok_s (внутри цикла), это было бы очень полезно. Почему мне нужно явно продвигать токен, а не, например, в цикле while, в котором он находится, который неявно выбирает каждую строку файла последовательно.

while( getline(myFile, line) ) { // Only one line anyway. . . is there a better way?
    char * con = line.c_str();
    token = strtok_s( con, "#", &next_token);
    while ((token != NULL))
    {
        printf( " %s\n", token );
        token = strtok_s( NULL, "#", &next_token);
    }
}

связанный вопрос .

Ответы [ 10 ]

8 голосов
/ 07 октября 2009

Используйте strdup(), чтобы скопировать const char *, возвращаемый c_str(), в char * (не забудьте потом free())

Обратите внимание, что strdup() и free() - это функции C, а не C ++, и вам лучше использовать методы std::string.

Второй strtok_s () необходим, потому что в противном случае ваш цикл не завершится (значение token не изменится).

5 голосов
/ 07 октября 2009

Вы не можете преобразовать в char *, потому что это позволит вам записать во внутренний буфер std::string.Чтобы не сделать реализацию std::string видимой, это не разрешено.

Вместо strtok попробуйте более "C ++-подобный" способ токенизации строк.Смотрите этот вопрос:

Как мне токенизировать строку в C ++?

5 голосов
/ 07 октября 2009

Как сказал Даниил, вы можете пойти с

strdup(line.c_str());

Что лучше, чем strcpy, который я первоначально предложил, так как он выделяет необходимое пространство

2 голосов
/ 07 октября 2009

strtok() - плохо спроектированная функция для начала. Проверьте свою документацию, чтобы увидеть, если у вас есть лучше. Кстати, никогда не используйте strtok() в какой-либо многопоточной среде, если в ваших документах не указано, что это безопасно, поскольку он сохраняет состояние между вызовами и изменяет строку, к которой он вызывается. Я предполагаю, что strtok_s() является более безопасной версией, но она не будет действительно безопасной.

Чтобы преобразовать std::string в char *, вы можете сделать:

char * temp_line = new char[line.size() + 1];  // +1 char for '\0' terminator
strcpy(temp_line, line.c_str());

и используйте temp_line. Ваша установка может иметь функцию strdup(), которая дублирует вышеперечисленное.

Причина, по которой вам нужно два вызова strtok_s(), заключается в том, что они делают разные вещи. Первый сообщает strtok_s() над какой строкой он должен работать, а второй продолжается той же строкой. Это причина для аргумента NULL; strtok_s() говорит, что нужно продолжать исходную строку.

Следовательно, вам нужен один вызов для получения первого токена, а затем - один для каждого последующего токена. Они могут быть объединены с чем-то вроде

char * temp_string_pointer = temp_line;
while ((token = strtok_s( con, "#", &next_token)) != NULL)
{
   temp_string_pointer = NULL;

и так далее, так как это вызовет strtok_s() один раз с указателем строки, а затем с NULL. Не используйте temp_line для этого, так как вы хотите delete[] temp_line; после обработки.

Вы можете подумать, что это много повозится, но это то, что обычно влечет за собой strtok() и родственники.

1 голос
/ 07 октября 2009

Когда у вас есть std::string и вам нужен (модифицируемый) массив символов, тогда std::vector<char> - это то, что вам нужно:

void f(char* buffer, std::size_t buffer_size);

void g(std::string& str)
{
  std::vector<char> buffer(str.begin(),str.end());
  // buffer.push_back('\0');    // use this if you need a zero-terminated string
  f(&buffer[0], buffer.size()); // if you added zero-termination, consider it for the size
  str.assign(buffer.begin(), buffer.end());
}
1 голос
/ 07 октября 2009

strtok работает так:

Первый вызов, возвращающий строку с начала, без разделителя или всей строки, если разделитель не найден:

token = strtok_s(con, "#", &next_token);

Второй вызов с использованием NULL позволяет продолжить синтаксический анализ той же строки, чтобы найти следующий разделитель:

token = strtok_s(NULL, "#", &next_token);

Если вы достигнете конца строки, следующий вызов вернет NULL;

0 голосов
/ 08 октября 2009

Вы можете легко написать процедуру преобразования, которая будет маркировать строку и вернуть вектор подстрок:

std::vector<std::string> parse(const std::string& str, const char delimiter)
{
    std::vector<std::string> r;

    if(str.empty())
        return r;

    size_t prev = 0, curr = 0;

    do
    {
        if(std::string::npos == (curr = str.find(delimiter, prev)))
            curr = str.length();

        r.push_back(str.substr(prev, curr - prev));
        prev = curr + 1;
    }
    while(prev < (int)str.length());
    return r;
}
0 голосов
/ 07 октября 2009

Если вам действительно нужен доступ к внутреннему буферу строки, вот как: &*string.begin(). Прямой доступ к строковому буферу полезен в некоторых случаях, здесь вы можете увидеть такой случай.

0 голосов
/ 07 октября 2009

2-й вызов strtok находится внутри цикла. Он продвигает ваш указатель токена так, что вы распечатываете токены один за другим, пока вы не распечатаете все из них, указатель станет нулевым, и вы выйдете из цикла.

Чтобы ответить на 1-ю часть вашего вопроса, как предлагали другие, c_str () дает вам только внутренний указатель буфера - вы не можете его изменить, поэтому он const. Если вы хотите изменить его, вам нужно выделить свой собственный буфер и скопировать в него содержимое строки.

0 голосов
/ 07 октября 2009

Я думаю, что вы можете сначала преобразовать строку в const char *, а затем скопировать const char * в буфер char * для дальнейшего использования.

...