C++ Как преобразовать строку в символ *

Мне нужно преобразовать строку в char * для использования в 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 ответов

Использование strdup() скопировать const char * вернулся c_str() в char * (Запомни free() это потом)

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

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

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

strdup(line.c_str());

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

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

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

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

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() и родственники обычно влекут за собой.

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

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

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

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

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

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

Всякий раз, когда у вас есть 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());
}

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

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

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

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;
}

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

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

Другие вопросы по тегам