Pointers, arrays and passing pointers to methods
Confused with the problem here. New to C, as made obvious by the below example:
#include <stdlib.h>
#include <stdio.h>
void pass_char_ref(unsigned char*);
int main()
{
unsigned char bar[6];
pass_char_ref(&bar);
printf("str: %s", bar);
return 0;
}
void pass_char_ref(unsigned char *foo)
{
foo = 开发者_开发技巧"hello";
}
To my understanding, bar is an unsigned character array with an element size of 6 set away in static storage. I simply want to pass bar by reference to pass_char_ref() and set the character array in that function, then print it back in main().
You need to copy the string into the array:
void pass_char_ref(unsigned char *foo)
{
strcpy( foo, "hello" );
}
Then when you call the function, simply use the array's name:
pass_char_ref( bar );
Also, the array is not in "static storage"; it is an automatic object, created on the stack, with a lifetime of the containing function's call.
Two things:
You don't need to pass
&bar
; just passbar
.When you pass an array like this, the address of its first (0th) element is passed to the function as a pointer. So, call
pass_char_ref
like this:pass_char_ref(bar);
When you call
pass_char_ref
like this, the array name "decays" into a pointer to the array's first element. There's more on this in this tutorial, but the short story is that you can use an array's name in expressions as a synonym for&array_name[0]
.Pointers are passed by value. You have:
void pass_char_ref(unsigned char *foo) { foo = "hello"; }
In some other languages, arguments are passed by reference, so formal parameters are essentially aliases for the arguments. In such a language, you could assign
"hello"
tofoo
and it would change the contents ofbar
.Since this is C,
foo
is a copy of the pointer that's passed in. So,foo = "hello";
doesn't actually affectbar
; it sets the local value (foo
) to point to theconst
string"hello"
.To get something like pass by reference in C, you have to pass pointers by value, then modify what they point to. e.g.:
#include <string.h> void pass_char_ref(unsigned char *foo) { strcpy(foo, "hello"); }
This will copy the string
"hello"
to the memory location pointed to byfoo
. Since you passed in the address ofbar
, the strcpy will write tobar
.For more info on
strcpy
, you can look at its man page.
In C, arrays are accessed using similar mechanics to pointers, but they're very different in how the definitions work - an array definition actually causes the space for the array to be allocated. A pointer definition will cause enough storage to be allocated to refer (or "point") to some other part of memory.
unsigned char bar[6];
creates storage for 6 unsigned characters. The C array semantics say that, when you pass an array to another function, instead of creating a copy of the array on the stack, a pointer to the first element in the array is given as the parameter to the function instead. This means that
void pass_char_ref(unsigned char *foo)
is not taking an array as an argument, but a pointer to the array. Updating the pointer value (as in foo = "hello";
, which overwrites the pointer's value with the address of the compiled-in string "hello"
) does not affect the original array. You modify the original array by dereferencing the pointer, and overwriting the memory location it points to. This is something that the strcpy
routine does internally, and this is why people are suggesting you use
void pass_char_ref(unsigned char *foo)
{
strcpy(foo, "hello");
}
instead. You could also say (for sake of exposition):
void pass_char_ref(unsigned char *foo)
{
foo[0] = 'h';
foo[1] = 'e';
foo[2] = 'l';
foo[3] = 'l';
foo[4] = 'o';
foo[5] = 0;
}
and it would behave correctly, too. (this is similar to how strcpy will behave internally.)
HTH
Please see here to an explanation of pointers and pass by reference to a question by another SO poster. Also, here is another thorough explanation of the differences between character pointers and character arrays.
Your code is incorrect as in ANSI C standard, you cannot pass an array to a function and pass it by reference - other data-types other than char
are capable of doing that. Furthermore, the code is incorrect,
void pass_char_ref(unsigned char *foo) { foo = "hello"; }
You cannot assign a pointer in this fashion to a string literal as pointers use the lvalue and rvalue assignment semantics (left value and right value respectively). A string literal is not an rvalue hence it will fail. Incidentally, in the second link that I have given which explains the differences between pointers and arrays, I mentioned an excellent book which will explain a lot about pointers on that second link.
This code will probably make more sense in what you are trying to achieve
void pass_char_ref(unsigned char *foo) { strcpy(foo, "hello"); }
In your main()
it would be like this
int main() { unsigned char bar[6]; pass_char_ref(bar); printf("str: %s", bar); return 0; }
Don't forget to add another line to the top of your code #include <string.h>
.
Hope this helps, Best regards, Tom.
Since bar[] is an array, when you write bar, then you are using a pointer to the first element of this array. So, instead of:
pass_char_ref(&bar);
you should write:
pass_char_ref(bar);
Time again for the usual spiel --
When an expression of array type appears in most contexts, its type is implicitly converted from "N-element array of T" to "pointer to T" and its value is set to point to the first element of the array. The exceptions to this rule are when the array expression is the operand of either the sizeof
or &
operators, or when the array is a string litereal being used as an initializer in a declaration.
So what does all that mean in the context of your code?
The type of the expression bar
is "6-element array of unsigned char" (unsigned char [6]
); in most cases, the type would be implicitly converted to "pointer to unsigned char" (unsigned char *
). However, when you call pass_char_ref
, you call it as
pass_char_ref(&bar);
The &
operator prevents the implicit conversion from taking place, and the type of the expression &bar
is "pointer to 6-element array of unsigned char" (unsigned char (*)[6]
), which obviously doesn't match the prototype
void pass_char_ref(unsigned char *foo) {...}
In this particular case, the right answer is to ditch the &
in the function call and call it as
pass_char_ref(bar);
Now for the second issue. In C, you cannot assign string values using the =
operator the way you can in C++ and other languages. In C, a string is an array of char with a terminating 0, and you cannot use =
to assign the contents of one array to another. You must use a library function like strcpy
, which expects parameters of type char *
:
void pass_char_ref(unsigned char *foo)
{
strcpy((char *)foo, "hello");
}
Here's a table of array expressions, their corresponding types, and any implicit conversions, assuming a 1-d array of type T (T a[N]
):
Expression Type Implicitly converted to
---------- ---- -----------------------
a T [N] T *
&a T (*)[N]
a[0] T
&a[0] T *
Note that the expressions a
, &a
, and &a[0]
all give the same value (the address of the first element in the array), but the types are all different.
The use of the address of operator (&) on arrays is no longer allowed. I agree that it makes more sense to do &bar rather than bar, but since arrays are ALWAYS passed by reference, the use of & is redundant, and with the advent of C++ the standards committee made it illegal.
so just resist the urge to put & before bar and you will be fine.
Edit: after a conversation with Roger, I retract the word illegal. It's legal, just not useful.
精彩评论