If you put a definition char *str;
inside a function, then it's an automatic variable of type "pointer-to-char
".
It's located on the stack, and that part of the stack becomes unused when the function returns (the compiler handles this for you by emitting code to move the stack pointer as necessary). In theory the existence of a stack is purely an implementation detail, in practice C always has a call stack, almost all implementations manage that more or less the same way, and however it is actually managed, the memory in which automatic variables is stored is liable to be referred to as "the stack".
If you put a definition char *str;
outside any function, then it's a global variable with static storage duration.
It is stored in a read-write data segment, and becomes unused when the program exits (probably the OS handles this for you, although it could in principle be code emitted by the compiler). Since it is zero-initialized (and assuming an architecture on which a null pointer is represented by all bits zero) yes, it can go in the bss segment, which is specifically for zero-initialized read-write objects with static storage duration. Again, the details of how objects of static duration are stored is up to the implementation but again, this is how its generally done.
None of this has anything to do with string literals being unmodifiable, because you haven't defined a string (let alone used a string literal). You've defined a pointer, which could point to a string but does not (yet) do so.