0

From Why does scanf() require &?, it is mentioned that

all arguments in C are passed by value.

void change( int * var ) {
    // Here, var is a pointer to the original number. var == &value
    // Writing to `*var` modifies the variable the pointer points to
    *var = 1337;
}

Could I write instead

void change( int * var ) {
    // Here, var is a copy of a pointer that happens to point to the same memory block as the original pointer. var == &value
    // Writing to `*var` modifies the variable the pointer points to
    *var = 1337;
}

Assuming

int main() {
    int value = 42;
    change(&value);
    return 0;
}

Nothing can be passed in C is a correct statement using the conventional meaning of "pass". Is my understanding sound?


My question rephrased is: Can anything truely be passed in C (the conventional use of "pass")?

Jonathan Komar
  • 2,678
  • 4
  • 32
  • 43
  • 1
  • 2
    @el.pescado Frankly, I don't see how you could have read anything I wrote and not see my question. – Jonathan Komar Apr 04 '18 at 05:47
  • 2
    @JonathanKomar No, it's not clear since you have answered your own question (even posted a link to another question here on SO that gives you the same answer). :P – rbaleksandar Apr 04 '18 at 05:48
  • Try reading it like a human rather than a machine. Provide an instructional answer. I have not answered my own question. I still do not know whether [fill in question title here] which would follow that "But are two pointers really created?" – Jonathan Komar Apr 04 '18 at 05:50
  • 1
    Your "if I may lazily borrow" example refers to `&value`, but it does not show where `&value` is defined. This causes disorientation. You then have a "Would it … be fair to say …" paragraph that discusses `int *var` and a copy of `*var`, and it is not clear what that `int *var` refers to, or the `*var`. The `change()` example isn't clearly hooked into your question. You might be assuming people will look at and remember the content of the other question — that is a bad assumption to make. Your question should be complete as a standalone question. The tail end of it is not fully coherent. – Jonathan Leffler Apr 04 '18 at 05:54
  • 2
    The basic answer is "Yes" — that is, all function arguments are copies of something, either a value or a pointer. – Jonathan Leffler Apr 04 '18 at 05:55
  • As per my understanding. at the bottom line. Yes all the arguments passed by reference of the value between function calls. When Function `FuncA` calls `FuncB(A,B)`, which means `FuncA` push the values of `A & B` to stack and calls the `FuncB`, which copies value from stack to process further. – ntshetty Apr 04 '18 at 05:59
  • 3
    So many words with so few meaning.... All it boils down to is. Does C pass by value? And yes it does. Please be brief with your question and dont try to sound bold, it just makes it difficult to understand what you really want. – Kami Kaze Apr 04 '18 at 06:06
  • And what do you mean with `are two pointers really created?` There are two variables `value` in `main`and `var`in `change` they are completly independend from each other. You could for example change `var` and it would not affect `value` – Kami Kaze Apr 04 '18 at 06:12
  • 2
    It is not a generalisation. Using more words does not change the question. Every function gets a copy of the parameters, that is not a generalisation. That's just how it is. At least in C. – Kami Kaze Apr 04 '18 at 06:17
  • @KamiKaze It is my intention to describe the background of my question and then limit its scope. From my understanding, that corresponds to the rules on StackExchange. Anyway, if ”pass by value“ is unclear as to not answer my question, then your simplified phrase does not carry enough semantic value ie it is an oversimplification of a technical process. Grammar: ”few“ can only be used when the noun that follows is not collective. Furthermore, ”bold“ does not work in the context of your sentence. Bold, however, does work here, as I am bold in correcting your grammatical mistakes ;) – Jonathan Komar Apr 04 '18 at 06:27
  • 1
    My bad. Call it "fancy language" and "little meaning". Still it is not a oversimplification, it is a precise description. If your question is what `pass by value` means, then quite a few seemed to misunderstand your question. All I wanted was telling you that by being brief and more precise in your question, it is easier to answer and help you. – Kami Kaze Apr 04 '18 at 07:01
  • If you would "Star Trek pass" variables to a function, then wouldn't they stop to exist in the caller function? C doesn't work like that, no... – Lundin Apr 04 '18 at 11:40
  • @Lundin Good point. Maybe one of those broken transporter episodes would work better: C is a like a malfunctioning transporter that assembles new particles (bytes) somewhere else but leaves the original particles where they were. Copies of pointers are like particles in quantom entanglement. How’s that? – Jonathan Komar Apr 04 '18 at 13:44

2 Answers2

