20

I'm trying to use pass by reference in C so that the function can modify the values of the parameters passed to it. This is the function signature:

int locate(char *name, int &s, int &i)

However when I try to compile it I get this error that refers specifically to the above line:

error: expected ‘;’, ‘,’ or ‘)’ before '&' token

If I remove the '&' the program will compile, but it will not function correctly, obviously. What's wrong here? How can I make call by reference work?

neuromancer
  • 53,769
  • 78
  • 166
  • 223
  • 7
    Why do you think pass by reference should work in C? C does not have pass by reference. – Alok Singhal Dec 17 '09 at 05:54
  • 5
    Sure it does. It just calls its references "pointers". – Crashworks Dec 17 '09 at 05:58
  • 9
    "pointers" are not "pass by reference". Whatever you pass to a function in C, it's passed by value. It can happen that the thing that's passed is a pointer, in which case, the function receives a *copy of the pointer*, and can use that copy to change the value pointed to by the pointer, but the pointer itself is passed by value. – Alok Singhal Dec 17 '09 at 06:05
  • 12
    Pure semantics, Pass by reference is the method of passing an address, not the nitty gritty of how the language deals with it. – Gary Willoughby Dec 17 '09 at 15:11
  • One reference that made me go looking for this situation comes from Matlab's External Interface API where I read the section... _C functions often return data in input arguments passed by reference. MATLAB creates additional output arguments to return these values. Note that in the listing in the previous section, all input arguments ending in Ptr or PtrPtr are also listed as outputs._ I too didn't realize '&' was strictly a C++ bit of syntax. – jxramos Jul 16 '15 at 00:51
  • Should this be closed as a duplicate of [Passing by reference in C](https://stackoverflow.com/questions/2229498/passing-by-reference-in-c) which is about the same age but has significantly more views and score? – TylerH Oct 11 '22 at 13:46

7 Answers7

38

C does not have references. You need to pass a pointer to the variable you wish to modify:

int locate(char *name, int *s, int *i)
{
    /* ... */

    *s = 123;
    *i = 456;
}

int s = 0;
int i = 0;
locate("GMan", &s, &i);

/* s & i have been modified */
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • what do you mean with "doesnt have references". you clearly are using & reference operator `locate("GMan", &s, &i);`. be more explicit. – vincent thorpe Jan 29 '20 at 01:14
  • Though C++ and Rust use `&` for references, C *doesn't actually have* references -- it *only* has pointers. In C++, `&` means "give me a reference to this". C, `&` means "give me a *pointer* to this (i.e., give me this thing's address in memory)". As a result, you can't declare a reference: `int &x = &i;` is valid C++ but is invalid C (it must be `int *x = &i;`). You also can't have a reference parameter in a function: `foo(int &x)` is valid C++ but is invalid C (it must be `foo(int *x)`). – 6equj5 Feb 04 '21 at 20:19
  • E.g. ´*s´ **is** a reference – Sam Ginrich Feb 27 '22 at 13:59
22

C has no reference variables but you can consider reference as const pointer to data so ,

Make const pointer to data like this so that pointer cant point to other data but data being pointed by it can be changed.

int  locate (char *name,  int  * const s, int * const i)
Ashish
  • 8,441
  • 12
  • 55
  • 92
7

C does not support pass by reference. You'll need C++ to do it the way it is written, or modify into

int locate(char *name, int *s, int *i)

and pass pointers to the second and third parameter variables.

wallyk
  • 56,922
  • 16
  • 83
  • 148
3

The earlier answers given seem to be missing context, and don't address the property that C pointers are overloaded. It's completely fair to claim that C "passes by reference." A pointer is a reference, too. However, more formally, a C "reference" is the mechanism to represent a symbol's memory address.

  • A pointer is simply a variable in memory whose value is treated as an address.
  • A reference is simply the value-literal for a memory address.
  • The C language allows for passing by reference - but only in the right context!

The separation of context is that of signature definition and signature invocation.

Consider the primitives int a = 0x22e8; and somewhere else we declare int* b = &a; (I'll get to functions in a minute).

We could visualize this in memory (assume endianness doesn't matter for this example):

...
0x00000200:        22e8        ; this is the variable for int a's literal value:
                               ; a == 0x000022e8
                               ; &a == 0x00000200
0x00000???:        9090        ; ... more code ...
0x00000400:        0200        ; this is pointer b pointing to a's address:
                               ; b == 0x00000200
                               ; *b == 0x000022e8
                               ; &b == 0x00000400
...

It's easy to see that we can assign a pointer to any address without any special tricks. A pointer is just a variable, but C allows us to reference the address it's pointing to; we can "dereference" the pointer from its value-address to instead treat the pointer as its pointee's underlying value during an invocation context: while ( *b == a ) .... We could easily invoke b == &a.

When applying this to function calls, you have to separate the context of function (signature) definition vs invocation in order to differentiate pass by reference.

int* foo(int* blah, int nah) { .. }     // signature definition context:
                                        // These are parameters
... vs ...

b = foo( &a, 4);                        // invocation context:
                                        // These are arguments

In defining a function signature, we are not telling the compiler which address an argument is accessed from — the runtime doesn't even know yet! It's just nonsense to define void bar(int &blah) {...}. Instead we use the dereferenced pointer syntax — "whatever argument is passed in will be loaded at the address pointed to" — to reference the desired argument value when runtime occurs. Thus C can pass arguments by reference.

The contexts of both function signature definitions and function calls change how the compiler looks at pointer overloading vs reference, and how the runtime can actually address them.

Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
ToFue
  • 75
  • 5
  • To be clearer, an actual C "reference" syntax is the ampersand syntax: `&a`.And also "pass by reference," the `b = foo(&a,4)`, occurs at runtime during function call execution; and signature definition, the `int* foo(int* a, int nah){..}` is the setup to allow the reference passing. – ToFue Jul 05 '17 at 04:01
  • More precisely "When p is a pointer then *p is a reference". This follows, when we embed the C grammar into C++ terminology. – Sam Ginrich Feb 27 '22 at 14:02
2

You can't do this in c. c doesn't have reference, you can use pointer instead.

Raymond
  • 744
  • 5
  • 12
2

If you wish to use pass by reference method to modify a parameter used in function call, always use pointers as formal arguments of function.

Hence instead of using this

int locate(char *name, int &s, int &i)

use,

int locate(char *name, int *s, int *i)

When you will call this function, you may use

.........

int a=5;
int d=10;
char c='A'; 
int result;

result=locate(&c, &a, &d);

I hope all would be clear now,

For more idea about passing by value or passing by reference and which one is better, this source is good for beginners

http://www.learnc.net/call-by-reference.php

Have fun.

1

(I am have been using C for a while but I am pretty still new to few concepts in C. I am trying to answer this to the best of my knowledge, feel free to correct me If I am wrong)

When you say pass by reference you pass the address, and do to so you would use pointers pointing to the addresses. So you need to pass the pointers to your function prototype but what you are doing is passing address directly.

What your function tries is de-reference(using &) your pointer, but you never had a pointer to parameters 's' and 'i' to de-reference it.

The right way to do for the function prototype/definition is

int locate(char *name, int *s, int *i)

and when you have to call this function you use the below declaration in the main or calling function

int locate(char *name, &s, &i)  
Benq
  • 13
  • 1
  • 1
  • 5
  • "you would use pointers pointing to the addresses" it is "pointers are addresses". Latter version of function locate exists in C++, only. – Sam Ginrich Feb 27 '22 at 14:05