2016-04-22 4 views
11

У меня есть this code, который работает, как ожидалось:Как сохранить const char * в char *?

#define MAX_PARAM_NAME_LEN 32 

const char* GetName() 
{ 
    return "Test text"; 
} 

int main() 
{ 
    char name[MAX_PARAM_NAME_LEN]; 
    strcpy(name, GetName());  

    cout << "result: " << name << endl; 
} 

Если бы я хотел, чтобы сохранить результат на char * (потому что некоторые функции в пределах рамочные я использую использовать только char * в качестве входных данных) без использования strcpy (для практичности и удобочитаемости кода, а также для обучения), как я мог это сделать? Имея в const, это хорошо работает:

const char* name; 
name = GetName(); 

, но я до сих пор const.

Попытка использовать только char*:

char* name; 
name = GetName(); 

я invalid conversion from 'const char*' to 'char*'. Какая лучшая привычка для такого преобразования?

+5

Что вы хотите сделать? Если вы не хотите изменять строку, первая идиома служит вам и не использует дополнительную память; если вы хотите изменить строку, вам нужно скопировать ее содержимое в другое место (так что вам нужно strcpy или подобное). – SJuan76

ответ

9

return "Test text"; возвращает указатель на только для чтения строки буквального.

Если вы используете функцию, которая принимает char* в качестве входа, и у вас есть const char* (например, в виде строки только для чтения буквальной), то вы должны поставить глубокую копию строки, начиная с этим const char* к таким функциям.

Иначе вы рискуете неопределенным поведением во время выполнения, если функция пытается изменить строку только для чтения.

То, что у вас есть в настоящее время, является адекватным; если вы не можете работать с std::string. (Если вы можете работы с std::stringи всех рамочных функциями принять const char* вход, то я хотел бы предложить ваш рефакторинг кода использовать std::string и передавать вывод метода c_str() на этой строке класса в рамки функции.)

Наконец, если некоторые из ваших каркасных функций требуют char*, то вы всегда можете построить себе небольшой класс адаптера:

class Adapter 
{ 
public: 
    Adapter(const& Adapter) = delete; /*don't try to copy me please*/ 
    Adapter& operator=(const Adapter&) = delete; /*don't try to copy me please*/ 
    Adapter(const char* s) : m_s(::strdup(s)) 
    { 
    } 
    ~Adapter() /*free memory on destruction*/ 
    { 
     ::free(m_s); /*use free to release strdup memory*/ 
    } 
    operator char*() /*implicit cast to char* */ 
    { 
     return m_s; 
    } 
private: 
    char* m_s; 
}; 

Тогда для функции void foo(char* c), вы можете вызвать foo(Adapter("Hello"/*or any const char* */)); и foo может сделать как это радует char*, который встроен в анонимное временное! Вы даже можете улучшить этот класс, чтобы взять конструктор в char*, где в этом случае берется только мелкая копия указателя (и деструктор не удаляет память).

+0

Что делать, если я хочу «скопировать» содержимое 'const char *' в 'char *' (так, без указания фиксированного размера)? Я не знаю размер этого char *, так как позже я буду конкатрировать другой символ. – markzzz

+0

О, подождите. Я вижу, что могу использовать 'char * name;', а также 'strcpy (name, GetName());' также. В принципе, я получил строку, не определенную длиной, которая будет служить моей задаче. Правильно ли это? – markzzz

+1

@paizza No. Используйте что-то вроде 'std :: string name = GetName();' затем передайте 'name.c_str()' любой функции фрейма, которая ожидает 'const char *'. – Andrew

-1

В C++, типичный способ «падение const» является использование const_cast<>:

char *name = const_cast<char*>(GetName()); 

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

Обходным путем является использование std::string в качестве временной зоны отдыха; это будет означать, копирование строки, но это может быть приемлемой производительность мудрым:

std::string s(GetName()); 
char *name = s.c_str(); 

Это, конечно, работать только если name не удерживается вокруг, когда s выходит из области видимости. Если это так, то у вас будет некоторый вид постоянного уровня хранения строк.

+3

Не удаляет const из 'const char *' неопределенного поведения? – Default

+1

Если я могу спросить, почему вы предлагаете что-то, на что нахмурились, не давая других предложений? – Default

+0

@Default Потому что это то, что плакат хотел знать, как это сделать, и я не могу точно знать, что в этой ситуации будет плохо. – unwind

15

Лучшая привычка для такого преобразования заключается в использовании std::string на протяжении всего вашего кода. Поскольку рамки, которые вы используете принимает const char* в качестве входных данных, вы всегда можете передать его результаты c_str() вызова на вашем std::string:

std::string GetName() { 
    return "Test text"; 
} 

int main() { 
    std::string name = GetName(); 
    int res = external_framework_function(name.c_str()); 
    cout << "result: " << res << " for " << name << endl; 
} 

Далекая второй лучше использует const char* в коде:

const char* name = GetName(); 

Поскольку каркас, который вы используете, принимает const char*, вы тоже хороши здесь.

Если вам нужен указатель, отличный от константы, копирование строки невозможно. Вы можете сделать функцию, которая делает это для вас, но вы бы нести ответственность за освобождение копии, которые вы получаете от него:

char* copy(const char* orig) { 
    char *res = new char[strlen(orig)+1]; 
    strcpy(res, orig); 
    return res; 
} 
... 
char *name = copy(GetName()); 
... 
delete[] name; 
-2

Вы можете явно брось. (char*) getName(). Но вы, вероятно, не должны. Потому что бит const означает нечто вроде «обещание не менять его». Поэтому, если у меня есть функция void foo(const char* string) Я saiying: «Дайте мне указатель на строку. Я не изменю ее». И если вы объявляете переменную const char* string = "hello"; Вы говорите, что эту строку не следует изменять. И поскольку вы выполняете это обещание, компилятор знает и может сделать ваш код более эффективным. Вот почему:

const char* a = "hello"; 
const char* b = "hello"; 
(a==b); //is probably true 

ваш компилятор знает, что вы не изменится a или b так что это делает их указывают на тот же адрес, поэтому он имеет только хранить одну "hello" строку. Если вы сейчас переходите на изменение a, то также изменяется и b, и это не то, что вы хотели.

Короче говоря, если вы абсолютно уверены, что функция вашего вызова не изменит строку, вы можете явно ее использовать. (или лучше, измените функцию на (const char*), если она ваша).
Если вы не уверены, вам придется сделать копию. (Как вы уже делаете с strcpy()).

+2

Почему вы предлагаете банк опасные броски? Единственный правильный способ получить строку non-const C из строкового литерала C++ - это скопировать ее. Любая попытка изменить версию, отличную от const, - UB. Пожалуйста, не предлагайте метод, который (почти наверняка) приведет к жесткому диагностированию поведения программы по линии. – Andrew

Смежные вопросы