2012-06-05 2 views
2

У меня есть приложение Visual Studio 2008 C++ 03, где я хочу скопировать из std :: string в массив символов, но мне нужно массив char должен быть завершен до нуля, даже если он должен обрезать строку для этого.копирование из std :: string в массив символов и завершение нулевого результата

Это, например, работает по желанию:

inline void CopyAndNullTerminate(const std::string& source, 
            char* dest, 
            size_t dest_size) 
{ 
    source.copy(dest, dest_size); 
    using std::min; 
    char* end = dest + min(dest_size - 1, source.size()); 
    *end = '\0'; 
} 

int main() 
{ 
    enum{ MAX_STRING_SIZE = 15 }; 
    char dest[ MAX_STRING_SIZE ]; 
    std::string test = "This is a test"; 

    CopyAndNullTerminate(test, dest, MAX_STRING_SIZE); 

    assert(strcmp(test.c_str(), dest) == 0); 
    return 0; 
} 

пример: http://ideone.com/0EBYb

Есть более короткий, более эффективный способ сделать это?

Благодаря

ответ

6

Да, использовать strncpy, определенные в cstring:

void copyString(const std::string& input, char *dst, size_t dst_size) 
{ 
    strncpy(dst, input.c_str(), dst_size - 1); 
    dst[dst_size - 1] = '\0'; 
} 

Обратите внимание, что для некоторых реализаций std::string (как указывал @ K-Балло), это может быть короче, но меньше эффективный. Это связано с тем, что std::string НЕ гарантируется реализация с использованием строк C-syle, хотя для большинства ситуаций это, вероятно, так.

+0

У этого есть неудачный побочный эффект, связанный с необходимостью создания допустимой нулевой строки C для тех реализаций 'std :: string', которые не используют это как внутреннее представление. –

+0

@ K-ballo true, но для большинства реализаций я предполагаю, что это будет используемая реализация ... –

+0

Хотя этот метод короче, он _may_ будет ** менее ** эффективным. Вы должны указать это в своем ответе. –

1

Как насчет хорошего ole 'C strcpy_s?

strcpy_s(dest, MAX_STRING_SIZE, test.c_str()); 

Я предпочитаю это strncpy. strcpy_s (и его старший кузен strlcpy) копия цикла завершится после копирования «\ 0», но strncpy всегда будет выписывать количество указанных байтов (заполнение «\ 0», если исходная строка короче).

+0

К сожалению, 'strlcpy' не является частью стандарта C, это функция BSD, насколько я могу судить, и не будет доступна в VS 2008. –

+0

@ RichardJ.RossIII, спасибо! Исправлена. – jxh

+0

@ RichardJ.RossIII, BTW, причина, по которой я предпочитаю эти функции, заключается в том, что 'strncpy' всегда записывает количество байтов, указанных в третьем параметре, и не имеет значения null, если длина строки источника превышает указанные байты. – jxh

4

Если вы сначала инициализируете строку адресата (до нуля), вы можете получить ее, если она не будет перезаписана последним элементом в вашем массиве.

enum{ MAX_STRING_SIZE = 15 }; 

char dest[ MAX_STRING_SIZE ] = {0}; // all elements are initialized to 0 
std::string test = "This is a test"; 

// determine the length to copy, it will be the min of MAX_STRING_SIZE-1 
// or test.size. This will ensure that even if the string it shorter than 
// the MAX_STRING_SIZE, that it will copy properly -- without reading past the 
// array bounds of the string. 
auto copy_len = std::min(test.size(), MAX_STRING_SIZE - 1); 

std::copy(
    test.begin(), 
    test.begin() + copy_len, 
    dest); 

Это скопирует самое 14 символов для вашего dest объекта. Если тестовая строка короче 14 символов, она копирует только длину тестовой строки. Все элементы, не скопированные, останутся при их инициализированном значении (null).

6

Предполагая, что dest_size гарантированно будет по крайней мере, 1 (что представляется разумным для меня, так как в противном случае это не возможно копировать и нуль прекратить что-либо в буфер):

inline void CopyAndNullTerminate(const std::string& source, 
            char* dest, 
            size_t dest_size) 
{ 
    dest[source.copy(dest, dest_size-1)] = 0; 
} 

В C++ 11 , а во всех активно поддерживаемых реализациях C++ 03 (включая Visual Studio) std::string имеет непрерывное хранилище, как и std::vector. Таким образом, вы можете использовать memcpy вместо std::string::copy и сравнить производительность.

Аналогично можно сравнить strncpy, std::copy, std::copy_n, strcpy_s, и, возможно, других я забыл, видеть который лучше оптимизирован. В каждом случае вы можете вычислить количество байтов для копирования как std::min(source.size(), dest_size-1). Это также позволяет избежать наиболее неэффективного случая strncpy (копирование маленькой строки в большой буфер).

При выполнении всех этих, вы можете рассчитывать на то, что является действительным называть source[0] даже если source пустая строка.

2

Вот пара, которая короче:

inline void CopyAndNullTerminate(const std::string& source, 
            char* dest, 
            size_t dest_size) 
{ 
    *dest = '\0'; // assumes `dest_size > 0` 
    strncat(dest, source, dest_size); 
} 

void CopyAndNullTerminate(std::string const &source, 
          char *dest, 
          size_t dest_size) { 
    sprintf(dest, "%*s", dest_size, source.c_str()); 
} 

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

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