6

I'm coming from C# and I'm learning C++ (with this tutorial) so I have a relatively insubstantial amount of knowledge on memory, but the only use I see in pointers is "saving space" and iterating through arrays. So why do functions like the scanf function take pointers as parameters? For instance:

printf("What's your name?: "); and then: scanf("%s",&userName). Wouldn't it make more sense to just pass the variable itself as an argument? The C book I was looking at said that using the variable itself would produce unexpected results, but I don't see why. Could anyone please enlighten me in a C++ fashion? I switched from learning C because I realized how much I love OOP.

Peter Olson
  • 139,199
  • 49
  • 202
  • 242
airplaneman19
  • 1,139
  • 6
  • 19
  • 32
  • possible duplicate of [Why use pointers?](http://stackoverflow.com/questions/162941/why-use-pointers) – Cheers and hth. - Alf Aug 14 '11 at 02:53
  • scanf is not c++ . If you poke around `iostream` which is c++ there won't be pointers, only references. Try `cin >> userName;` – Daniel Aug 14 '11 at 03:05
  • 4
    `scanf` is C++. Most of the C standard library is included in C++ by reference. – Keith Thompson Aug 14 '11 at 03:08
  • 1
    IIRC, `scanf` is C and `std::scanf` is C++. Also, @airplaneman19, please show the declaration of `userName`: is it like `char* userName;` or `char userName[MAX_LEN];`? – Mike DeSimone Aug 14 '11 at 04:17
  • "but the only use I see in pointers is "saving space". That's about it, plus the processing time saved in passing a pointer as opposed to a whole data structure. Pointers are admittedly a bit more difficult to get your head around initially, but become second nature once you're used to them. Remember C++ came from C, which was designed in a time where efficiency was paramount given hardware limitations. C# is obese and wasteful by comparison, but less dangerous because of it's restrictions on the use of pointer. – Pete855217 Aug 14 '11 at 04:33

8 Answers8

8

There are 3 different ways of passing a variable to a function in C++, pass by copy, pass by reference and pass by pointer.

#include <iostream>

void passByCopy(int a)
{
   a += 1;
}

void passByReference(int &a)
{
   a += 1;
}

void passByPointer(int *a)
{
   (*a) += 1; // De-reference then increment.
}

int main()
{
   int a = 0;
   // Passing by copy, creates a copy of the 'a' object, then sends it to the function.
   passByCopy(a);
   std::cout << a << std::endl; // Outputs 0

   // Passing by reference, causes the 'a' object in the function to reference the 'a'
   // object at this scope. The value of 'a' will change. 
   passByReference(a);
   std::cout << a << std::endl; // Outputs 1

   // Passing by pointer, does almost the same thing as a pass by reference, except a 
   // pointer value can by NULL, while a reference can't.
   passByPointer(&a);

   std::cout << a << std::endl; // Outputs 2
}

With scanf, the purpose of the function is to pass values to variables in the current scope, so it can't use pass by copy. It doesn't use pass by reference for two reasons, one is that it is an old C function, so pass by reference didn't exist when it was written. The second is that it is a variadic function, which means that internally the function receives a list of pointers rather than a series of arguments.

Darcy Rayner
  • 3,385
  • 1
  • 23
  • 15
7

C and C++ pass variables by value; the formal parameter is a different object in memory from the actual parameter. Thus, if the formal parameter is modified in the function, the value of the actual parameter isn't changed.

By passing a pointer, the function can modify the contents of the actual parameter:

void swap(int *a, int *b)
{
  int t = *a;
  *a = *b;
  *b = t;
}

...
swap(&x, &y);

Thus, writing to *a in swap is equivalent to writing to x in the caller.

Pointers in C serve three main purposes:

  • Faking pass-by-reference semantics, as above (as Karl notes in the comments, C++ has a mechanism that supports true pass-by-reference);
  • Tracking dynamically-allocated memory (the memory allocation functions malloc, calloc, and realloc and the C++ new operator return pointer values);
  • Building dynamic data structures (trees, lists, queues, stacks, etc.).
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 1
    It's worth noting, for clarity, that pass-by-reference doesn't need to be faked in C++. – Karl Knechtel Aug 14 '11 at 04:41
  • Seeing this as "faking pass-by-reference" is a very perverse world-view. I would see references as "faking pointers" while hiding the fact that the callee can modify the caller's data, which is useless, dangerous, and harmful to quality and clarity of code. – R.. GitHub STOP HELPING ICE Aug 14 '11 at 18:35
4

All parameters are passed by value in C. If you want to pass by reference, you need to explicitly pass the address of the variable in question. Passing by reference is important when you want the function to modify the variable passed in.

C++ has references, but since C++ code often calls C library functions, you still see the same syntax used in C++ sometimes.

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
Caleb
  • 124,013
  • 19
  • 183
  • 272
2

In your specific example, scanf is part of the C standard library. C does not have a string class, so strings are represented as arrays of characters.

In C, the address of the first character is usually passed when strings are required. This can either be &str[0] or str. I'm not sure it's correct to have &username if it's expecting a char *, I guess it depends on username.

Cade Roux
  • 88,164
  • 40
  • 182
  • 265
1

C has no concept of passing by reference and can return only a single value. The traditional purpose of passing by pointer is therefore to allow the called function to write to a variable so that the caller can read what has been written.

C++ has the ability to pass by reference, but scanf and printf are C functions that are also available when building as C++ so that isn't available to them.

EDIT: to explain further, even putting beside the variable arguments issue, in the following code:

void calledFunction(int var1, int var2)
{
  var1 = 23;
  var2 = 19;
}

void callingFunction(void)
{
    int v1 = 9, v2 = 18;

    calledFunction(v1, v2);
    printf("%d %d", v1, v2);
}

The output is "9 18". calledFunction gets local copies of v1 and v2 because C passes by value, meaning that the values of v1 and v2 were passed in, but no other link was kept to the originals. So the fact that it modifies its copies has no effect on the originals.

Tommy
  • 99,986
  • 12
  • 185
  • 204
1

In C there are no references, all the arguments are passed by value.

If scanf would be in C# then its parameters would be preceded by out or ref keyword and no pointers would be needed. Passing pointers allow the scanf function to write some values to whatever place the pointers point to.

In C++ however there are references, though different from what you know from C#. Nonetheless if you'd use iostream library and not stdio which was inherited to C++ from C, then you wouldn't have to use pointers in this way. You'd just write:

String username;
cin >> username;
ciamej
  • 6,918
  • 2
  • 29
  • 39
  • except that C# has only pointers, not references, albeit with superficially different syntax. – Gene Bushuyev Aug 14 '11 at 04:15
  • in the C/C++ meaning, yes, C# has only pointers with special syntax. However they're not called this way, they are called references. Also C# lacks the type of references that are in C++ (which are more like a concept than a concrete thing). For instance you can't achieve in C# the same thing that a C++ const reference offers (C# readonly references is a different thing). – ciamej Aug 14 '11 at 04:35
1

One other use of pointers that I don't see mentioned in the other anwers here is that it's one of only two ways that a C function can return multiple values. A C function is defined to return a single object, but it can receive many arguments. If your multi-valued function always returns the same set of values, it's a question of convenience whether to wrap the values in a struct and have the function return the struct or have the function receive pointers through which it can write the values.

The pointer-parameter option becomes much more attractive if the function also needs to return a status or error code (because it's silly to write that through a pointer, forcing the caller to allocate another variable and obstructing standard idioms like if(f()==ERROR)...). And if the set of values is not predictable at compile time (like scanf, which must interpret the format string at runtime), then pointer-parameters become the only (sensible) option.

Edit: In your example, scanf("%s",&username); assuming username is an array type or a pointer to storage suitable for holding a character string, you don't need to pass the address. If it's an array, it will be passed as a pointer implicitly. And if it already is a pointer, taking the address yields a pointer-to-pointer, which is not suitable to hold a string. So drop the & here.

luser droog
  • 18,988
  • 3
  • 53
  • 105
0

scanf is a C function. C doesn't have references, so it has to use pointers in order to write to arguments. Also, scanf is a varargs function, so it takes variable numbers of arguments. And varargs functions can only take built-in types: pointers (to anything), integers, doubles.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    The latter is not correct, though they're usually used that way. All the variadic functions in the standard library take scalar (pointer, integer, or floating-point) arguments, but a user-written variadic function can take argument of any type that an ordinary function can. See your system's documentation for the `va_arg()` macro, or the "Variable arguments" section of the [C standard](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf). (BTW, the name "varargs" refers to the obsolete `` header, which was superseded by ``). – Keith Thompson Aug 14 '11 at 03:20