Wasya UK, снова неверно. Код int *arr производит определение указателя на память с предположительным типом int.
У тебя нигде нет определения массива. Есть указатель на память, в которой может быть какой-то произвольный массив или просто единичное значение. И узнать это из указателя возможности у тебя нет.
Теперь давай снова вернемся к коду int *arr = {}. Что в точности означает = {} в этом коде?
Wasya UK, нет. Там нет присвоения пустого массива.
Часть = {} выполняет сразу две операции.
Первая операция находится в коде {} - это формирование пустого списка инициализации [?]. Эта операция сводится к формированию local temporary [?] с типом int* и инициализации этого temporary local методом default initialization [?], который для данного типа сводится к методу zero initialization [?].
Результатом Zero initialization для int* будет nullptr.
Вторая операция находится в коде = и выполняет инициализацию определенного arr значением ранее выведенного temporary local и с использованием метода copy initialization [?].
Все вместе это сводится к инициализации arr методом zero initialization.
У тебя в функции нет массивов. У тебя там есть только указатель, который по умолчанию инициализируется в nullptr и без проверки поступает в область разыменования. Это все приводит к неопределенному поведению [?].
Wasya UK, неуверенность - это тоже хорошо.
Теперь у тебя есть лишний повод сходить в документацию и изучить механизм его работы. Изучение документации позволяет поднимать уверенность в своих знаниях.
Range-based for-loop использует std::begin и std::end для определения границ итерирования. Голый указатель на память неизвестного размера принципиально не способен дать информацию ни о начале диапазона итерирования, ни о его конце.
Тебе стоит использовать std::span[?] если ты пишешь в стандарте C++20. Иначе для тебя будет лучше найти или создать аналог std::span если ты хочешь использовать именно range-based for-loop в коде.