开发者

Why do certain C/C++ functions use pointers as parameters?

I'm coming from C# and I'm learning C++ (with this tutori开发者_StackOverflow社区al) 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.


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.


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.).


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.


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.


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.


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;


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