All function arguments in C are passed by value.  That means that the parameter (in this case, x defined in add) is initialized to a copy of the value of the argument (in this case, y, which has the value 3).
Since x is a local variable, executing
x = x + 1;
changes the value of x, but that change has no effect after the function returns and x no longer exists.
Note that the argument doesn't have to be the name of a variable. You can legally call your function like this:
add(42);
x is initialized to 42 -- but x = x + 1 certainly isn't going to change the value of 42.
If you want to modify the value, you can have the function return the new value:
int add(int x) {    
    return x + 1;
}
The caller can do anything it likes with the result, including assigning it back to the variable:
int y = 3;
y = add(y);
Or you can pass the address of the object you want to modify:
int add(int *x) {
    *x = *x + 1;
}
and then the caller can do this:
int y = 3;
add(&y);
This is still pass-by-value, but the value being passed is a pointer value, the address of x. It's how we can emulate pass-by-reference in C.