在C中通过引用传递数组

在C中通过引用传递数组,c,arrays,function,reference,C,Arrays,Function,Reference,我是C的新手,我有一个疑问 由于C函数创建其参数的本地副本,我想知道为什么下面的代码会按预期工作: void函数(int数组[]){ 数组[0]=4; 数组[1]=5; 数组[2]=6; } int main(){ int数组[]={1,2,3}; 函数(数组); printf(“%d%d%d”,数组[0],数组[1],数组[2]); 返回0; } 线路输出为4 5 6 为什么这样做有效,而下面的不行 void函数(整数){ 整数=2; } int main(){ 整数=1; 函数(整数);

我是C的新手,我有一个疑问

由于C函数创建其参数的本地副本,我想知道为什么下面的代码会按预期工作:

void函数(int数组[]){
数组[0]=4;
数组[1]=5;
数组[2]=6;
}
int main(){
int数组[]={1,2,3};
函数(数组);
printf(“%d%d%d”,数组[0],数组[1],数组[2]);
返回0;
}
线路输出为4 5 6

为什么这样做有效,而下面的不行

void函数(整数){
整数=2;
}
int main(){
整数=1;
函数(整数);
printf(“%d”,整数);
返回0;
}
在这种情况下,输出仅为1

简短版本:如果父变量作为数组传递,为什么函数可以修改它们的值


谢谢大家!

在“按引用传递”和“按值传递”之间存在差异


Pass-by-reference指向内存中的一个位置,其中Pass-by-value直接传递值,数组变量始终是reference,因此它指向内存中的一个位置。默认情况下,整数将按值传递

数组名称是指向数组中第一个元素的指针。在第一个代码示例中,您传递了一个指向包含第一个数组元素的内存位置的指针。在第二个代码示例中,您通过值传递了一个整数,因此它与名为“integer”的局部变量无关

检查那个链接

按参考传递和按值传递


传递给函数的数组将转换为指针。当您将指针作为参数传递给函数时,只需给出内存中变量的地址即可。因此,当您修改数组单元格的值时,您可以编辑给定给函数的地址下的值

将简单整数传递给函数时,将在堆栈中复制该整数;在函数中修改该整数时,将修改该整数的副本,而不是原始副本

C语言中不同类型内存的提醒 在C中,我们可以使用三种类型的内存:

  • 用于局部变量和函数调用的堆栈:当我们在main()中创建变量时,我们使用堆栈存储变量,当调用函数时,给方法的参数在堆栈中注册。当我们退出一个函数时,我们“弹出”这些参数以返回到原始状态,在调用函数之前使用变量。(轶事:stackoverflow是指我们对堆栈进行黑客攻击,在函数中使用先前的变量,而不将其作为参数传递)
  • 与动态分配的内存相对应的堆:当我们需要大量数据时,我们使用此堆,因为堆栈被限制为几兆字节
  • 存储程序指令的代码
在这个数组由一个函数传递的情况下,它是一个指针(指向另一个变量的地址),它存储在堆栈中,当我们调用函数时,我们将指针复制到堆栈中

对于整数,它也存储在堆栈中,当我们调用函数时,我们复制整数

如果我们想要修改整数,我们可以传递整数的地址来修改指针下的值,如下所示:

void function(int *integer)
{
    *integer = 2;
}

int main()
{
    int integer = 1;
    function(&integer);

    printf("%d", integer);

    return 0;
}

这是由于数组趋向于衰减为指针这一事实造成的

int a[] = { 1, 2, 3 };
int* p = a; // valid: p is now the address of a[0]
a = p;  // NOT valid.

printf("a = %p\n", a);
printf("p = %p\n", p); // prints same address as a
a
p
将打印相同的值

与其他人所说的相反,
a
不是指针,它可以简单地衰减为指针

在第一个
function()
中,传递的是数组第一个元素的地址,函数体会取消对该元素的引用。事实上,编译器将函数原型视为:

void function(int* array /*you wrote int array[]*/){
    array[0] = 4;
    array[1] = 5;
    array[2] = 6;   
}

function(&array[0]);
这必须发生,因为您说的是“大小未知的数组”(int-array[])。编译器无法保证推断按值传递所需的堆栈数量,因此它会衰减为指针

----编辑----

让我们结合两个例子,使用更独特的名称使事情更清楚

#include <stdio.h>

void func1(int dynArray[]) {
    printf("func1: dynArray = %p, &dynArray[0] = %p, dynArray[0] = %d\n",
             dynArray, &dynArray[0], dynArray[0]);
}

void func2(int* intPtr) {
    printf("func2: intPtr = %p, &intPtr[0] = %p, intPtr[0] = %d\n",
             intPtr, &intPtr[0], intPtr[0]);
}

void func3(int intVal) {
    printf("func3: intVal = %d, &intValue = %p\n",
             intVal, &intVal);
}

int main() {
    int mainArray[3] = { 1, 2, 3 };
    int mainInt = 10;

    printf("mainArray = %p, &mainArray[0] = %p, mainArray[0] = %d\n",
             mainArray, &mainArray, mainArray[0]);
    func1(mainArray);
    func2(mainArray);

    printf("mainInt = %d, &mainInt = %p\n",
             mainInt, &mainInt);
    func3(mainInt);

    return 0;
}
func1
func2
中,“dynArray”和“intPtr”是局部变量,但它们是指针变量,从main接收“mainArray”的地址


此行为特定于阵列。如果要将数组放入结构中,则可以通过值传递它。

在第一个代码中,传递指向数组顶部元素的数组地址。因此,当您修改函数中的值并返回到主函数时,您仍然在访问同一地址中的同一数组。这称为按引用传递


但是,在第二种情况下,整数的值从主函数复制到被调用函数。换句话说,这两个整数在内存中的地址不同。因此,修改一个并不修改另一个。

传递的不是数组的地址,而是数组第一个元素的地址。(相同的内存地址,不同的类型。)例如,当我们使用数组[1]时,[1]是否已经隐式地取消了对指针的引用?此外,我尝试将数组初始化为int数组[3],并在函数头中的数组[3]中使用,但它仍然打印4 5 6,即使编译器可以保证按值传递所有内容所需的堆栈量。我错过什么了吗?谢谢大家!@Rogério,给定“int a[]={1,2,3}”,表达式a[1]正好等价于*(a+1)。也就是说,“a”是第一个int的地址,“a+1”是紧跟其后的int的地址,“*(a+1)”是该表达式指向的int。下标运算符可以看作是语法上的糖类。关于你的第二点,见我先前的评论。不能在C中按值传递数组。编译器是否有足够的信息来传递数组并不重要。我不是这么想的
mainArray = 0xbf806ad4, &mainArray[0] = 0xbf806ad4, mainArray[0] = 1
func1: dynArray = 0xbf806ad4, &dynArray[0] = 0xbf806ad4, dynArray[0] = 1
func2: intPtr = 0xbf806ad4, &intPtr[0] = 0xbf806ad4, intPtr[0] = 1

mainInt = 10, &mainInt = 0xbf806acc
func3: intVal = 10, &intValue = 0xbf806ad0