繁体   English   中英

C++ 函数改变传递参数的值

[英]C++ Function Alters Value of Passed Parameter

我有一个简单的交换函数来获取一个整数数组,并返回一个带有交换值的新数组。

int* Node::dataSwap(int *data, int n_index, int swap_index){
    
    printDatt(data);
    int *path = data;
    int swapped = data[n_index];
    int to_swap = data[swap_index];
    path[n_index] = to_swap;
    path[swap_index] = swapped;
    printDatt(data);
    
    return path;
    
}

但是,此函数正在更改对原始数据的引用。 输出看起来像这样(打印应该是相同的数据到控制台)。

0, 1, 2
 3, 4, 5 
 6, 7, 8

0, 1, 2
 3, 4, 8
 6, 7, 5

为什么“数据”在我不更改的情况下会被更改? “路径”是对“数据”实际内存地址的引用吗?

参数data和局部变量pathint * 您可以将其读作“指向 int 的指针”。

指针是保存内存地址的变量。 不多也不少。 由于您设置了path = data ,这两个指针是相等的。

在您看来, data是一个数组。 但这不是函数dataSwap所看到的。 对于函数dataSwap ,它的参数data只是一个指向 int 的指针。 这个 int 是数组的第一个元素。 您使用data[n_index]访问了数组的元素; 但这只是*(data + n_index)的同义词。

如何解决您的问题?

C 方式: mallocmemcpy

既然要返回一个新数组,就应该返回一个新数组。 为此,您应该使用malloc分配一个新的内存区域,然后使用memcpy将原始数组的值复制到新的内存区域。

请注意,仅使用函数的当前参数是不可能做到这一点的,因为这些参数都没有指示数组的大小:

  • data是指向数组第一个元素的指针;
  • n_index是数组中元素之一的索引;
  • swap_index是数组中另一个元素的索引。*

因此,您应该向函数中添加第四个元素int size ,以指定数组中有多少个元素。 您可以使用size作为mallocmemcpy参数,或者编写一个 for 循环遍历数组的元素。

新问题出现:如果你调用malloc来分配新的内存,那么用户将不得不在某个时刻调用free来释放内存。

C++ 有很酷的关键字new它的语法比malloc的语法要轻一些。 但这并不能解决主要问题; 如果您使用关键字new分配新内存,那么用户将不得不在某个时候使用关键字delete释放内存。

呃,好大的负担!

但这是C方式。 C++ 中的一个很好的经验法则是:永远不要手动处理数组。 标准库为此提供了std::vector 在某些情况下,使用new可能是最好的解决方案; 但在大多数简单的情况下,事实并非如此。

C++ 方式: std::vector

使用标准库中的std::vector类,您的代码变为:

#include <vector>

std::vector<int> Node::dataSwap(std::vector<int> data, int n_index, int swap_index)
{
    std::vector<int> new_data = data;
    int swapped = data[n_index];
    int to_swap = data[swap_index];
    new_data[n_index] = to_swap;
    new_data[swap_index] = swapped;

    return (new_data);
}

没有malloc ,没有new ,没有free也没有delete std::vector在内部处理所有这些。 您也不需要手动复制数据; 初始化new_data = data调用类std::vector的复制构造函数并为您执行此操作。

尽量避免使用new 使用一个在内部处理所有内存的类,就像您在高级语言中所期望的那样。

或者,更简单:

C++ 方式: std::vectorstd::swap

#include <vector>
#include <algorithm>

std::vector<int> Node::dataSwap(std::vector<int> data, int n_index, int swap_index)
{
    std::vector<int> new_data = data;
    std::swap(new_data[n_index], new_data[swap_index]);

    return (new_data);
}

“路径”是对“数据”实际内存地址的引用吗?

是的! 为了创建一个作为传递数据副本数组(仅交换一对值),那么您的函数需要创建新数组(即为其分配数据),复制传递的数据进入它,然后执行交换。 然后,该函数将返回该数据的地址,当不再需要时,该地址应在稍后释放。

但是,为了做到这一点,您还需要将数据数组的大小传递给函数。

使用“旧式”C++ 的一种方法是使用new运算符。 添加“大小”参数后,您的函数将如下所示:

int* Node::dataSwap(int *data, int n_index, int swap_index, int data_size)
{    
    printDatt(data);
    int *path = new int[data_size]; // Create new array...
    for (int i = 0; i < data_size; ++i) path[i] = data[i]; // ... and copy data
    int swapped = data[n_index];
    int to_swap = data[swap_index];
    path[n_index] = to_swap;
    path[swap_index] = swapped;
    printDatt(data);    
    return path; // At some point later on, your CALLING code would "delete[] path"
}

您正在更改指针路径指向的内存,即data 我认为尝试更好地了解指针的工作原理会对您有所帮助。 :)

然后你可以使用 std 库中的交换函数:

std::swap(data[n_index], data[swap_index]);

它会让你的代码更好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM