Я столкнулся с ошибкой сегментации, когда я получил доступ к правильной памяти при перестановке двух строк - PullRequest
0 голосов
/ 08 ноября 2019

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

Я могу правильно отследить первую строку двухмерной строки s [2] [27], ноя поменял s [0] на s [1], я попытался cout 0, и компилятор выдал мне ошибку сегментации.

void swap1(char *a, char *b)
{
    char *temp;
    int i = 0, j = 0;
    while (a[i] != '\0')
    {
        temp[j] = a[i];
        i++;
        j++;
    }
    temp[j] = '\0';
    i = 0, j = 0;
    while (b[i] != '\0')
    {
        a[j] = b[i];
        i++, j++;
    }
    a[j] = '\0';
    i = 0, j = 0;
    while (temp[i] != '\0')
    {
        b[j] = temp[i];
        i++, j++;
    }
    b[j] = '\0';
}
int main()
{
    char s[2][27] = {"wangzhehan", "cuisibo"};
    // const char s[2][10]={"111","222"};
    cout << s[0] << endl;//s[0] can be printed correctly

    swap1(s[0], s[1]);

    cout << s[0];//the compiler showed a segmentation fault here

ожидаемый результат - wangzhehan cuisibo, но на самом деле результатwangzhehan

тогда компилятор показал: «Возникла исключительная ситуация. Ошибка сегментации» или, есть ли лучший способ поменять две строки, не используя стандартную библиотечную функцию?

Ответы [ 3 ]

1 голос
/ 08 ноября 2019

При замене двух строк вам не нужно хранить временную строку целиком.
(или вам придется полагаться на динамическое распределение)

В вашем коде вы объявляете char *temp; и сразу после того, как вы используете temp[j], но эта временная строка не выделяется (указатель указывает на что-либо).

Я не приведу здесь полное решение, поскольку оно выглядит как упражнение, но только это
Используйте один цикл, в котором вы помещаете a[i] во временный char (не char *), затем перемещаетесь b[i] в a[i] и, наконец, перемещаете временный char в * 1015. *.
(вам придется позаботиться о длине двух строк при замене символов)

1 голос
/ 08 ноября 2019

Вы не выделяли память, куда вы собираетесь временно копировать строки. Указатель temp не инициализирован.

char *temp;

Таким образом, функция вызывает неопределенное поведение.

Функция может быть написана проще, если использовать стандартные строковые функции Си.

Например,

#include <iostream>
#include <cstring>
#include <algorithm>

void swap1( char *a, char *b )
{
    size_t n = std::max( strlen( a ), strlen( b ) ) + 1;

    char *temp = new char[n];

    std::strcpy( temp, a );
    std::strcpy( a, b );
    std::strcpy( b, temp );

    delete [] temp;
}    

int main() 
{
    char s[2][27] = {"wangzhehan", "cuisibo"};

    std::cout << s[0] << '\n';

    swap1( s[0], s[1] );

    std::cout << s[0] << '\n';

   return 0;
}

Выходные данные программы:

wangzhehan
cuisibo

Если вы не можете использовать стандартные строковые функции и должны использовать только циклы, то функция может выглядеть следующим образом, как показано в демонстрационной программе ниже.

#include <iostream>

void swap1( char *a, char *b )
{
    size_t n1 = 0;

    while( a[n1] != '\0' ) ++n1;

    size_t n2 = 0;

    while ( b[n2] != '\0' ) ++n2;

    size_t n = n1 < n2 ? n2 : n1;

    char *temp = new char[n + 1];

    for ( size_t i = 0; ( temp[i] = a[i] ) != '\0'; ++i );
    for ( size_t i = 0; ( a[i] = b[i] ) != '\0'; ++i );
    for ( size_t i = 0; ( b[i] = temp[i] ) != '\0'; ++i );

    delete [] temp;
}    

int main() 
{
    char s[2][27] = {"wangzhehan", "cuisibo"};

    std::cout << s[0] << '\n';

    swap1( s[0], s[1] );

    std::cout << s[0] << '\n';

   return 0;
}

Опять же, вывод функции -

wangzhehan
cuisibo

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

Например

#include <iostream>

template <size_t N>
void swap1( char ( &a )[N], char ( &b )[N] )
{
    char temp[N];

    for ( size_t i = 0; ( temp[i] = a[i] ) != '\0'; ++i );
    for ( size_t i = 0; ( a[i] = b[i] )    != '\0'; ++i );
    for ( size_t i = 0; ( b[i] = temp[i] ) != '\0'; ++i );
}    

int main() 
{
    char s[2][27] = {"wangzhehan", "cuisibo"};

    std::cout << s[0] << '\n';

    swap1( s[0], s[1] );

    std::cout << s[0] << '\n';

   return 0;
}
1 голос
/ 08 ноября 2019

Код:

   char *temp;
[...]
        temp[j] = a[i];

хранит a[i] по любому адресу, который находится в стеке в данный момент (понимаем, для нераспределенной памяти). Это потерпит крах. Если вам нужно что-то поменять на временное, сначала выделите временное для размера минимальной длины строки.

Обратите внимание, что ваш код - очень плохая идея.

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

Если вы действительно хочешь заново изобрести колесо, ты бы сделал что-то вроде этого:

void swap(char *& s1, char *& s2) { char * tmp = s2; s2 = s1; s1 = tmp; }
int main()
{
    char * s[2] = {"wangzhehan", "cuisibo"};
    cout << s[0] << endl;//s[0] can be printed correctly

    swap(s[0], s[1]);

    cout << s[0];
...