【问题标题】:Memory error in finding prime sum查找素数时的内存错误
【发布时间】:2018-01-20 15:37:41
【问题描述】:

问题:给定一个偶数(大于 2),返回两个素数,其和等于给定数。 解决方案:使用埃拉托色尼筛法找到给定数之前的所有素数。然后找到总和等于给定数字的一对数字。 代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
void primesum(int A)
{
    std::vector<bool> primes(A + 1, 1);
    std::vector<int> arr, final;
    primes[0] = 0;
    primes[1] = 0;

    for (int i = 2; i <= int(sqrt(A)); i++)
    {
        if (primes[i] == 1)
        {
            for (int j = 2; i + j <= A; j++)
            {
                primes[i * j] = 0;
            }
        }
    }
    for (int i = 0; i < primes.size(); i++)
        if (primes[i])
            arr.push_back(i);

    /* for (auto x : primes)
        std::cout << x << " ";
       std::cout << "\n"; */
    std::vector<int>::iterator it;
    for (int i = 0; i < arr.size(); i++)
    {
        it = std::find(arr.begin(), arr.end(), A - arr[i]);
        if (it != arr.end())
        {
            final.push_back(arr[i]);
            final.push_back(A - arr[i]);
            break;
        }
    }
    std::cout << final[0] << " " << final[1] << "\n";
    return;
}
int main()
{
    int x = 184;
    primesum(x);
    return 0;
}

此代码适用于大多数情况,但 x=184 时除外。这种情况下的错误是:

a.out: malloc.c:2394: 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.
[1]    13944 abort (core dumped)  ./a.out

我无法理解为什么会发生这种情况以及它的解决方案是什么?

【问题讨论】:

  • 在调试器中运行代码。此外,打开诊断以检测对容器的超出范围的访问。找出崩溃的地方应该很容易。
  • 使用调试信息构建并使用例如Valgrind 了解您何时何地越界。
  • Dupe。这次也是内存损坏。
  • GCC 有有用的调试编译器扩展,通过在文件顶部定义_GLIBCXX_DEBUG 来开启。
  • 您的第一个循环primes[i * j] = 0; 超过了向量长度

标签: c++ c++11 primes


【解决方案1】:

x=184。那么primes.size() 是185。第一个循环迭代直到i=13。 13是质数。第二个循环迭代直到j=171。在循环中您访问primes[2223]。这是写越界,导致UB。结果,您会得到损坏的动态内存和断言。

看起来你在循环条件中写错了,你想要i * j &lt;= A

【讨论】:

    【解决方案2】:

    使用primes[i * j] = 0,在查找素数时,您的无效索引超出了向量大小,这就是该代码崩溃的原因。您可以将其更正为

    for (int i = 2; i <= int(sqrt(A)); i++)
    {
        if (primes[i] == 1)
        {
            for (int j = 2; i * j <= A; j++)
            {
                primes[i * j] = 0;
            }
        }
    }
    

    【讨论】:

    • 由于向量arr会被默认排序,你可以有更有效的方法来查找总和等于某个数字的2个元素
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-14
    • 2015-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多