12

我肯定知道

function(int *a); function(int a[]);

在 C 中是一样的,function(int a[]) 将被翻译成 function(int *a)

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

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

其次,字符串:

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

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

4

6 回答 6

20

这里有一个关键点,例如,所有内容实际上都是按值传递的,这将传递to的副本(恰好是指向某些内存的指针):afoo()

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

这就是为什么如果你在其中做这样的事情foo()并不会真正改变指针amain()而是改变本地副本

foo(int *a)
{
  a = NULL; /*changes local copy of the pointer*/
}

换句话说,您可以使用foo()'local copy ofa来更改'a'指向的内存,但不能更改ina 指向main()的内存。

现在,要“通过引用”传递一些东西,你将一个指向指针的副本传递给函数(类似于 a->b->memory):

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是在堆上分配的,而内存b是在堆栈上分配的。

最后,字符串,以下是相似的,因为相同的原则适用,但是第一个是常量字符串文字,应该定义为const,你不应该尝试在任何地方修改它,但你可以更改第二个:

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

 

于 2012-11-19T07:38:52.680 回答
6

来自 K&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 中的所有内容都作为值传递。要对此进行进一步解释,请使用此链接

Eli Bendersky 也有一篇很棒的文章讨论了同样的问题。

于 2012-11-19T07:36:40.050 回答
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.
于 2012-11-19T07:39:38.293 回答
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);
}

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

如果在 a 是数组时调用 function(a),它实际上会传递 a 的基地址。所以,它基本上是由 Ref 调用的

还,

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

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

于 2018-08-08T18:39:31.403 回答
-1

编辑:下面的答案是错误的。
数组总是通过引用传递。 ”这是错误的。请参阅iabdalkader 的部分答案why。但是,我将这个答案保留在下面,以便在结构技巧中封装,将数组的副本传递给函数。


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

如果要使用值传递它们,请将它们封装在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 
于 2012-11-19T07:29:11.373 回答
-2

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

int a[]等价于int a ,当调用函数 foo(int a) 时,它会得到指针地址

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

于 2012-11-19T07:50:57.017 回答