It's actually a bit of a leading question, because it presumes that everything will be in memory.
Local variables, as well as temporary values without a name, are only placed on the stack if necessary. There are different reasons why that might be necessary, for example:
- The compiler is dumb or made to act dumb by compiling at the lowest possible optimization level.
- The target machine has an odd architecture without (or very few) registers (rare).
- There are too many local variables and temporary values live simultaneously to fit them all into registers at that point in the program, so some of them get "spilled". Being spilled is not a property of a variable exactly, but rather of a specific live range. In some sense a variable can therefore move around (if it has multiple associated live ranges and they get allocated differently) and even be in multiple places simultaneously (depending on how you count temporary copies, or unambiguously when loop unrolling is involved).
- The address of the local variable is taken and used in such a way that the compiler cannot prove that the variable does not need to be in memory (may induce live range splitting so the variable is only actually in memory temporarily).
Most likely none of the above apply (the last item definitely does not apply, the address is not taken) so we should expect cPtr
to spend its entire lifetime in registers.
Testing it out on clang targeting x64 we might get code like this:
main: # @main
push rbx
mov edi, 23
call malloc
mov rbx, rax
; at this point, rbx roughly corresponds to cPtr
; it's also still in rax but rax is overwritten by the next operation
movabs rax, 32777976875610985 ; btw this weird number is a piece of string
mov qword ptr [rbx + 15], rax
movups xmm0, xmmword ptr [rip + .L.str]
movups xmmword ptr [rbx], xmm0
; rbx (cPtr) is copied to rdi in order to give it to puts as argument
mov rdi, rbx
call puts
mov rdi, rbx
call free
xor eax, eax
pop rbx
ret
.L.str:
.asciz "Good luck on this test"
Targeting MIPS or ARM or PowerPC with eg GCC shows a similar pattern of cPtr
not being on the stack but in a register (or several registers, depending on how you count), though of course the code looks pretty different.
A fun detail of the code above is that while the entire string does appear in a data segment (rodata), a piece of it also appears in the code segment as the immediate operand of that movabs
.