Результат вызова strcpy отличается от ожидаемого

#include <stdio.h>
#include <string.h>

int main()
{
   char src[]="123456";
   strcpy(src, &src[1]);
   printf("Final copied string : %s\n", src);
}

Когда я использую компилятор Visual Studio 6, он дает ожидаемый ответ "23456".

Почему эта программа печатает "23556" при компиляции с gcc 4.7.2?


person Blood-HaZaRd    schedule 18.12.2014    source источник
comment
поведение undefined, вместо этого используйте memmov()   -  person Peter Miehle    schedule 18.12.2014
comment
как вы пришли к тому факту, что это перекрытие? &Src[1]=23456 правильно !?! так где перебор?   -  person Blood-HaZaRd    schedule 18.12.2014
comment
@PeterMiehle Да, memmov плюс дополнительный e.   -  person Jite    schedule 18.12.2014
comment
src распадается на указатель на первый элемент массива src. &src[1] — указатель на второй элемент массива. Поскольку исходная строка не имеет длины 0, они явно перекрываются.   -  person Deduplicator    schedule 18.12.2014
comment
это означает, что я должен скопировать из другой строки char dest[]="123456"; и сделать strcpy(src, &dest[1]);   -  person Blood-HaZaRd    schedule 18.12.2014
comment
src = источник = от, dst = пункт назначения = до   -  person Peter Miehle    schedule 18.12.2014
comment
Я спрашиваю себя после того, как снова прочитал ваш вопрос: каков ожидаемый ответ на неопределенное поведение? Как можно ожидать хоть какого-то ответа?   -  person dhein    schedule 06.01.2015


Ответы (3)


strcpy(src, &src[1]); - это неопределенное поведение:

C11 §7.24.2.3 Функция strcpy

Функция strcpy копирует строку, на которую указывает s2 (включая завершающий нулевой символ), в массив, на который указывает s1. Если копирование происходит между перекрывающимися объектами, поведение не определено.

Кстати, memcpy похож (но не memmove). См. Часто задаваемые вопросы по C: в чем разница между memcpy и memmove.

person Yu Hao    schedule 18.12.2014
comment
Хм... похоже на проблему memcpy и memmove. - person legends2k; 18.12.2014
comment
Где вы находите эти сведения? И как вы их так быстро находите? ИЛИ вы написали свою собственную книгу :D? - person Rizier123; 18.12.2014
comment
Таким образом, это означает, что компилятор VS настроен на неопределенное поведение, или у кодера была неопределенная рефлексия для написания такой линии? - person Blood-HaZaRd; 18.12.2014
comment
@Rizier123 Rizier123 У меня есть копия черновика стандарта C поблизости, если вы об этом спрашиваете :). См. Где найти текущие стандартные документы C или C++?. - person Yu Hao; 18.12.2014
comment
@ Rizier123: В моей системе это описано на справочных страницах glibc (man 3 strcpy): строки не могут перекрываться. - person Witiko; 18.12.2014
comment
@Blood-HaZaRd: это неопределенное поведение, реализация может делать все, что ей заблагорассудится. - person Witiko; 18.12.2014
comment
Даже в K&R (ANSI) C 1988 года есть это в первом абзаце Приложения B3 относительно строковых функций. Любая правильная книга C документирует это. - person JohnH; 18.12.2014

Это неопределенное поведение. Вместо этого используйте функцию memmove. memmove позволяет перекрывать исходный и целевой буферы.

memmove(src, &src[1], strlen(&src[1]) + 1) ;  // + 1 for copying the terminating zero
person Jabberwocky    schedule 18.12.2014
comment
Да, память перекрывается. - person Iharob Al Asimi; 18.12.2014
comment
Вместо неловко выглядящего &src[1] вы можете использовать src+1 для ясности. - person Jongware; 18.12.2014
comment
@Jongware, вы правы, но я намеренно оставил его таким же, как в исходном вопросе. - person Jabberwocky; 18.12.2014

Из ISO/IEC 9899:TC3 (c99)

7.21.2.3 Функция strcpy

Синопсис

1

#include <string.h>

char *strncpy(char * restrict s1, const char * restrict s2, size_t n);

Описание

2 Функция strcpy копирует строку, на которую указывает s2 (включая завершающий нулевой символ), в массив, на который указывает s1. Если копирование происходит между перекрывающимися объектами, поведение не определено.

Итак, то, что вы делаете, просто не определено;)

Вы также можете ознакомиться с ПРИЛОЖЕНИЕМ J.2

Указание случаев неопределенного поведения с примечанием о том, как предотвратить:

Поведение не определено в следующих обстоятельствах:

[...]

- сделана попытка скопировать объект в перекрывающийся объект с использованием библиотечной функции, отличной от явно разрешенной (например, memmove) (раздел 7).

person dhein    schedule 18.12.2014