为什么函数对实际参数的副本进行操作

Why does a function operates on the copy of the actual parameters?

本文关键字:副本 操作 参数 函数 为什么      更新时间:2023-10-16

我想了解当您按值将参数传递给函数时,后面会发生什么。"函数复制值"是如何完成的?

我希望这是传递一个数组和传递两个变量之间的平行关系。

我已经搜索了一些线程,我认为这将是最合适的,尽管我还有一些其他问题。

这里有两个例子:

示例1:

void function(int arr[])
{
cout << arr << endl;                // The address of the first elm
cout << sizeof(arr);                // 4 (bytes size of address on 32 bit)
}
int main()
{
int vector[] = {1,2,3,4,5,6,7};
function(vector);
return 0;
}

Ex2:

void interChange(int a, int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 5, b = 3;
interChange(a, b);
return 0;
}

在第一个例子中,我想表明,即使我按值传递数组,它仍然被解释为指针(允许修改函数以更改实际的vector值),这就是为什么打印数组将输出地址,而打印其大小将输出指针的维度。

在第二个例子中,参数是按值传递的,但这次它们不会改变变量ab的值。这个过程是如何发生的?为什么他们也被复制而不是使用他们的地址?编译器是否考虑了他们的地址?如果我在main()中打印&a,然后在interChange中,我会得到两个非常接近的地址,例如:0x69fed80x69fe80

好的,这只是C编程语言选择的约定。C++继承了C.

你举了两个不同但有些关联的例子。我将分别发言。

对于第二个示例:例如,当您声明一个变量int a时,machine需要在某个地方存储一个值。也就是说,有一定量的RAM被分配来存储可以被解释为int的值。在x86上,32位机器——这应该是32位/4字节的内存。

当用参数调用函数时,必须将值传递给函数。THat是必须分配一些内存来存储这些值。默认情况下,C和C++选择复制值。这是调用函数时发生的第一件事——分配了一些内存。因为它的参数和值被复制到新的内存中。这对int来说很好,因为它们可以存储在CPU寄存器中,而CPU寄存器的大小是有限的。如果您想修改值——您需要获取存储值的内存地址——请将该地址传递给函数。请注意,您已在复制了地址。但是使用地址指针可以更改存储在该地址的值。


// Copy two integers
void interChange(int a, int b) {
int tmp;
tmp = a;
a = b;
b = tmp;
}
void interChangePtr(int* a, int* b) {
int tmp;
tmp = *a;
a* = *b;
b* = tmp;
}
int main() {
int a = 5, b = 3;
interChange(a, b);
// a=5, b=3.
interChangePtr(&a, &b);
// a=3, b=5
return 0;
}

至于您的第二个例子,这是C选择的另一个约定。键入时:

int main() {
int arr[25]; // Allocates memory on the stack for 25 integers
...

声明一个数组(以C风格)会通知编译器您希望它为堆栈上的数组分配内存。数组只是一个连续的内存块。因此,您可以获取指向它的指针,并使用该指针修改值。在C中,如果您键入arr,这是指向堆栈上为您分配的内存的指针。因此,当您将函数void function(int arr[])调用为function(arr)时,这实际上传递了一个指向数组的指针,而不是实际的内存块。这些约定的原因是性能。将单个指针传递给数组比分配新数组和复制数据更快。

希望这能给你一些进一步研究这个话题的线索。

无论何时将任何参数传递给任何函数,通常都会将其复制到函数参数中。但这里有一个例外,在数组的情况下,这种情况不会发生。无论何时将数组传递给任何函数,编译器都会自动将其转换为指向数组第一个元素的指针。现在让我们来看两个案例

案例1:当您传递一个数组时,编译器将它转换为指向该数组第一个元素的指针。现在是int类型的数组,所以Ofc指针将是int类型,int指针的大小是4字节,你可以看到。

情况2:当您在第二个函数中传递两个int时。传递的参数被复制到函数参数中。所以请记住,是否在参数和参数列表中写入了和以前相同的名称。两者都是不同的变量。无论你在函数中做什么,基本上都不会影响变量。所以你的交换函数是没有用的,因为它正在处理它自己的函数的A和B,而不是在主函数的末尾。

我希望现在一切都清楚了。评论如果你没有得到任何部分

按值复制实际上意味着以下模式。

int a = 10;
int b = a;

在这个简单的例子中,a的值被复制到变量b中。

这个函数声明来自您的第一个示例

void function(int arr[]);

相当于申报

void function(int *arr);

因为编译器隐式地调整具有数组类型的参数以指向数组元素类型。

另一方面,通过值传递的数组被隐式转换为指向其第一个元素的指针。

此功能定义

void function(int arr[])
{
cout << arr << endl;                // The address of the first elm
cout << sizeof(arr);                // 4 (bytes size of address on 32 bit)
}

及其调用

function(vector);

你可以想象的以下方式

function(vector);
//...
void function( /*int arr[] */)
{
int *arr = vector; 
cout << arr << endl;                // The address of the first elm
cout << sizeof(arr);                // 4 (bytes size of address on 32 bit)
}

也就是说,函数参数是它的局部变量,如果参数是通过值传递的,那么这些局部变量就会获得参数值的副本。

但要考虑的是,数组的元素实际上是通过指向数组第一个元素的指针通过引用传递的。

它看起来就像你有以下功能一样

void interChange(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}

interChange( &a, &b);

若要显示将数组作为转换为指向其第一个元素的指针的参数传递的相似性,可以按照以下方式重写函数定义

void interChange(int *a, int *b)
{
int tmp;
tmp = a[0];
a[0] = b[0];
b[0] = tmp;
}

也就是说,它看起来像是传递给函数数组,每个数组只包含一个元素。