ошибка сегментации во время memcpy

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

Когда я пытаюсь скопировать перевернутую подстроку обратно в исходное место, я получаю

Программа получила сигнал SIGSEGV, ошибка сегментации. 0x00007ffff7b5dc66 в ?? () из /lib/x86_64-linux-gnu/libc.so.6

Любая помощь будет потрясающей!

Вот что у меня есть до сих пор:

void reverse(char* line, int start, int end){

      char str[end-start];

      memcpy ( str , line + start , end-start );

      reverseSubString ( str );

      memcpy ( line + start, str , end-start );

}

void reverseSubString(char* str){

    int i, j, len;
    char temp;

    i=j=len=temp=0;

    len=strlen(str);

    for (i=0, j=len-1; i<=j; i++, j--)
    {
        temp=str[i];
        str[i]=str[j];
        str[j]=temp;
    }
}

person ThomDall    schedule 26.02.2013    source источник
comment
Почему бы просто не перевернуть вашу подстроку на месте, а не копировать ее, переворачивать и копировать? Передайте аргумент длины в reverseSubString вместо использования strlen (который в любом случае является источником вашей ошибки, как указано в ответах ниже).   -  person Jim Balter    schedule 27.02.2013
comment
reverseSubString выполняется без проблем, но я понимаю, откуда вы взялись. Я внес изменения, чтобы включить более надежную длину, но второй memcpy по-прежнему вызывает ошибку сегментации. Первоначально я пытался изменить его на месте, столкнулся с той же проблемой.   -  person ThomDall    schedule 27.02.2013
comment
reverseSubString выполняется без проблем - нет, конечно, нет... не для произвольной последовательности символов, которые не заканчиваются NUL. Первоначально я пытался изменить его на месте, столкнулся с той же проблемой - тогда вы должны были попытаться понять и решить эту проблему, а не добавлять бессмысленные копии туда и сюда.   -  person Jim Balter    schedule 27.02.2013


Ответы (2)


  char str[end-start];

  memcpy ( str , line + start , end-start );

Если не включен 0-терминатор исходной строки, у вас есть массив char, который не заканчивается 0. Так

len=strlen(str);

вычисляет кто-знает-что, если это еще не сбой. потом

for (i=0, j=len-1; i<=j; i++, j--)
{
    temp=str[i];
    str[i]=str[j];
    str[j]=temp;
}

доступ за пределы выделенной памяти.

person Daniel Fischer    schedule 26.02.2013
comment
reverseSubString выполняется без проблем, но я понимаю, откуда вы взялись. Я внес изменения, чтобы включить более надежную длину, но второй memcpy по-прежнему вызывает ошибку сегментации. Первоначально я пытался изменить его на месте, столкнулся с той же проблемой. - person ThomDall; 27.02.2013
comment
В итоге моя строка была объявлена ​​в немодифицируемой памяти! Легко исправить! - person ThomDall; 27.02.2013

reverseSubstring() ожидает строку C с завершением NUL, потому что она вызывает strlen() для переданной строки. Однако вы не можете завершать строку NUL в функции reverse. Либо сделайте это, либо, что еще лучше, передайте аргумент length:

void reverseSubString(char *str, size_t len)
{
    int i, j;
    char temp;

    for (i = 0, j = len - 1; i <= j; i++, j--) {
        temp = str[i];
        str[i] = str[j];
        str[j] = temp;
    }
}

void reverse(char *line, int start, int end)
{
    char str[end - start];
    memcpy(str, line + start, end - start);
    reverseSubString(str, end - start);
    memcpy (line + start, str, end - start);
}
person Community    schedule 26.02.2013
comment
reverseSubString(line+start, end-start) будет иметь тот же эффект... нет необходимости в memcpy и VLA. - person Jim Balter; 27.02.2013
comment
@JimBalter Конечно, но я и не говорил, что это нужно - я просто исправил ошибку. Честно говоря, я даже не задумывался о времени работы кода (т.к. ориентировался на ошибку). Этот код работает, и, в конце концов, я не собирался делать его быстрее (OP также должен беспокоиться о том, чтобы заставить его работать, прежде чем пытаться сделать его быстрым). - person ; 27.02.2013
comment
Дело в том, что было бы хорошо указать, что этот код намного сложнее и подвержен ошибкам (и неэффективен), чем это необходимо, а не просто включать его без комментариев. Что касается того, чтобы заставить его работать, прежде чем пытаться сделать его быстрым - намного проще заставить код работать, когда он не выполняет много ненужных операций. Существует огромная разница между написанием кода, направленного на решение проблемы и, следовательно, не только более простого, но и более эффективного, и возни с кодом таким образом, чтобы сделать его быстрее, но не ориентированным на проблему; Я говорил только о первом. - person Jim Balter; 27.02.2013
comment
for (i = 0, j = len; i < j; i++, j--) выглядит лучше для меня, и по интуиции я бы сказал, что это также экономит ... ;-) Вы также можете безопасно объявить i и j (также) быть size_t таким образом. В любом случае +1 за наиболее подходящий подход, передающий длину обратной функции... - person alk; 27.02.2013
comment
@alk Тот же комментарий для вас, что и для Джима Балтера :) Я не утруждаю себя переписыванием всего кода OP. Он тоже должен приложить усилия. - person ; 27.02.2013
comment
@alk Это не безопаснее, это UB ... на первой итерации str[j] не определена. Что касается ответа H2CO3: опять же, было бы неплохо указать ... - там ничего нет о том, что ОП не нужно прилагать усилий. К нам приходят новички и указывают на проблемы с их кодом, что делает их лучшими программистами, а мир — лучше, особенно если они в конечном итоге зарабатывают на жизнь написанием кода. - person Jim Balter; 28.02.2013
comment
@JimBalter: Ой, да, ты прав... - Прошу прощения за плохое, т.к. неправильный совет. - person alk; 01.03.2013
comment
@alk Это работает, если вы decr j перед обменом, а не после, но это не так хорошо согласуется с синтаксисом C for. - person Jim Balter; 01.03.2013