Почему в приведенном ниже коде обнаруживается разрушение стека, если str1 = «Переполнение» и str2 = «стек», но не если str1 = «стек» и str2 = «Переполнение»?
#include <iostream>
#include<cstring>
using namespace std;
void string_Concat (char *ptr1, const char *ptr2)
{
int length1 = strlen (ptr1);
int length2 = strlen (ptr2);
int i, j;
char *temp = ptr1;
ptr1 = new char[length1 + length2 + 1];
ptr1 = temp;
for (i = length1, j = 0; ptr2[j] != '\0'; i++, j++)
ptr1[i] = ptr2[j];
ptr1[i] = '\0';
}
int
main ()
{
char str1[] = "Overflow";
char str2[] = "stack";
string_Concat (str1, str2);
std::cout << str1 << std::endl;
return 0;
}
выход : переполнение стека *** обнаружено разрушение стека ***: прекращено
Здесь, даже если входные строки изменены, это не должно вызывать проблемы с разбивкой стека, поскольку мы выделяем достаточно места.
уже подпись если офф. void string_Concat (char *ptr1, const char *ptr2)
эта функция не может объединять строки.
Кажется, здесь есть большая проблема с логикой. Вы должны создать массив символов длиной обеих строк и поместить каждую строку в этот массив, прямо сейчас вы даже не копируете первую строку.
Отладчик — правильный инструмент для решения подобных проблем. Это фундаментальная часть программирования на всех уровнях. Ваш отладчик сказал вам, где проблема?
Кроме того, почему это функция void
, которая объединяется со строкой 1 и оставляет строку 2? Странный выбор дизайна.
Делайте диагностику здесь, godbolt.org/z/465r86qo9 , помогите чем? Всегда полезно добавить несколько дезинфицирующих средств во время отладки, чтобы посмотреть, что они найдут.
кстати, для вопроса, который вы задали: когда в вашем коде есть ошибка, некоторые входные данные могут привести к его сбою, а некоторые входные данные могут сделать его не сбойным. Это не должно быть сюрпризом. В любом случае код работает неправильно. Это называется неопределенным поведением, может случиться что угодно. Худший случай, когда кажется, что все в порядке
Ваш код имеет неопределенное поведение в обоих случаях, поскольку str1
в main()
имеет фиксированную длину, и ваш код добавляет символы после этой длины. Тот факт, что в одном случае это работает, а в другом — нет, является случайностью — одна из особенностей неопределенного поведения заключается в том, что в одних случаях оно может работать, а в других — нет. И это ненадежно - в некоторых других случаях случаи, когда это работает сегодня, могут не работать завтра.
Не изобретайте велосипед. Смотрите std::strcat()
. Или предпочитайте использовать std::string
.
Это неправильно. У вас несколько проблем.
Во-первых, этот код:
char str1[] = "...";
Это выделяет достаточно места для хранения строки плюс завершающий нулевой байт. Если вы попытаетесь добавить к нему, вы в конечном итоге столкнетесь с любыми данными, которые следуют за ним. Это плохо. Вы категорически не можете.
Затем вы делаете этот код:
char *temp = ptr1;
ptr1 = new char[length1 + length2 + 1];
ptr1 = temp;
Что здесь происходит. temp указывает на значение ptr1. Затем вы выделяете новое место для ptr1 — хорошо, это круто. Затем вы уничтожаете указатель и возвращаете ему значение temp — исходный ptr1. Это утечка памяти и ничего не дает.
Правильный способ сделать это, конечно, использовать строки C++. Но вы только учитесь, поэтому второй правильный способ сделать это почти то, что у вас есть.
Выделите пространство так, как вы это сделали (вроде), и скопируйте в него обе строки, а затем верните это значение. Так:
char * stringConcat(const char * str1, const char * str2) {
// get the lengths
char * newStr = new char[length1 + length2 + 1];
// append the two input strings to newStr kind of like what you did
return newStr;
}
И, в основном, вы бы сохранили возвращенный указатель и распечатали его, как вы это сделали.
вы выделяете память для хранения указателя на него в
ptr1
, а затем сразу делаетеptr1 = temp;
. Теперь любой указатель на эту выделенную память теряется. Непонятно, как и почему вы ожидаете, что это сработает, или почему вы не используетеstd::string