A good idea if you want to know how this all works is to run your application in a debugger. It's really cut's the crap to figure out what's going on.
Any debugger is OK, however I know windbg best so here's some pointers on where to get started at a slightly modified version of your code, like Greg suggested, you need an int*.
CHANGE:
char *x = &x4;
TO:
int *x = &i;
DELETE:
x = &x4;
MOVE(first variable, before x1):
int i;
NEW CHANGE(much easeir to read, and doing as previously (x-i) is random/not currently in-scope values):
printf("%02d: %08x : %08x\n", i, x + i, *(x + i));
This change will show effectivly the stack-frame address and the value.
In windbg, get the calls, memory, threads and command windows up so you can see them all.
Compile your C code with a compiler, I used MSVC (you can get it for trial for free), compile with the "Visual Studio 20## Command Prompt" with "cl /Zi your.c". Load up Windbg (debugging tools for Windows), press Ctrl+E or use "open executable".
Load the following windows so you can see them all at one time, Calls, Locals, Memory, Threads and Command.
At the command window, put a breakpoint on your DoTestStack with "bu DoTestStack".
start debugging with "g" command.
After you get to the breakpoint, use "p" to single step, you should get the source popped up also, or you can watch the output of your application, after it's running in the for loop, go back to Windbg. Get the memory window up and set it to "Pointers and Symbols" for an address type in "i", it should have the debug information from the compile (/Zi) and will give you a listing of "Pointers and symbols" starting from a pointer to the address of i.
The output should be identical to the test code (after you do the changes I suggested), if you continue to hit p, you will see also that in the memory window you can observe the value for i changing per execution, however as the printf is now printing other values, you will simply see it at the original "0" on the output ;).
You can alternativly use the windbg command dds (note the value for i is 0xb as it's in the middle of the for loop)
0:000> dds i
0018ff24 0000000b
0018ff28 02586bf9
0018ff2c 0018ff24
0018ff30 0018ff38
0018ff34 00401118 a!TestStack+0x8 [c:\temp\a.c @ 33]
0018ff38 0018ff40
0018ff3c 00401128 a!main+0x8 [c:\temp\a.c @ 35]
0018ff40 0018ff88
0018ff44 00401435 a!__tmainCRTStartup+0xf8 [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 257]
0018ff48 00000001
0018ff4c 003c1e48
This is identical (exept no symbol support) as the modified test code;
00: 0018ff24 : 00000000
01: 0018ff28 : 02586bf9
02: 0018ff2c : 0018ff24
03: 0018ff30 : 0018ff38
04: 0018ff34 : 00401118
05: 0018ff38 : 0018ff40
06: 0018ff3c : 00401128
07: 0018ff40 : 0018ff88
08: 0018ff44 : 00401435
09: 0018ff48 : 00000001
10: 0018ff4c : 003c1e48