数组是按值传递还是按引用传递?

时间:2012-11-19 07:24:16

标签: c arrays string pointers

我肯定知道

function(int *a); function(int a[]);
在C中的

是相同的,函数(int a [])将被翻译成函数(int * a)

int *a = malloc(20);
int b[] = {1,2,3,4,5};

这两个不一样,第一个是指针,第二个是数组。当我调用函数(b)时会发生什么?(function(int * a)) 我知道b在堆栈上,所以如何传递给该函数?

其次,字符串:

char *c1 = "string";
char c2 [] = "string";

在这种情况下我不知道c1在哪里,我想c2在堆栈上。 假设函数现在是:function(char * c),它与函数(char c [])相同,当我调用函数(c1)和函数(c2)时会发生什么,字符串将通过引用传递或值?

7 个答案:

答案 0 :(得分:16)

这里有一个关键点,一切都是以值传递,例如,这会将 a的副本传递给{{1} (恰好是指向某个内存的指针):

foo()

这就是为什么如果你在int *a = malloc(20); foo(a); 中做这样的事情,它并没有真正改变foo()中的指针a,而是更改本地副本:< / p>

main()

换句话说,您可以使用foo(int *a) { a = NULL; /*changes local copy of the pointer*/ } 的{​​{1}}本地副本将指向的内存更改为“a”,但不能更改{{1} } {em>指向foo()中的

现在,要通过“引用”传递一些东西,你将指向指针的指针的副本传递给函数(类似a-&gt; b-&gt;内存):

a

因此,当您在a中指定它以更改main()中的指针时:

int *a = malloc(20);
foo(&a);

现在回答一些其他问题,当您使用数组名称时,它会转换为指向数组第一个元素的指针:

foo()

最后两个函数调用是等效的,因为它们都传递指向某个内存的第一个元素的指针,区别在于main()的内存在堆上分配,内存为foo(int **a) { *a = NULL; /*changes the pointer in main */ } 但是,在堆栈上分配。

最后,字符串,以下是相似的,因为相同的原则适用,但第一个是常量字符串文字,应该定义为int *a = malloc(20); int b[] = {1,2,3,4,5}; foo(a); foo(b); ,你应该尝试在任何地方修改它,但你可以改变第二个:

a

答案 1 :(得分:5)

来自K&amp; R2

When an array name is passed to a function, what is passed is the 
location of the initial element. Within the called function, this 
argument is a local variable, and so an array name parameter is a 
pointer, that is, a variable containing an address.

参数声明char c2 []只是char* c2的语法糖。

C中的所有内容都作为值传递。有关此用法的进一步说明请使用此link

Eli Bendersky也有一个很好的article讨论相同的事情。

答案 2 :(得分:1)

当您将数组传递给期望指针的函数时,数组的引用会“衰减”为指向其第一个元素的指针。

http://c-faq.com/aryptr/aryptrequiv.html

实际传递给函数是通过引用来完成的,这是由编译器通过将地址(指针)放在堆栈或CPU寄存器中来完成的。

字符串也不例外,因为它们只是字符数组。

答案 3 :(得分:0)

      int *a = malloc(20);
                         ===========
    |a|----------------> | | | | | |  
                         ===========
    a is a pointer          20 bytes on heap each of 4 bytes 
    to int on stack 


    int b[] = {1,2,3,4,5};


     =================================
     |   1 |  2   |  3  |  4  |  5   |
     =================================
     b[0]   b[1]    b[2]  b[3]   b[4]   
Full array is on stack


char *c1 = "string";
char c2 [] = "string";


In case of "string" it's string literal and allocated on readonly memory.

In first case , |c1| ----> |s|t|r|i|n|g|\0|

In second case ,  ============================================
                  | s  |  t   |   r  |  i  |  n  |  g  | \0  |
                  ============================================
                  c2[0] c2[1]   c2[2] c2[3] c2[4] c2[5]  c2[6]

The full char array is on stack.

答案 4 :(得分:0)

如果您认为这是按价值致电,请尝试运行此命令:

void bubbleSort(int a[],int n){            //or int *a
    printf("\nBUBBLE SORT");
    int i,j;
    for(i=n-1;i>0;i--)
        for(j=0;j<i;j++)
            if(a[j]>a[j+1])
                swap(&a[j],&a[j+1]);
    displayArray(a,n);
}
main(){
    int n=5,a[n],i,j;
    initArray(a,n);
    displayArray(a,n);
    bubbleSort(&a,n);
    displayArray(a,n);
}

在bubbleort()调用之后,在bubbleSort()和displayArray()中都会显示相同的结果。

如果在a是数组时调用函数(a),则它将实际上传递a的基址。因此,基本上是按引用致电

char *c="blah-blah"; and,
char c[]="blah-blah";

完全一样! 在这两种情况下,c均指向字符串中的第一个元素。另外,第一个字符串不是NOT,我的意思是 NOT 常量。尝试更改它。会的。

答案 5 :(得分:-1)

数组总是通过引用(指针)传递。

如果要使用值传递它们,请将它们封装在struct中。这将导致在原始数组的副本上进行操作。示例如下所示:

foo的第一个参数是struct object,它包含数组的副本。第二个参数是数组引用。

#include <stdio.h>

struct a{
    int i[2]; // An array encapsulated in struct.
};

void foo(struct a b, int j[]){
    b.i[0]=30;
    j[1]=30;
}

int main(){
    struct a c;
    c.i[0]=10;
    c.i[1]=20;
    printf("Before %d %d\n",c.i[0], c.i[1]);
    foo(c, c.i);
    printf("After %d %d \n",c.i[0], c.i[1]);
    return 0;
}


$ ./a.out 
Before 10 20
After 10 30 

答案 6 :(得分:-1)

数组是通过引用传递的原因?因为您通过值传递指针地址所以更改指针将改变指向的内存而不是指针地址本身,因此更改指针不会将原始指针替换为函数,因此当您键入时a =该函数内的ANOTHER_POINTER,在使用函数

后不会丢失传递的数组

int a [] 等同于 int a ,并且在调用函数foo(int a)时它将获得指针地址

现在如果你想改变它自己的指针你可以通过引用foo(int *&amp; a)传递指针地址,所以现在改变指针地址 a = ANOTHER_POINTER 将改变地址指针