开发者

Pointers, arrays and passing pointers to methods

开发者 https://www.devze.com 2022-12-14 18:13 出处:网络
Confused with the problem here. New to C, as made obvious by the below example: #include <stdlib.h>

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:

  1. You don't need to pass &bar; just pass bar.

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

  2. 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" to foo and it would change the contents of bar.

    Since this is C, foo is a copy of the pointer that's passed in. So, foo = "hello"; doesn't actually affect bar; it sets the local value (foo) to point to the const 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 by foo. Since you passed in the address of bar, the strcpy will write to bar.

    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.

0

精彩评论

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