Нет портативного способа обнаружить это. Вы должны сделать сравнение указателей, и они определены только в пределах одного и того же объекта. То есть если две строки не перекрываются и фактически являются разными объектами, тогда сравнение указателей дает вам неопределенное поведение.
Я бы позволил стандартной библиотеке справиться с этим, используя memmove(a, b, strlen(b) + 1)
.
EDIT:
Как отметил Стив Джессоп в комментариях, на самом деле существует портативный, но медленный способ обнаружения перекрытия в этом случае. Сравните каждый адрес в пределах b с первым и последним адресом a на равенство. Сравнение равенства с ==
всегда четко определено.
Итак, у вас есть что-то вроде этого:
l = strlen(b);
isoverlap = 0;
for (i = 0; i <= l; i++)
{
if ((b + i == a) || (b + i == a + l))
{
isoverlap = 1;
break;
}
}
РЕДАКТИРОВАТЬ 2: Визуализация дела 2
У вас есть что-то вроде следующего массива и указателей:
S t r i n g 0 _ _ _ _ _ _ _
^ ^
| |
b a
Обратите внимание, что b + strlen(b)
приводит к указателю на завершающую \ 0. Начните один позади, иначе вам понадобится дополнительная обработка крайних случаев. Указатели там действительны, вы просто не можете разыменовать их.
src = b + strlen(b) + 1;
dst = a + strlen(b) + 1;
S t r i n g 0 _ _ _ _ _ _ _
^ ^ ^ ^
| | | |
b a src dst
Теперь цикл копирования, который также копирует \ 0.
while (src > b)
{
src--; dst--;
*dst = *src;
}
Первый шаг дает это:
src--; dst--;
S t r i n g 0 _ _ _ _ _ _ _
^ ^ ^ ^
| | | |
b a src dst
*dst = *src;
S t r i n g 0 _ _ _ 0 _ _ _
^ ^ ^ ^
| | | |
b a src dst
И так до тех пор, пока src
не станет равным b
:
S t r i S t r i n g 0 _ _ _
^ ^
| |
b a
src dst
Если вы хотите, чтобы это было немного более хакерским, вы можете сжать его дальше, но я не рекомендую это:
while (src > b)
*(--dst) = *(--src);