Начал читать учебник "Программирование: Введение в профессию" Том №2 "Системы и сети" автора А.В. Столярова, в котором рассматривается язык программирования Си. В теме про указатели и строковые массивы (стр.96) есть небольшой пример реализации процедуры копирования из одной строки в другую. Собственно так выглядит код (на стр.94 есть еще один пример):
void stringCopy(char* dest, const char* src)
{
while ((*dest++ = *src++));
}
Автор настаивает, что в коде есть ошибка. Причем сам пример часто мелькает в интернете в качестве "суперкороткого решения", и автор относится к этому отрицательно. Сам же автор конкретной ошибки не указывает, однако просит разобраться (для себя), лишь намекая на побочный эффект, который легко не заметить.
Вот так выглядит правильный пример кода автора учебника:
while (*src)
{
*dest = *src;
dest++;
src++;
}
*dest = '\0'
Собственно я искал хоть какое-то упоминание о ошибке в этом коде, но никто даже не интересовался, кроме как принципом работы кода. В общем если разобраться в приоритетах операций - все становится на свои места (я так сначала думал с разгону):
1.Оказывается что постфиксный инкремент/декремент имеют отличную от префиксных аналогов реализацию. Что точно уж объясняет работу ошибочного кода. Я проверил он работает 100%. https://ravesli.com/urok-40-inkrement-dekrement-pobochnye-effekty/
#include <stdlib.h>
void stringCopy(char* dest, const char* src)
{
while ((*dest++ = *src++));// почему-то неправильная запись с ошибкой (хотя все работает)
/*
Правильная запись
while (*src)
{
*dest = *src;
dest++;
src++;
}
*dest = '\0';
*/
}
int main()
{
char* src = malloc(15);
char* dest = malloc(15);
*(src + 0) = '\0';
*(src + 1) = 'e';
*(src + 2) = 'a';
*(src + 3) = 'r';
*(src + 4) = '!';
//дальше не продолжал инициализацию - Visual Studio туда помещает
//мусор без нулей
stringCopy(dest, src);
//вот тут я поставил точку останова в дебаггере - мои указатели
//ссылаются на нулевые строки (значит копирование успешно прошло при нулевой строке и значит что ошибка не в операторе постфиксного инкремента)
free(src);
free(dest);
}
2.Наконец вроде бы разобрался с понятием "леводопустимых" выражений (стр 87). Получается, что уникальность реализации постфиксных инкремента и декремента имеет прямую связь с этим понятием "леводопустимости"? Или это отдельно? Чтобы уже разобраться совсем совсем.
В итоге не понятно, есть ли там ошибка или нету. Получается что проблема в наглядности этого кода и лучше писать все красиво по полочкам, ибо никогда не знаешь что стукнет в голову компилятору или сложно анализировать код? А ошибка придумана - чтобы сломать мозг тому кто будет ее искать и привести его к этому выводу?
Upd: ошибки там нет. Ошибка была в примере на стр. 94 (по видимости автора ошибкой является то, что длина высчитывается с учетом знака окончания строки, хотя это даже не правило). Просто мне показалось из-за стиля его заметок в виде крестика, что там тоже должна быть ошибка. Просто автор пытался показать, что так делать не стоит. Компактность кода в этом случае приводит к сложности понимания происходящего.
Upd: продолжив дальнейшее изучение книги я наткнулся на стр.100-103 параграф "Точки следования (sequence points). У меня конечно нет столько опыта, хотелось бы услышать имеет ли место в данной ситуации то, о чем там говорится. Ну и так как никто не ответил о "леводопустимых выражениях" - может и о них кто-то скажет в данной ситуации.
stringCopyнедостаточно, нужно ещё и подсчитать размер исходной строки (а это ещё один пробег по ней, если только размер не хранится отдельно). – VladD Mar 17 '22 at 11:48