str - указатель (т.е. переменная для хранения адреса), в ней мусор,
т.к. ничего разумного в нее не успели положить. Тогда как tmp_line
- это уже реальный блок памяти длиной MAXLINE, куда можно что-то
писать. Поэтому писать по адресу из str до тех пор, пока она не проинициализирована, нельзя - запись произойдет в случайное место памяти. Но если предварительно написать:
str = tmp_line;
то str и tmp_line станут эквивалентными и тогда писать по str станет возможно. Однако компилироваться будут всё равно по-разному, т.к. tmp_line - адресная константа, а str - адресная переменная (адрес из нее еще доставать надо).
Т.е. разница между ними в точности такая же, как между числовой константой и числовой переменной, только предназначены они для задания адресов.
Переменная для хранения адреса обычно используются, когда блок памяти аллокируется динамически:
str = malloc(число_байт);
в случаях, когда объем памяти на стадии компиляции еще не известен, но станет известен в процессе работы программы.
Или в случаях, когда этот указатель инкрементируют в цикле.
P.S. До тех пор, пока еще путаетесь с указателями, советую ставить пробел в другом месте:
char* str;
Тогда на интуитивном уровне станет ясным, что str - переменная, но не для хранения символов, а для хранения адресов, указующих на память, где лежат символы (= указатель на символ).
И не забывайте такие указатели инициализировать, т.е. они, подобно переменным, вначале содержат мусор.