EDIT: Your code is an example of an Undefined Behaviour, but I will try to explain in detail why my computer outputs the same as your second output.
The following code in my computer gives your second output, which is what makes the most sense.
#include <stdio.h>
int main(int argc, char* argv[])
{
char a = 0, b = 0;
int* p = (int*)&b;
*p = 258;
//printf("%d %d\n%p %p\n", a, b, &a, &b);
printf("%p %p\n%d %d\n", &a, &b, a, b);
//printf("%p %p\n", &a, &b);
//printf("hd\n");
//printf("%p %p\n", &a, &b);
}
Outputs:
&a=0x7ffe2c4f7bde &b=0x7ffe2c4f7bdf
a=0 b=2
Assuming big endianness, bytes are read from left to right in ascending value order. If you declared first a and then b, then the memory of a is located at the right of b (depending on the compiler it might be reversed, but I will try to explain my computers behaviour), diagramatically:
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| b | a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
if you cast the pointer to b as an int, then the compiler will think you have 4 bytes instead of one at the left of a, and will write to it.
258 in binary is 0b100000010, so only the last 8 bits of this fall into the char range that b reads, which would be 0000 0010, which is 2. This is why a stays zero.
A cool way to test this is declaring another char c after b, and checking how after executing the same program, c is 1 because it is located at the inmediate left of b and *p = 258 would have written the first bit of c to 1.
Here's what I mean:
#include <stdio.h>
int main(int argc, char* argv[])
{
char a = 0, b = 0, c = 0;
int* p = (int*)&b;
*p = 258;
printf("&a=%p &b=%p\n &c=%p a=%d b=%d c=%d\n", &a, &b, &c, a, b, c);
}
Outputs:
&a=0x7ffc6ce4943d &b=0x7ffc6ce4943e
&c=0x7ffc6ce4943f a=0 b=2 c=1