我目前正在用C ++实现素数筛,我设计了代码,以便我能够控制筛子的大小(通过main函数中的整数文字),但是我得到了一些奇怪的错误一切都在。我在几年内没有使用过C ++,但我记得使用new
和delete
运算符来管理堆内存。
我的问题有点如下......
该程序适用于某些筛子尺寸,但不适用于其他尺寸,并且效果不是严格线性的。例如,如果我制作了大小为10,000的筛子,程序运行正常,但是如果我的大小为1,000,那么程序会因为一个相当神秘的(我的经验值)消息而崩溃,这些消息总是引导我到关于C malloc的页面断言错误(通过谷歌)。此外,该程序适用于10,000 with 删除语句,如果我通过valgrind
运行另一个无用的(对我来说)消息,则会崩溃。结果,我甚至无法在我自己的DX上调试该死的东西
任何智慧的话语?
特别是,为什么程序会从较小的输入中崩溃?理论上,这可能 less 可能导致堆错误,不是吗?此外,为什么valgrind
无法运行程序,而它可以自行运行?我怀疑(再次)这与新/删除操作符的错误或丑陋使用有关,但我不完全确定。对我来说特别令人困惑的部分(约valgrind
)是错误提到我在new
上使用unsigned long
运算符,据我所知 - 不是我做的(至少没有具体)。我认为这是一些与我不熟悉的编译器相关的细节,但我并不完全确定。
代码(带有删除语句;工作时大小为10,000,但不是valgrind
):
using namespace std;
#include <iostream>
#include <cstdlib>
#include <map>
#include <string>
long count_primes(bool* sieve,int size)
{
long count = 0;
for (int a=0;a<size;a++)
{
if (sieve[a])
{
count++;
}
}
return count;
}
int next_prime(bool* primes_so_far,int current_prime,int size)
{
for (int a=current_prime+1;a<size;a++)
{
if (primes_so_far[a]) return a;
}
return -2;
}
int prime_number_sieve(int* primes,int size)
{
if (size<4) return -2;
bool* sieve = new bool[size];
for (int a=0;a<size;a++)
sieve[a] = true;
sieve[0] = false;
sieve[1] = false;
int a=2;
do
{
int b = a;
if (b*a < size) sieve[b*a] = false;
do
{
b++;
sieve[b*a] = false;
} while (b*a < size);
a = next_prime(sieve,a,size);
} while (a*a < size);
long prime_list_size = (long) count_primes(sieve,size);
int* prime_list = new int[prime_list_size];
for (int b=0,c=0;b<size;b++)
{
if (sieve[b]) prime_list[c++] = b;
}
srand(time(NULL));
int rand_int1 = rand();
int rand_int2 = rand();
long rand_num1 = (((long) rand_int1) * prime_list_size)/RAND_MAX;
long rand_num2 = (((long) rand_int2) * prime_list_size)/RAND_MAX;
primes[0] = prime_list[rand_num1];
primes[1] = prime_list[rand_num2];
delete[] sieve;
delete[] prime_list;
return 0;
}
int main()
{
int* prime = new int[2];
prime_number_sieve(prime,10000);
cout << "\n";
cout << prime[0];
cout << "\n";
cout << prime[1];
cout << "\n";
return 0;
}
上面的 valgrind
错误:
==23738== Invalid write of size 1
==23738== at 0x400A4B: prime_number_sieve(int*, int) (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738== by 0x400C31: main (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738== Address 0x5ab83e0 is 0 bytes after a block of size 10,000 alloc'd
==23738== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==23738== by 0x4009CD: prime_number_sieve(int*, int) (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738== by 0x400C31: main (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738==
valgrind: m_mallocfree.c:303 (get_bszB_as_is): Assertion 'bszB_lo == bszB_hi' failed.
valgrind: Heap block lo/hi size mismatch: lo = 4063233, hi = 0.
This is probably caused by your program erroneously writing past the
end of a heap block and corrupting heap metadata. If you fix any
invalid writes reported by Memcheck, this assertion failure will
probably go away. Please try that before reporting this as a bug.
将尺寸更改为1,000时出错:
a.out: malloc.c:2392: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
Aborted (core dumped)
修改
我非常感谢所有(实际)的帮助!感谢下面的答案,程序现在将运行大多数输入(当然不是太大)但我仍然得到Valgrind错误。我并不介意那个,但我很想知道发生了什么。我尝试了下面的建议,将随机素数的选择机制改为(((long) rand_int1) % prime_list_size);
而不是(((long) rand_int1) * prime_list_size)/RAND_MAX
,但我在Valgrind方面没有明显的结果。我仍然无法确切地知道无效堆写入的来源。我将修改代码以查看是否是我的删除,并将报告回来。
答案 0 :(得分:3)
循环
do
{
b++;
sieve[b*a] = false;
} while (b*a < size);
在检查sieve[b*a]
之前是否已分配给b*a < size
。这允许在数组末尾之外分配元素。这是此循环的最后一次迭代的未定义行为。
最好使用std::vector<bool>
[注意它有一些其他向量没有的限制]或std::bitset
,而不是手动使用运算符new
和{{ 1}}。请记住,仍然需要确保您的代码不会脱离标准容器的末尾。
答案 1 :(得分:1)
我可以在你的代码中看到两个问题。
第一个在这里:
do
{
b++;
sieve[b*a] = false;
} while (b*a < size);
这不能阻止写入超出限制size
,因为在分配筛子后发生检查 [b * a] = false;
while (b*a < size)
{
sieve[b*a] = false;
b++;
}
我看到的另一个问题是:
long rand_num1 = (((long) rand_int1) * prime_list_size)/RAND_MAX;
long rand_num2 = (((long) rand_int2) * prime_list_size)/RAND_MAX;
乘法中的项可能导致溢出。我想你想得到一个小于size
的随机索引?你可以这样做:
long rand_num1 = (((long) rand_int1) % prime_list_size);
long rand_num2 = (((long) rand_int2) % prime_list_size);
当然,这不会产生完美的均匀分布,但它会起作用。为了更好地分发,请查看std库的数字随机生成器及其vector
,这对于您正在做的事情来说是一个非常好的工具。