Calling a pointer a reference (as Java and Javascript do) is a completely different use of the word reference than in pass-by-reference. C does not support pass-by-reference. Here is your example re-written to show that it not really passing a value by reference, only a pointer by value.
#include <stdio.h>
void f(int *j) {
int k = (*j) + 1;
j = &k;
}
int main() {
int i = 20;
int *p = &i;
f(p);
printf("i = %d\n", i);
printf("j = %d\n", *p);
printf("i(ptr) = %p\n", &i);
printf("j(ptr) = %p\n", p);
return 0;
}
Here is the output
i = 20
j = 20
i(ptr) = 0x7ffdfddeee1c
j(ptr) = 0x7ffdfddeee1c
As you can see, the value stays the same, but more importantly the pointers don't change either. However, C++ allows pass by reference. Here is the same example put through a C++ compiler but with and added ampersand in the header which makes this a reference parameter.
#include <stdio.h>
void f(int *&j) { // note the & makes this a reference parameter.
// can't be done in C
int k = (*j) + 1;
j = &k;
}
int main() {
int i = 20;
int *p = &i;
f(p);
printf("i = %d\n", i);
printf("j = %d\n", *p);
printf("i(ptr) = %p\n", &i);
printf("j(ptr) = %p\n", p);
return 0;
}
Here is the output
i = 20
j = 21
i(ptr) = 0x7ffcb8fc13fc
j(ptr) = 0x7ffcb8fc13d4
Note that we were able to change the actual pointer!
Just as a reference The Dragon Book is a classic Computer Science text book on compilers. Because it's the most popular compiler book ever (or at least it was when I was in college, maybe I'm wrong), I would guess that the vast, vast majority of people who design languages or write compilers leaned from this book. Chapter 1 of this book explains these concepts very clearly and explains why C is pass-by-value only.