指针,数组和指向方法的指针

时间:2009-12-27 19:43:50

标签: c pointers

对此问题感到困惑。 C的新手,如下例所示:

#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";
}

据我所知,bar是一个无符号字符数组,其元素大小为6,静态存储。我只想通过引用pass_char_ref()传递bar并在该函数中设置字符数组,然后将其打印回main()。

7 个答案:

答案 0 :(得分:7)

您需要将字符串复制到数组中:

void pass_char_ref(unsigned char *foo) 
{ 
  strcpy( foo, "hello" ); 
} 

然后当你调用该函数时,只需使用数组的名称:

pass_char_ref( bar );

此外,该阵列不在“静态存储”中;它是一个自动对象,在堆栈​​上创建,具有包含函数调用的生命周期。

答案 1 :(得分:4)

两件事:

  1. 您无需通过&bar;只需通过bar

    当你传递这样的数组时,它的第一个(第0个)元素的地址作为指针传递给函数。所以,请像这样呼叫pass_char_ref

    pass_char_ref(bar);
    

    当您像这样调用pass_char_ref时,数组名称“衰减”为指向数组第一个元素的指针。这个in this tutorial还有更多内容,但短篇小说是你可以在表达式中使用数组的名称作为&array_name[0]同义词

  2. 指针按值传递。你有:

    void pass_char_ref(unsigned char *foo)
    {
      foo = "hello";
    }
    

    在其他一些语言中,参数通过引用传递,因此形式参数基本上是参数的别名。在这种语言中,您可以将"hello"分配给foo,它会更改bar的内容。

    由于这是C,foo是传入指针的副本。因此,foo = "hello";实际上不会影响bar;它将本地值(foo)设置为指向const字符串"hello"

    要在C中通过引用传递,你必须按值传递指针,然后修改它们指向的内容。 e.g:

    #include <string.h>
    void pass_char_ref(unsigned char *foo)
    {
      strcpy(foo, "hello");
    }
    

    这将将<{1}}字符串复制到"hello"指向的内存位置。由于您传递了foo的地址,因此strcpy将写入bar

    有关bar的详情,请查看its man page

答案 2 :(得分:1)

在C中,使用与指针类似的机制来访问数组,但它们在定义的工作方式上有很大的不同 - 数组定义实际上会导致分配数组的空间。指针定义将导致分配足够的存储空间以引用(或“指向”)内存的某些其他部分。

unsigned char bar[6];

为6个无符号字符创建存储空间。 C数组语义表示,当您将数组传递给另一个函数时,不是在堆栈上创建数组的副本,而是将指向数组中第一个元素的指针作为函数的参数。这意味着

void pass_char_ref(unsigned char *foo)

不是将数组作为参数,而是指向数组的指针。更新指针值(如在foo = "hello";中,用编译后的字符串"hello"的地址覆盖指针的值)影响原始数组。您可以通过取消引用指针来修改原始数组,并覆盖它指向的内存位置。这是strcpy例程在内部执行的操作,这就是人们建议您使用

的原因
void pass_char_ref(unsigned char *foo)
{
    strcpy(foo, "hello");
}

代替。你也可以说(为了说明):

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;
}

它也会表现正常。 (这类似于strcpy在内部的表现。)

HTH

答案 3 :(得分:1)

请参阅here对指针的解释,并通过另一张SO海报的问题参考。此外,here是对字符指针和字符数组之间差异的另一个彻底解释。

您的代码不正确,因为在ANSI C标准中,您无法将数组传递给函数并通过引用传递它 - 除char之外的其他数据类型都能够执行此操作。此外,代码不正确,

void pass_char_ref(unsigned char *foo)
{
  foo = "hello";
}

您不能以这种方式将指针分配给字符串文字,因为指针使用左值右值赋值语义(分别为左值和右值)。字符串文字不是 rvalue 因此它将失败。顺便说一句,在我给出的第二个链接中解释了指针和数组之间的差异,我提到了一本很好的书,它将解释很多关于第二个链接的指针。

这段代码可能对你想要实现的目标更有意义

void pass_char_ref(unsigned char *foo)
{
  strcpy(foo, "hello");
}

main()中,就像这样

int main()
{
  unsigned char bar[6];

  pass_char_ref(bar);

  printf("str: %s", bar);

  return 0;
}

不要忘记在代码#include <string.h>的顶部添加另一行。

希望这有帮助, 最好的祝福, 汤姆。

答案 4 :(得分:0)

由于bar []是一个数组,当你编写bar时,你正在使用指向该数组的第一个元素的指针。所以,而不是:

pass_char_ref(&bar);

你应该写:

pass_char_ref(bar);

答案 5 :(得分:0)

通常的间隔时间再次 -

当大多数上下文中出现数组类型的表达式时,其类型将从“N元素数组T”隐式转换为“指向T”,其值设置为指向数组的第一个元素。此规则的例外情况是,数组表达式是sizeof&运算符的操作数,或者数组是一个字符串文件,用作声明中的初始化程序。

那么代码上下文中的含义是什么呢?

表达式bar的类型是“6元素无符号字符数组”(unsigned char [6]);在大多数情况下,类型将被隐式转换为“指向unsigned char”(unsigned char *)的指针。但是,当您致电pass_char_ref时,请将其称为

pass_char_ref(&bar);

&运算符阻止隐式转换发生,表达式&bar的类型是“指向无符号字符的6元素数组的指针”(unsigned char (*)[6]),显然与原型不匹配

void pass_char_ref(unsigned char *foo) {...}

在这种特殊情况下,正确答案是抛弃函数调用中的&并将其称为

pass_char_ref(bar);

现在是第二个问题。在C中,您无法使用=运算符以C ++和其他语言的方式分配字符串值。在C中,字符串是char的数组,其终止为0,并且您不能使用=将一个数组的内容分配给另一个数组。您必须使用像strcpy这样的库函数,它需要char *类型的参数:

void pass_char_ref(unsigned char *foo)
{ 
  strcpy((char *)foo, "hello");
}

这是一个数组表达式表,它们对应的类型以及任何隐式转换,假设一个类型为T(T a[N])的一维数组:

Expression             Type                Implicitly converted to
----------             ----                -----------------------
         a             T [N]               T *
        &a             T (*)[N]          
      a[0]             T 
     &a[0]             T *

请注意,表达式a&a&a[0]都提供相同的(数组中第一个元素的地址),但类型都不同。

答案 6 :(得分:-1)

不再允许在数组上使用运算符(&amp;)的地址。我同意做&amp; bar而不是bar更有意义,但由于数组总是通过引用传递,因此使用&amp;这是多余的,随着C ++的出现,标准委员会将其定为非法。

所以只要抵制放置&amp;的冲动在酒吧之前,你会没事的。

编辑:与罗杰谈话后,我撤回非法一词。这是合法的,只是没用。