Ниже приведено пошаговое объяснение того, что делает код и как изменяется значение переменных. Я рекомендую вам использовать отладчик и пошагово код и проверять каждую переменную после каждого шага.
Но вот оно:
// Define two int variables (i and j) and two int-pointer variables (p and q)
int i, j, *p, *q; // i: uninitialized j: uninitialized p: uninitialized q: uninitialized
// Assign 10 to i
i = 10; // i: 10, j: uninitialized, p: uninitialized, q: uninitialized
// Make p point to j
p = &j; // i: 10, j: uninitialized, p: points to j, q: uninitialized
// Allocate some memory for q
q = malloc(sizeof(int)); // i: 10, j: uninitialized, p: points to j, q: points to uninitialed memory
// Assign i to the memory that q points to
*q = i; // i: 10, j: uninitialized, p: points to j, q: points to memory containing 10
// Assign i to j
j = i; // i: 10, j: 10, p: points to j, q: points to memory containing 10
// Make q point to the same as p
q = p; // i: 10, j: 10, p: points to j, q: points to j
// Assign 5 to the memory that q points to (which is j)
*q = 5; // i: 10, j: 5, p: points to j, q: points to j
// print i (10), j (5), the memory p points to (j aka 5), the memory q points to (j aka 5)
printf("%d %d %d %d", i, j, *p, *q); // Print 10 5 5 5
Примечание:
q = p;
представляет утечку памяти, так как больше нет указателя на динамически выделенную память.