带有指向数组指针的程序重新分配
Procedural realloc with pointer to an array
为了保持代码整洁(并且过于复杂,就像我一直做的那样)我希望 main() 函数将一个 /pointer 传递给一个 int/ 数组给一个函数。然后该函数将按程序扩展数组并添加符合条件的新条目。
我有一个有效的代码,但出于某种原因 valgrind
报告内存泄漏(来自主数组)。而且,我不喜欢在重新分配数组之前必须分配数组的方式。
#include <iostream>
#include <cstdlib>
int get_divisors(int num_input, int *num_result);
int main()
{
int num_input, *num_result = (int*)malloc(sizeof(int));
std::cin >> num_input;
int num_size = get_divisors(num_input, num_result);
for (int loop_1 = 0; loop_1 < num_size; loop_1++){
std::cout << num_result[loop_1] << "\n";
}
free(num_result);
}
int get_divisors(int num_input, int *num_result)
{
int num_count = 0;
for (int loop_1 = 1; loop_1 < num_input; loop_1++){
if (num_input % loop_1 == 0){
num_count++;
num_result = (int*)realloc(num_result, num_count*sizeof(int));
num_result[num_count - 1] = loop_1;
}
}
return num_count;
}
Valgrind: (--leak-check=full --show-leak-kinds=all -v)
==13337== HEAP SUMMARY:
==13337== in use at exit: 72,724 bytes in 2 blocks
==13337== total heap usage: 7 allocs, 6 frees, 72,768 bytes allocated
==13337==
==13337== Searching for pointers to 2 not-freed blocks
==13337== Checked 123,368 bytes
==13337==
==13337== 20 bytes in 1 blocks are definitely lost in loss record 1 of 2
==13337== at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13337== by 0x400A0A: get_divisors(int, int*) (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337== by 0x400964: main (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337==
==13337== 72,704 bytes in 1 blocks are still reachable in loss record 2 of 2
==13337== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13337== by 0x4E9B2AF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==13337== by 0x4010139: call_init.part.0 (dl-init.c:78)
==13337== by 0x4010222: call_init (dl-init.c:36)
==13337== by 0x4010222: _dl_init (dl-init.c:126)
==13337== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==13337==
==13337== LEAK SUMMARY:
==13337== definitely lost: 20 bytes in 1 blocks
==13337== indirectly lost: 0 bytes in 0 blocks
==13337== possibly lost: 0 bytes in 0 blocks
==13337== still reachable: 72,704 bytes in 1 blocks
==13337== suppressed: 0 bytes in 0 blocks
==13337==
==13337== ERROR SUMMARY: 7 errors from 3 contexts (suppressed: 0 from 0)
==13337==
==13337== 1 errors in context 1 of 3:
==13337== Invalid free() / delete / delete[] / realloc()
==13337== at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13337== by 0x4009B7: main (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337== Address 0x5a37c80 is 0 bytes inside a block of size 4 free'd
==13337== at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13337== by 0x400A0A: get_divisors(int, int*) (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337== by 0x400964: main (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337==
==13337==
==13337== 5 errors in context 2 of 3:
==13337== Invalid read of size 4
==13337== at 0x400985: main (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337== Address 0x5a37c80 is 0 bytes inside a block of size 4 free'd
==13337== at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13337== by 0x400A0A: get_divisors(int, int*) (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337== by 0x400964: main (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337==
==13337== ERROR SUMMARY: 7 errors from 3 contexts (suppressed: 0 from 0)
问题:
在您的 get_divisor()
函数中,以下语句重新分配指针:
num_result = (int*)realloc(num_result, num_count*sizeof(int));
但是num_result
是传值的参数,所以你只改变这个局部变量。 main 中的指针保持不变,因此如果内存被移动到另一个地址,您将在 return 从函数中释放重新分配的内存。
快速修复:
您可以通过引用传递指针,以便它实现您的预期方法(即原始指针确实在函数内被修改)。只需更改函数 signature/definition:
int get_divisors(int num_input, int *&num_result); // pass by reference
更好的方法:
首先,你真的应该摆脱 c++ 中的 malloc()
和 realloc()
:它们适用于基本类型,但不尊重更复杂对象的对象生命周期(即对象不是建)。
其次,你不应该重新发明轮子。不要自己管理可变大小的数组,而是选择 vectors:
vector<int> vnum_result(1); // initial size is one.
vnum_result.resize(num_count); // change the size
// no worries about freeing.
当然,按引用或按值传递的问题仍然存在。
你应该习惯 C++ 容器,不要害怕 return 使用容器(查找 return 值优化和复制省略):
#include <iostream>
#include <vector>
std::vector<int> get_divisors(int num_input)
{
std::vector<int> result;
for (int loop_1 = 1; loop_1 < num_input; loop_1++) {
if (num_input % loop_1 == 0) {
result.push_back(loop_1);
}
}
return result;
}
int main()
{
int num_input;
if(std::cin >> num_input) {
std::vector<int> divisors = get_divisors(num_input);
// You may consider a ranged base for: for (int divisor : divisors)
for (std::size_t loop_1 = 0; loop_1 < divisors.size(); loop_1++){
std::cout << divisors[loop_1] << "\n";
}
}
}
为了保持代码整洁(并且过于复杂,就像我一直做的那样)我希望 main() 函数将一个 /pointer 传递给一个 int/ 数组给一个函数。然后该函数将按程序扩展数组并添加符合条件的新条目。
我有一个有效的代码,但出于某种原因 valgrind
报告内存泄漏(来自主数组)。而且,我不喜欢在重新分配数组之前必须分配数组的方式。
#include <iostream>
#include <cstdlib>
int get_divisors(int num_input, int *num_result);
int main()
{
int num_input, *num_result = (int*)malloc(sizeof(int));
std::cin >> num_input;
int num_size = get_divisors(num_input, num_result);
for (int loop_1 = 0; loop_1 < num_size; loop_1++){
std::cout << num_result[loop_1] << "\n";
}
free(num_result);
}
int get_divisors(int num_input, int *num_result)
{
int num_count = 0;
for (int loop_1 = 1; loop_1 < num_input; loop_1++){
if (num_input % loop_1 == 0){
num_count++;
num_result = (int*)realloc(num_result, num_count*sizeof(int));
num_result[num_count - 1] = loop_1;
}
}
return num_count;
}
Valgrind: (--leak-check=full --show-leak-kinds=all -v)
==13337== HEAP SUMMARY:
==13337== in use at exit: 72,724 bytes in 2 blocks
==13337== total heap usage: 7 allocs, 6 frees, 72,768 bytes allocated
==13337==
==13337== Searching for pointers to 2 not-freed blocks
==13337== Checked 123,368 bytes
==13337==
==13337== 20 bytes in 1 blocks are definitely lost in loss record 1 of 2
==13337== at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13337== by 0x400A0A: get_divisors(int, int*) (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337== by 0x400964: main (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337==
==13337== 72,704 bytes in 1 blocks are still reachable in loss record 2 of 2
==13337== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13337== by 0x4E9B2AF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==13337== by 0x4010139: call_init.part.0 (dl-init.c:78)
==13337== by 0x4010222: call_init (dl-init.c:36)
==13337== by 0x4010222: _dl_init (dl-init.c:126)
==13337== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==13337==
==13337== LEAK SUMMARY:
==13337== definitely lost: 20 bytes in 1 blocks
==13337== indirectly lost: 0 bytes in 0 blocks
==13337== possibly lost: 0 bytes in 0 blocks
==13337== still reachable: 72,704 bytes in 1 blocks
==13337== suppressed: 0 bytes in 0 blocks
==13337==
==13337== ERROR SUMMARY: 7 errors from 3 contexts (suppressed: 0 from 0)
==13337==
==13337== 1 errors in context 1 of 3:
==13337== Invalid free() / delete / delete[] / realloc()
==13337== at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13337== by 0x4009B7: main (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337== Address 0x5a37c80 is 0 bytes inside a block of size 4 free'd
==13337== at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13337== by 0x400A0A: get_divisors(int, int*) (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337== by 0x400964: main (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337==
==13337==
==13337== 5 errors in context 2 of 3:
==13337== Invalid read of size 4
==13337== at 0x400985: main (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337== Address 0x5a37c80 is 0 bytes inside a block of size 4 free'd
==13337== at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13337== by 0x400A0A: get_divisors(int, int*) (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337== by 0x400964: main (in /media/areuz/Storage - Linux/1 :: Documents/Programming/2 :: C++ Language/1 :: C++ Codes/Divisibility Check/divisibility)
==13337==
==13337== ERROR SUMMARY: 7 errors from 3 contexts (suppressed: 0 from 0)
问题:
在您的 get_divisor()
函数中,以下语句重新分配指针:
num_result = (int*)realloc(num_result, num_count*sizeof(int));
但是num_result
是传值的参数,所以你只改变这个局部变量。 main 中的指针保持不变,因此如果内存被移动到另一个地址,您将在 return 从函数中释放重新分配的内存。
快速修复:
您可以通过引用传递指针,以便它实现您的预期方法(即原始指针确实在函数内被修改)。只需更改函数 signature/definition:
int get_divisors(int num_input, int *&num_result); // pass by reference
更好的方法:
首先,你真的应该摆脱 c++ 中的 malloc()
和 realloc()
:它们适用于基本类型,但不尊重更复杂对象的对象生命周期(即对象不是建)。
其次,你不应该重新发明轮子。不要自己管理可变大小的数组,而是选择 vectors:
vector<int> vnum_result(1); // initial size is one.
vnum_result.resize(num_count); // change the size
// no worries about freeing.
当然,按引用或按值传递的问题仍然存在。
你应该习惯 C++ 容器,不要害怕 return 使用容器(查找 return 值优化和复制省略):
#include <iostream>
#include <vector>
std::vector<int> get_divisors(int num_input)
{
std::vector<int> result;
for (int loop_1 = 1; loop_1 < num_input; loop_1++) {
if (num_input % loop_1 == 0) {
result.push_back(loop_1);
}
}
return result;
}
int main()
{
int num_input;
if(std::cin >> num_input) {
std::vector<int> divisors = get_divisors(num_input);
// You may consider a ranged base for: for (int divisor : divisors)
for (std::size_t loop_1 = 0; loop_1 < divisors.size(); loop_1++){
std::cout << divisors[loop_1] << "\n";
}
}
}