У меня есть следующий код:
char arr[6] = "Hello";
strcpy(arr, "Hello mellow");
cout << strlen(arr) << ", " << arr << endl; // 12, Hello mellow
char arr1[] = "Hello";
strcpy(arr1, "Hello mellow");
cout << strlen(arr1) << ", " << arr1 << endl; // 12, Hello mellow
Итак, почему это работает? Почему это не ограничивается? Что бы я ни поставил вместо "Hello mellow", он работает и распечатывает его.
Он работает, потому что strcpy
не проверяет, что целевой массив не меньше, чем исходный. Ваш код вызывает неопределенное поведение, поскольку вы вызываете strcpy
с недопустимыми аргументами, и поскольку поведение не определено, все может случиться; В вашем случае память тихо перезаписывается. Ваша программа также может потерпеть крах.
В общем случае C и C++ не проверяют границы (в отличие от других языков более высокого уровня: Java, PHP, Python, Javascript и т.д.).
Это означает, что если вы попытаетесь сделать strcopy
, скажем, 13- strcopy
строкой, такой как "Hello mellow"
для массива символов, она не будет проверять, был ли данный массив создан с достаточной памятью, чтобы содержать строку. Он просто скопирует данную строку, символ по символу, в указанный указатель памяти.
Что здесь происходит, так это то, что вы пишете в некоторых местах в памяти, к которым вы не должны обращаться; время от времени, эта программа может просто сбой, без каких-либо других признаков, чем: segmentation fault.
Если вы попытаетесь это сделать...
char arr1[8];
char arr2[8];
strcpy(arr1,"Hello mellow");
printf("%s\n", arr1);
printf("%s\n", arr2);
... это очень вероятно (но не на 100%, см. комментарии), вы получите следующий результат:
Hello mellow
llow
Зачем? Поскольку второй char[]
был бы перезаписан данными, которые вы пытались поместить в первый, без наличия достаточного количества зарезервированного пространства для него.
Собственные массивы в C/C++ представляют собой абстракции низкого уровня, которые во многих случаях рассматриваются как указатели на ячейки памяти. Таким образом, при передаче arr
на strcpy
все strcpy
знает адрес arr[0]
. В результате нет возможности проверки границ. Это очень хорошо по соображениям производительности. Программист должен гарантировать, что он/она использует эти низкоуровневые конструкции безопасно, например, используя strncpy
и давая соответствующую границу, или используя std::vector
и проверяя границы в явном виде или используя std::vector::at
проверке границ при доступе к местоположению.
Я думаю, что, поскольку нет проверки времени выполнения или времени компиляции, и если вы Lucky, вы не получите ошибку сегментации;)