按值将数组传递给函数

时间:2011-01-23 14:58:10

标签: c arrays pass-by-reference pass-by-value

以下是 C Programming Just the FAQs 一书的摘录。这不是错误的,因为Arrays永远不能通过引用传递吗?

  

VIII.6:如何通过值将数组传递给函数?

     

答案:通过声明,可以按值将数组传递给函数   被调用的函数是数组名   方括号([])   附在最后。打电话的时候   功能,只需传递地址   数组(即数组的名称)   到被调用的函数。例如,   以下程序传递数组   x[]到名为的函数   byval_func()按值:

     

int[]参数告诉我们   编译器byval_func()   函数将采用一个参数 - 一个   整数数组。当。。。的时候   你调用byval_func()函数   将数组的地址传递给   byval_func()

byval_func(x);
     

因为数组正在传递   value,数组的精确副本   制作并放置在堆栈上。该   调用函数然后接收这个   数组的副本,可以打印出来。   因为数组传递给了   byval_func()是该副本   原始数组,修改数组   在byval_func()函数中有   对原始阵列没有影响。

6 个答案:

答案 0 :(得分:59)

  

因为数组是按值传递的,所以会生成数组的精确副本并将其放在堆栈上。

这是不正确的:数组本身没有被复制,只有指向其地址的指针的副本被传递给被调用者(放在堆栈上)。 (无论您是将参数声明为int[]还是int*,它都是decays into a pointer。)这允许您从被调用函数中修改数组的内容。因此,这个

  

因为传递给byval_func()的数组是原始数组的副本,所以修改byval_func()函数中的数组对原始数组没有影响。

是完全错误的(感谢@Jonathan Leffler对他的评论)。但是,在函数内重新分配指针不会更改指向函数外部原始数组的指针。

答案 1 :(得分:51)

烧掉那本书。如果你想要一个不是由初学者程序员编写的真正的C FAQ,请使用这个:http://c-faq.com/aryptr/index.html

语法方面,严格来说,不能按C中的值传递数组。

void func (int* x); /* this is a pointer */

void func (int x[]); /* this is a pointer */

void func (int x[10]); /* this is a pointer */

然而,对于记录,C中有一个脏技巧,它允许你在C中按值传递一个数组。不要在家里尝试这个!因为尽管有这个技巧,仍然没有理由按值传递数组。

typedef struct
{
  int my_array[10];
} Array_by_val;

void func (Array_by_val x);

答案 2 :(得分:1)

在C和C ++中,不可能通过值将完整的内存块作为参数传递给函数,但我们可以传递其地址。在实践中,这具有几乎相同的效果,并且是更快和更有效的操作。

为安全起见,您可以传递数组大小或在指针之前放置const限定符,以确保被调用者不会更改它。

答案 3 :(得分:1)

这不是错误的吗,因为数组永远不能通过值传递?

完全正确。您不能在C中按值传递数组。

我看了一下书中引用的部分,很快就能发现这种混乱或错误的根源。

当将*i用作函数的参数时,作者并不知道i[]等效于i。发明后一种形式是为了清楚地说明代码的读者,byval_func()指向一个数组,这个问题很好地说明了这种混乱的根源。

我认为很有趣的是,该书特定部分的作者或至少一个其他部分的作者(因为该书总共有 5 位作者)或其中一个 7 校对人员至少没有提到以下句子:

调用byval_func()函数时,您将数组的地址传递给#include <stdio.h> struct a_s { int a[20]; }; void foo (struct a_s a) { size_t length = sizeof a.a / sizeof *a.a; for(size_t i = 0; i < length; i++) { printf("%d\n",a.a[i]); } } int main() { struct a_s array; size_t length = sizeof array.a / sizeof *array.a; for(size_t i = 0; i < length; i++) { array.a[i] = 15; } foo(array); }

至少,他们应该注意到存在冲突。 由于您传递的是地址,因此它只是一个地址。没有什么神奇的事情可以将地址变成一个全新的数组。


但是回到问题本身:

由于您似乎已经了解自己,因此无法按C中的值传递数组。但是您可以做三件事(可能还有更多,但这是我的正式要求),根据情况的不同,可以选择其他方法,所以让我们开始吧。

  1. 将数组封装在结构中(如其他答案所述):
#include <stdio.h>

void foo (int *array, size_t length)
{
   int b[length];

   for(size_t i = 0; i < length; i++)
   {
       b[i] = array[i];
       printf("%d\n",b[i]);
   }
}

int main()
{
   int a[10] = {0,1,2,3,4,5,6,7,8,9};

   foo(a,(sizeof a / sizeof *a));
}
  1. 通过指针传递,但还要添加一个用于确定数组大小的参数。在被调用的函数中,创建了一个具有该大小信息的新数组,并为其分配了调用者中数组的值:
#include <stdio.h>

int a[10];
size_t length = sizeof a / sizeof *a;

void foo (void)
{
   for(size_t i = 0; i < length; i++)
   {
       printf("%d\n",a[i]);
   }
}

int main()
{   
   for(size_t i = 0; i < length; i++)
   {
       a[i] = 25;
   } 

   foo();
}
  1. 避免定义局部数组,而只使用一个具有全局范围的数组:
CREATE trigger [dbo].[insercionVentasConcluidadas]

on [dbo].[pedido]
after update
as 
declare @fechaactual date
declare @estado varchar
begin 
    if UPDATE(estado)
    begin 
        select @estado = estado from inserted;

        set @fechaactual = GETDATE();
        if (@estado = 'cerrado')
        print N'RAS'
        begin

            insert into ventaConcluida(numeroPedido, nombreCliente, nombreProveedor, fechaCreacion, fechaCierre, diasTranscurridos, MontoPedido)
            select d.idPedido, d.nombreCliente, d.nombreProveedor, d.fechaPedido, @fechaactual, dbo.calculoDias(d.fechaPedido, @fechaactual),
                    d.montoPedido
            from inserted i 
            inner join deleted d
            on i.idPedido = d.idPedido

        end
    end 
end

答案 4 :(得分:0)

Yuo可以通过将数组包装到struct中来解决此问题

#include <stdint.h>
#include <stdio.h>

struct wrap
{
    int x[1000];
};

struct wrap foo(struct wrap x)
{
    struct wrap y;

    for(int index = 0; index < 1000; index ++)
        y.x[index] = x.x[index] * x.x[index];
    return y;
}

int main ()
{
    struct wrap y;

    for(int index = 0; index < 1000; index ++)
        y.x[index] = rand();
    y = foo(y);
    for(int index = 0; index < 1000; index ++)
    {
        printf("%d %s", y.x[index], !(index % 30) ? "\n" : "");
    }


}

答案 5 :(得分:-14)

#include<stdio.h>
void  fun(int a[],int n);
int main()
{
    int a[5]={1,2,3,4,5};
    fun(a,5);
}
void  fun(int a[],int n)
{
    int i;
    for(i=0;i<=n-1;i++)
        printf("value=%d\n",a[i]);
}

通过这种方法,我们可以按值传递数组,但实际上数组正在通过其基本地址进行访问,该地址实际上是在堆栈中复制的。