c1 is a local pointer, so it must be on the stack;
Right. Although it can also be allocated in the CPU register.
c2 - static pointer, it must be on the heap;
Not. A variable declared as static, or a variable declared as global ("file scope"), has something called a static storage duration. This means that before calling the program, they must be initialized to a known value. If the programmer does not explicitly initialize them, the compiler ensures that they are set to zero.
To simplify static initialization, all such objects of static storage duration are usually placed in a separate, allocated part of RAM, often called .bss . It is unlikely that .bss will be pushed onto the stack.
c3 is on the heap.
The actual C3 pointer is on the stack, but the contents it points to are on the heap. The only variables that are on the heap are those that you dynamically allocate using malloc (). Nothing else exists.
My guess and schedule are right?
C1 is correct, the pointer points to the string literal rodata, which is stored in a read-only section in memory.
C2 is invalid because it is in .bss. It points to the string literal rodata, though, as in your graph.
C3 is invalid. When you strcpy () something, you make a hard copy of the string literal in rodata and store that copy on the heap in the area that C3 points to. C3 itself is on the stack.
EDIT: Not sure if this chart is worth it, but here you go.
stack .bss rodata heap | | | | | | | | | c1 |-------------->| "abc" | | | | | | c2 |--->| "abc" | | | | c3 |----------------------------->|abc | | | | | | | | |