Yes, everything* in C is passed by value, which means that copies of arguments are passed to function - that's the only way of passing values to functions. "Pass by pointer" (or "reference") doesn't really exist - it's still "passing by value", where "value" is pointer. Pointers are values after all.
Linguistic note: when we say "could you pass me some sugar please" we expect someone to temporarily transfer possession of sugar bowl to us, so at any moment of time there's only one sugar bowl. In other words, we expect sugar bowl to be moved to us. That's not the case in programming. "Passing" in this context means merely "associating parameters with function being called", and doesn't necessarily involve moving. That's why we differentiate between "pass-by-value", "pass-by-reference", "pass-by-name" etc.
Example:
/* I have 2 apples, 3 oranges and one pear */
int apple = 2;
int orange = 3;
int pear = 1;
/* Apples are my favorite fruit */
int *my_favorite_fruit = &apple;
void no_eat_fruit (int fruit) {
/* Does not work, "fruit" is copy, so changes to it have no effect outside function */
fruit--;
}
no_eat_fruit(apple);
/* No apples have been eaten at this point */
void eat_fruit(int *fruit) {
/* Here, "fruit" is copy, but "*fruit" refers to original object */
*fruit--;
}
eat_fruit(&apple);
eat_fruit(my_favorite_fruit);
/* I have no apples left */
/* Let's change my mind, now I like oranges */
void no_change_my_mind(int *favorite) {
/* Doesn't work, "favorite" is copy, so changes to it have no effect outside function */
favorite = &orange;
}
no_change_my_mind(my_favorite_fruit);
/* I still like apples, LOL! */
void change_my_mind(int **favorite) {
/* In order to change pointer, we have pass pointer-to-pointer.
Here, "favorite" is copy, but "*favorite" points to original pointer */
*favorite = &orange;
}
change_my_mind(&my_favorite_fruit);
*
with exception to arrays. Arrays "decay into pointers" when passed into function.