c++ 为什么数组的值在void函数外部改变,而在void函数内部改变?

llmtgqce  于 2023-03-25  发布在  其他
关注(0)|答案(2)|浏览(120)

我是C++编程的初学者。我写了一个简单的程序。我定义了一个名为“myFunction”的函数,它得到一个数组及其大小作为输入参数。在函数内部,数组的第一个元素变为100。然而,在主函数中,数组的第一个元素的值发生了变化。为什么会这样?我认为它不应该改变。我知道,在类似的情况下,对于一个int变量,它不会发生。

#include <iostream>

using namespace std;

void myFunction(int a[],int b)
{
    a[0] = 100;
}

void myFunction2 (int a)
{
    a = a+2;
}

main()
{
    int size_of_array = 5;
    int myArray[size_of_array] = {7,8,2,3,5};
    int c = 2;
    myFunction(myArray,5);
    myFunction2(c);
    cout << myArray[0]<< endl;
    cout << c;
}

我期望在调用“myFunction”之后,“myArray”的第一个元素应该是7

fhity93d

fhity93d1#

在C中,数组本身不会作为值传递,而是在main中作为一系列5个顺序(可能)32位int值分配。
你的myFunction函数得到一个 * 指针 *,指向内存块的开始,而不是整个数组的副本。a[0] = 100;在功能上与*(a + 0) = 100;相同。您正在取消引用指针并向其赋值。这会更改该地址的内存中的值。此更改反映在mainafter you'中。我调用了myFunction,因为内存地址从未更改。
您传递给myFunction2int值已被复制。在该函数中对a所做的更改对main中的c没有影响。
值得注意的是,像你所展示的可变长度数组并不是C
标准的一部分。虽然有些编译器可能支持它们,但最好不要依赖这种支持。
编写以下代码并让编译器计算出大小就足够了。

int myArray[] = {7,8,2,3,5};

现在,如果我们离开原始数组的领域,开始使用像std::vector这样的容器,我们可以通过值或引用传递,如果我们通过值传递,你 * 确实 * 得到了一个副本。

#include <vector>
#include <iostream>

void foo(std::vector<int> v) {
    v[0] = 100;
}

void bar(std::vector<int>& v) {
    v[0] = 100;
}

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    for (auto x : v) std::cout << x << std::endl;

    foo(v);

    for (auto x : v) std::cout << x << std::endl;

    bar(v);

    for (auto x : v) std::cout << x << std::endl;

    return 0;
}

输出:

1
2
3
4
5
1
2
3
4
5
100
2
3
4
5

在调用foo之后,main中的v没有变化。但是因为v通过引用传递给bar,所以当我们打印数组时,赋值给它的第一个元素确实会反映在main中。

enyaitl3

enyaitl32#

这是C++从C继承的一个糟糕的特性:原始数组不能作为副本传递给函数,尽管有一些语法看起来像是这样。

void f(int v[]);

在C和C++中只是

void f(int* v);

这就是为什么引入std::array的原因之一。它可以像原始数组一样使用,但在用作函数参数时提供了正常规则。
一个二个一个一个
为了使混淆更彻底,很可能将指针或对原始数组的引用作为函数参数传递。然而,语法不是很好,特别是指针变体很容易被错误地使用。

#include <iostream>

void call_by_reference(int(&array)[2]) {
    array[0] = 5;
    std::cout << "call_by_reference: " << array[0] << ", " << array[1] << '\n';
}

void call_by_pointer(int(*array)[2]) {
    (*array)[1] = 7;
    std::cout << "call_by_pointer: " << (*array)[0] << ", " << (*array)[1] << '\n';
}

int main() {
    int array[2] = {1, 2};

    std::cout << "main array: " << array[0] << ", " << array[1] << '\n';

    call_by_reference(array);

    std::cout << "main array: " << array[0] << ", " << array[1] << '\n';

    call_by_pointer(&array);

    std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
}
main array: 1, 2
call_by_reference: 5, 2
main array: 5, 2
call_by_pointer: 5, 7
main array: 5, 7

call_by_pointer中,(*array)[1]中的括号对于访问特别重要!

#include <iostream>
#include <array>

void call_by_pointer(int(*array)[2]) {
    std::cout << "call_by_pointer: " << *array[0] << ", " << *array[1] << '\n';
}

int main() {
    int array[2] = {1, 2};
    call_by_pointer(&array);
}
call_by_pointer: 1, -18532096

这个程序编译没有问题!但是元素访问是错误的。访问操作符[x]的优先级高于解引用操作符*。因此,根据访问内存中元素1的指针算法,地址被提前了两个元素的int数组的大小,然后被解引用。但是这已经在数组之外了,因此输出内存垃圾。
std::array再次改善了这种情况。

#include <iostream>
#include <array>

void call_by_reference(std::array<int, 2>& array) {
    array[0] = 5;
    std::cout << "call_by_reference: " << array[0] << ", " << array[1] << '\n';
}

void call_by_pointer(std::array<int, 2>* array) {
    (*array)[1] = 7;
    std::cout << "call_by_pointer: " << (*array)[0] << ", " << (*array)[1] << '\n';
}

int main() {
    std::array<int, 2> array = {1, 2};

    std::cout << "main array: " << array[0] << ", " << array[1] << '\n';

    call_by_reference(array);

    std::cout << "main array: " << array[0] << ", " << array[1] << '\n';

    call_by_pointer(&array);

    std::cout << "main array: " << array[0] << ", " << array[1] << '\n';
}
main array: 1, 2
call_by_reference: 5, 2
main array: 5, 2
call_by_pointer: 5, 7
main array: 5, 7

参数语法易于阅读,忘记指针变量中的括号将导致编译错误。

相关问题