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

void
getstr(char *&retstr)
{
 char *tmp = (char *)malloc(25);
 strcpy(tmp, "hello,world");
 retstr = tmp;
}

int
main(void)
{
 char *retstr;

 getstr(retstr);
 printf("%s\n", retstr);

 return 0;
}

gcc would not compile this file, but after adding #include <cstring> I could use g++ to compile this source file.

The problem is: does the C programming language support passing pointer argument by reference? If not, why?

Thanks.

eLRuLL
  • 18,488
  • 9
  • 73
  • 99
Jichao
  • 40,341
  • 47
  • 125
  • 198
  • Not related to your question, but for curiosity, what's the use case for passing a pointer as a reference? – Tristram Gräbener Dec 01 '09 at 12:16
  • 1
    @Tristram: if you want the function to be able to modify the pointer, and have the modification propagate beyond the scope of the function. – Charles Salvia Dec 01 '09 at 12:17
  • If you want to perform malloc of strings in a function that does not free that memory then you could consider using valgrind or equivalent tool to test for memory leaks. – PP. Dec 01 '09 at 12:18
  • 2
    A reference is a way of confusing programmers as to what is really happening. If you discipline your approach to pointers you'll find that references are not necessary. When dealing with a reference a compiler is taking actions on an object and managing the indirection for you. – PP. Dec 01 '09 at 12:25
  • 1
    PP: Gross oversimplification of references; any feature can be abused. –  Jan 13 '10 at 15:07

6 Answers6

29

No, C doesn't support references. It is by design. Instead of references you could use pointer to pointer in C. References are available only in C++ language.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
20

References are a feature of C++, while C supports only pointers. To have your function modify the value of the given pointer, pass pointer to the pointer:

void getstr(char ** retstr)
{
    char *tmp = (char *)malloc(25);
    strcpy(tmp, "hello,world");
    *retstr = tmp;
}

int main(void)
{
    char *retstr;

    getstr(&retstr);
    printf("%s\n", retstr);

    // Don't forget to free the malloc'd memory
    free(retstr);

    return 0;
}
Bojan Resnik
  • 7,320
  • 28
  • 29
  • 2
    Don't cast what `malloc()` returns. If you've included `stdlib.h`, it does absolutely nothing. If you haven't, it hides that fact. – David Thornley Dec 01 '09 at 22:02
  • 3
    As `malloc` returns `void*` I find it good practice to cast it explicitly to the required type instead of relying on implicit conversions. If `stdlib.h` is not included, casting doesn't hide that fact - the compiler will warn you that `malloc` has not been declared. – Bojan Resnik Dec 02 '09 at 08:16
5

Try this:


void
getstr(char **retstr)
{
 char *tmp = (char *)malloc(25);
 strcpy(tmp, "hello,world");
 *retstr = tmp;
}

int
main(void)
{
 char *retstr;

 getstr(&retstr);
 printf("%s\n", retstr);

 return 0;
}
PP.
  • 10,764
  • 7
  • 45
  • 59
  • 1
    Don't cast the return value of `malloc`. It can hide a failure to `#include ` (which you did forget in the code above). See http://c-faq.com/malloc/mallocnocast.html Also, don't forget to check the return value of `malloc`. – Sinan Ünür Dec 01 '09 at 21:53
  • 3
    Wow, some people struggle to see the difference between a proof of concept test routine and production code! It was obvious this was a rough-and-ready test routine because there was no corresponding `free` but I guess some people miss the obvious! – PP. Dec 02 '09 at 08:13
2

This should be a comment but it is too long for a comment box, so I am making it CW.

The code you provided can be better written as:

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

void
getstr(char **retstr)
{
    *retstr = malloc(25);
    if ( *retstr ) {
        strcpy(*retstr, "hello,world");
    }
    return;
}

int
main(void)
{
    char *retstr;

    getstr(&retstr);
    if ( retstr ) {
        printf("%s\n", retstr);
    }
    return 0;
}
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
1

There is an interesting trick in libgmp which emulates references: typedef mpz_t __mpz_struct[1];

and then you can write like this:

mpz_t n;
mpz_init(n);
...
mpz_clear(n);

I would not recommend to use this method, because it may be incomprehensible for others, it still does not protect from being a NULL: mpz_init((void *)NULL), and it is as much verbose as its pointer-to-pointer counterpart.

Dmytro Sirenko
  • 5,003
  • 21
  • 26
0

C lang does not have reference variables but its part of C++ lang.

The reason of introducing reference is to avoid dangling pointers and pre-checking for pointers nullity.

You can consider reference as constant pointer i.e. const pointer can only point to data it has been initialized to point.

Ashish
  • 8,441
  • 12
  • 55
  • 92