Использование strcpy_s для копирования строки в char * - PullRequest
0 голосов
/ 10 января 2020

Я знаю, что когда вы используете strcpy_s, вы должны указывать размер строки назначения в качестве второго параметра. Но если строка назначения - символ *, я не уверен, что делаю это правильно. У меня есть три примера:

char* dest = new char;

// Example 1
CString strTemp = "Bob";
strcpy_s(dest, strTemp.GetLength() + 1, strTemp);   

// Example 2
strcpy_s(dest, strlen("Jose")+1, "Jose");

// Example 3 
char* c = new char;
c = "Richard";
strcpy_s(dest, strlen(c) + 1,c);        

Это все правильно?

Ответы [ 4 ]

2 голосов
/ 10 января 2020

Во всех трех примерах вы передаете размер строки source . Вы должны передать размер буфера destination , чтобы strcpy_s мог убедиться, что не будет переполнения буфера.

Передача размера исходной строки побеждает эту проверку. strcpy_s уже знает размер исходной строки; это может сделать strlen(src) так же хорошо, как вы можете. Чего он не может сделать, так это автоматически определить размер буфера назначения. Ему нужно указать его размер.

const int SIZE = 2048; // an arbitrary large number
char* dest = new char[SIZE];

std::errno_t result = strcpy_s(dest, SIZE, src);   

if (result != 0) {
    // error
}

Вместо этого все ваши примеры должны выглядеть примерно так:

  • dest указывает не на один символ, а на большой массив символов.
  • Второй параметр - размер буфера назначения.
  • Обязательно проверьте код возврата на наличие ошибок.

Примечание: Избегайте использования строк C в C ++, насколько это возможно. Гораздо лучше использовать std::string. Он позаботится обо всем этом беспорядке для вас. Вам не придется иметь дело с распределением памяти или беспокоиться о переполнении буфера.

1 голос
/ 10 января 2020

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

char* dest = new char;, который выделяет один символ, на

char* dest = new char[strlen(strTemp)+1];.

И обратите внимание, что cString не является типом, поэтому замените CString strTemp = "Bob"; на char* strTemp = "Bob"; или const char* strTemp = "Bob"; (последний эквивалентен auto strTemp = "Bob";).

Обратите внимание, что c style string s не objects поэтому strTemp.GetLength() недействительно. Замените его на strlen(strTemp) и включите заголовок <cstring>, который включает эту функцию strlen().

Наконец, ваш код должен быть похож на следующий

#include<iostream>
#include<cstring>
using namespace std;
int main(){

    auto strTemp = "Bob";
    char* dest = new char[strlen(strTemp)+1];
    strcpy_s(dest, strlen(strTemp) + 1, strTemp);   
    cout<<dest;
}
1 голос
/ 10 января 2020

Это все правильно?

Ни один из примеров не верен.

char* dest = new char;

Вы выделили один char. Единственная строка, которую он может представлять, - это пустая строка.

char* c = new char;
c = "Richard";

Назначив c для указания на другое место, вы потеряли значение указателя, которое было возвращено new , Как следствие, вы больше не можете передавать это значение в delete. Это называется утечкой памяти.

Кроме того, начиная с C ++ 11 это плохо сформировано, поскольку строковые литералы больше не могут быть преобразованы в указатель на неконстантный символ. Плохая форма означает, что компилятор не требуется для компиляции вашей программы, и вместо этого он должен выдать вам сообщение о диагностике c, информирующее вас о неправильной форме.

strcpy_s(dest, strlen(c) + 1,c);

Вы должны передать размер буфера назначения; не размер исходных данных. В этом случае буфер назначения слишком мал, но поскольку вы передали неправильное значение, ошибка не обнаруживается и поведение не определено.

Как я уже говорил, передайте размер буфера назначения:

auto error = strcpy_s(dest, 1, "Richard");

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

Конечно, вы можете выделить достаточно памяти для работы копии:

std::size_t destsz = 1024;
char* dest = new char[destsz];

Вы знаете размер, который вы выделили , Просто передайте это strcpy_s:

auto error = strcpy_s(dest, destsz, "Richard");

Не забудьте очистить:

delete[] dest;

PS Стандартная библиотека C ++ не предоставляет strcpy_s. Это нестандартная функция. Это стандартно только на C языке (но для реализации это необязательно).

PSS Не используйте new для выделения строк. Используйте std::string в C ++. С std::string вы можете копировать следующим образом:

std::string c = "Richard";
std::string dest = c;

При таком подходе будет намного сложнее утечка памяти или более серьезные ошибки.

0 голосов
/ 10 января 2020

Если вы выделяете память перед копированием в нее строки, использование функции копирования строк демонстрирует запутанное мышление, приводящее к вопиющим отходам: просто используйте memcpy() (или std:copy_n()).

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

В заключение, все ваши варианты использования неверны.

В качестве отступления:
new char выделяет одиночный char, а не массив соответствующего размера. Вместо этого используйте new char [n].
Вам действительно нужно скопировать строку или вы могли бы просто передать указатель?
Обрабатывающий обработчик ограничений не должен делать то, что вы хотите. Или вообще ничего полезного.

...