Your example works because you are passing the address of your variable to a function that manipulates its value with the dereference operator.
While C does not support reference data types, you can still simulate passing-by-reference by explicitly passing pointer values, as in your example.
The C++ reference data type is less powerful but considered safer than the pointer type inherited from C. This would be your example, adapted to use C++ references:
void f(int &j) {
j++;
}
int main() {
int i = 20;
f(i);
printf("i = %d\n", i);
return 0;
}