Как закодировать функцию strcat, которая работает с двумя динамическими массивами

#c #pass-by-reference #dynamic-arrays #c-strings #strcat

#c #передача по ссылке #динамические массивы #c-строки #strcat

Вопрос:

Как мы знаем, функция strcat объединяет одну c-строку в другую, чтобы создать одну большую c-строку, содержащую две другие.

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

Желаемая strcat функция должна быть способна работать для myStr1 и myStr2 любого размера

 //dynamic c-string array 1
char* myStr1 = new char [26];
strcpy(myStr1, "The dog on the farm goes ");

//dynamic c-string array 2
char* myStr2 = new char [6];
strcpy(myStr2, "bark.");

//desired function
strcat(myStr1,myStr2);
cout<<myStr1; //would output 'The dog on the farm goes bark.'
  

Это все, что я смог сделать самостоятельно:

 //*amp; indicates that the dynamic c-string str1 is passed by reference
void strcat(char*amp; str1, char* str2) 
{
    int size1 = strlen(str1);
    int size2 = strlen(str2);
    //unknown code
    //str1 = new char [size1 size2]; //Would wipe out str1's original contents
}
  

Спасибо!

Комментарии:

1. Вы можете продолжать в том же духе; но не назначайте новое пространство до str1 тех пор, пока вы не скопируете старую строку str1 и не освободите старое пространство

2. Я в недоумении, почему std::string не используется вместо этой вещи, которую вы опубликовали, от которой у меня глаза кровоточат.

Ответ №1:

Сначала вам нужно лучше понять, как работают указатели. Ваш код, например:

 char* myStr1 = new char [25];
myStr1 = "The dog on the farm goes ";
  

сначала выделяет 25 символов, затем игнорирует указатель на эту выделенную область (технический термин — «утечка») и устанавливает myStr1 указатель на строковый литерал.

Вместо этого этот код должен был использоваться strcpy для копирования из строкового литерала в выделенную область. За исключением того, что строка состоит из 25 символов, поэтому вам нужно будет выделить место как минимум для 26, поскольку один необходим для ASCII NUL terminator ( 0x00 ) .

Правильный код для этой части должен был быть:

 char* myStr1 = new char [26]; // One more than the actual string length
strcpy(myStr1, "The dog on the farm goes ");
  

Для выполнения конкатенации строк C алгоритм может быть:

  1. измерьте длины n1 и n2 двух строк (с strlen помощью)
  2. n1 n2 1 выделите символы для буфера назначения ( 1 требуется для завершения строки C)
  3. strcpy первая строка в начале буфера
  4. strcat вторая строка в буфер (*)
  5. delete[] память для исходных строковых буферов, если они не нужны (если это правильно или нет, зависит от того, кто является «владельцем» строк… эта часть сложна, поскольку строковый интерфейс C этого не указывает).

(*) Это не самый эффективный способ. strcat переберет все символы строки, чтобы найти, где она заканчивается, но вы уже знаете, что первая длина строки n1 равна, и конкатенацию можно было бы выполнить вместо этого с strcpy помощью too , выбрав правильное начало as buffer n1 . Еще лучше вместо strcpy того, чтобы вы могли использовать memcpy везде, если вы знаете количество, поскольку strcpy вам нужно будет проверять каждый символ на наличие NUL терминатора. Однако, прежде чем приступить к такого рода оптимизации, вы должны четко понимать, как все работает … только после того, как код конкатенации строк верен и для вас совершенно очевиден, вы имеете право даже начать думать об оптимизации.

PS: Как только вы получите все это правильно, работоспособно и эффективно, вы поймете, насколько упрощенным является использование std::string объектов вместо этого, где весь этот запутанный код становится просто s1 s2 .

Комментарии:

1. Мне потребовалось некоторое время, чтобы понять, почему strcpy() — это способ назначения объектов в динамических массивах символов. Это глупая ошибка, назначающая ее как myStr1 = «bark». Я уверен, что это мне очень поможет!

Ответ №2:

Вы выделяете память и указываете свои указатели на эту память. Затем вы перезаписываете указатели, заставляя их указывать куда-то еще. Присвоение, например myStr1 , приводит к тому, что переменная указывает на строковый литерал вместо выделенной вами памяти. Вам нужно скопировать строки в выделенную вами память.

Конечно, это копирование приведет к другой проблеме, поскольку вы, похоже, забываете, что C-строкам нужен дополнительный символ для терминатора. Таким образом, для строки C с 5 символами требуется пространство для шести символов.


Что касается вашей функции конкатенации, вам также нужно выполнить копирование здесь. Выделите достаточно места для обеих строк плюс один символ-терминатор. Затем скопируйте первую строку в начало новой памяти, а вторую строку скопируйте в конец.

Также вам нужна временная переменная указателя для выделяемой вами памяти, так как в противном случае вы «уничтожили бы исходное содержимое str1» (не совсем верно, вы просто str1 указываете где-то в другом месте, теряя исходный указатель).