Почему поведение одного и того же логического кода отличается?

Почему в приведенном ниже коде обнаруживается разрушение стека, если 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;
}

выход : переполнение стека *** обнаружено разрушение стека ***: прекращено

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

вы выделяете память для хранения указателя на него в ptr1, а затем сразу делаете ptr1 = temp;. Теперь любой указатель на эту выделенную память теряется. Непонятно, как и почему вы ожидаете, что это сработает, или почему вы не используете std::string

463035818_is_not_a_number 09.02.2023 20:07

уже подпись если офф. void string_Concat (char *ptr1, const char *ptr2) эта функция не может объединять строки.

463035818_is_not_a_number 09.02.2023 20:10

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

B Remmelzwaal 09.02.2023 20:12

Отладчик — правильный инструмент для решения подобных проблем. Это фундаментальная часть программирования на всех уровнях. Ваш отладчик сказал вам, где проблема?

Drew Dormann 09.02.2023 20:18

Кроме того, почему это функция void, которая объединяется со строкой 1 и оставляет строку 2? Странный выбор дизайна.

B Remmelzwaal 09.02.2023 20:19

Делайте диагностику здесь, godbolt.org/z/465r86qo9 , помогите чем? Всегда полезно добавить несколько дезинфицирующих средств во время отладки, чтобы посмотреть, что они найдут.

user4581301 09.02.2023 20:20

кстати, для вопроса, который вы задали: когда в вашем коде есть ошибка, некоторые входные данные могут привести к его сбою, а некоторые входные данные могут сделать его не сбойным. Это не должно быть сюрпризом. В любом случае код работает неправильно. Это называется неопределенным поведением, может случиться что угодно. Худший случай, когда кажется, что все в порядке

463035818_is_not_a_number 09.02.2023 20:26

Ваш код имеет неопределенное поведение в обоих случаях, поскольку str1 в main() имеет фиксированную длину, и ваш код добавляет символы после этой длины. Тот факт, что в одном случае это работает, а в другом — нет, является случайностью — одна из особенностей неопределенного поведения заключается в том, что в одних случаях оно может работать, а в других — нет. И это ненадежно - в некоторых других случаях случаи, когда это работает сегодня, могут не работать завтра.

Peter 09.02.2023 21:32

Не изобретайте велосипед. Смотрите std::strcat(). Или предпочитайте использовать std::string.

Thomas Matthews 10.02.2023 01:30
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
9
70
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это неправильно. У вас несколько проблем.

Во-первых, этот код:

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;
}

И, в основном, вы бы сохранили возвращенный указатель и распечатали его, как вы это сделали.

Другие вопросы по теме

Похожие вопросы