1

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.

  • You might want to say something about arrays that are not passed by value, but decay into a pointer to their first element. – chqrlie Apr 04 '18 at 06:16
  • @BasileStarynkevitch Thanks, you're right, although I don't think at this general level there's much difference. – el.pescado - нет войне Apr 04 '18 at 06:24
  • 1
    There is a *lot of differences* between variables (which are *names* occurring in source code) and values. At runtime variables do not exist (you only have locations, the compiler forgot the variables), but values do exist. Study the [semantics](https://en.wikipedia.org/wiki/Semantics_(computer_science)) of some programming language (e.g. [R5RS](http://www.schemers.org/Documents/Standards/R5RS/)) – Basile Starynkevitch Apr 04 '18 at 06:26
  • @BasileStarynkevitch I welcome other answers (as does the community, I hope) I’d like your insight here. (afterall, it is about learning and not about checkmarks) – Jonathan Komar Apr 04 '18 at 06:33
  • @el.pescado My question implies; Are things really ”passed“? or just ”copied“? Could you please address this? – Jonathan Komar Apr 04 '18 at 06:35
  • 1
    It depends on what you mean by "passed". I understand "passing" as action of associating function with actual arguments, regardless whether they are copied/referenced/aliased etc. So, I'd say "copies of arguments are passed into function". – el.pescado - нет войне Apr 04 '18 at 06:54
  • @BasileStarynkevitch I'm not arguing that there's no difference. I just think that the difference is not significant when explaining "passing by value". I agree that correct terminology should be used when possible though, so I updated my answer. – el.pescado - нет войне Apr 04 '18 at 06:58
  • The difference is absolutely essential. Variables do not exist at runtime. – Basile Starynkevitch Apr 04 '18 at 06:58
  • @BasileStarynkevitch the same way general relativity is "absolutely essential" but we still teach Newtonian physics at school. – el.pescado - нет войне Apr 04 '18 at 07:01
  • No, I strongly disagree. Even a beginner should know and **think about locations** and should be told that in C **variables do not exist at runtime**. In particular, a pointer could point (and very often is pointing) to a location which is not a variable (e.g. result of `malloc`, or field of some `struct`, or component of some array). Teaching that pointers point to variables is a horrible mistake and confuses even the beginner. – Basile Starynkevitch Apr 04 '18 at 07:04
  • Funny how C answers tend to go "In C, things _always_ work like x. Except..." :) Although in this case, the correct answer is rather "In C, things are _always_ passed by value. Except for arrays, they don't get passed by value. Except when they are passed by value." `typedef struct { int array[666]; } arr_t; ... void func (arr_t look_ma_im_passing_arrays_by_value);` – Lundin Apr 04 '18 at 11:44
0

This question has been racking my brains. I had to prove it. Out of respect for el.pescado's efforts, I am leaving his or her answer as accepted answer.

Code

#include <stdio.h>
#include <stdlib.h>


void copy( int * memoryslot )
{
  /* This does not prove that * memoryslot is a copied pointer */
  printf("copy:              ValueCopied:        %p\n", memoryslot);  /* memoryslot is a ptr    */
  printf("copy: CalculatedPointerAddress:        %p <- Well, it is not. Here is the proof.\n", &memoryslot); /* get address of pointer */
  * memoryslot = 30; /* To prove I can still use a copy to change the original value */
  return;
}

int main(void) 
{
  int memoryslot = 20;
  int * memoryslotPtr = &memoryslot;
  printf("Caller                 Pointer to memory slot\n");
  printf("-------------------------------------\n");
  printf("main:                    Value:        %d\n", memoryslot);
  printf("main:   CalculatedValueAddress:        %p\n", &memoryslot);
  printf("main: CalculatedPointerAddress:        %p <- If * memoryslot were the same, it would be this.\n", &memoryslotPtr);

  /* Pass address, yields same as &memoryslot */
  copy( memoryslotPtr ); 

  printf("main:                    Value:        %d\n", memoryslot);


  return EXIT_SUCCESS;
}

Output

Caller                 Pointer to memory slot
-------------------------------------
main:                    Value:        20
main:   CalculatedValueAddress:        0x7ffee9134c48
main: CalculatedPointerAddress:        0x7ffee9134c40 <- If * memoryslot were the same, it would be this.
copy:              ValueCopied:        0x7ffee9134c48
copy: CalculatedPointerAddress:        0x7ffee9134c08 <- Well, it is not. Here is the proof.
main:                    Value:        30
Jonathan Komar
  • 2,678
  • 4
  • 32
  • 43