当我在linux mint中调用操作员new时出现分段错误

Segmentation fault when I call operator new in linux mint

本文关键字:new 错误 分段 操作员 调用 linux mint      更新时间:2023-10-16

在Linux Mint上,我使用运算符new来分配内存:

int maxNummber = 1000000;
int* arr = new int[maxNumber];

当我运行代码时,我遇到

flybird@flybird ~/cplusplus_study $ ./a.out 
-412179
Segmentation fault

当我更改maxNumber = 100时,代码运行成功。

命令free -m:的结果

flybird@flybird ~/cplusplus_study $ free -m
              total       used       free     shared    buffers     cached
Mem:          2016        800       1216          0        158        359
-/+ buffers/cache:        283       1733
Swap:         2045          0       2045

这是实际的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <ctime>
#include <memory>
#include <string.h>
#include <iterator>
#include <cstdlib>
using namespace std;
class GenRandomNumber;
class BitMap
{
public:
    BitMap(int n):maxNumer(n)
    {
        int length = 1 + n / BITSPERWORD;
        pData = new int[length];
        memset(pData, 0, length);
    }
    void set(int i)
    {
        pData[i>>SHIFT] |= 1<<(i & MASK); // i&MASK 相当于i%32
    }
    void clear(int i)
    {
        pData[i>>SHIFT] &= ~(1<<(i & MASK)); // i>>SHIFT 相当于 i/32
    }
    bool test(int i)
    {
        return pData[i>>SHIFT] & (1<<(i & MASK));
    }
    void sort(string inputFile, string outputFile)
    {
        ifstream read(inputFile.c_str());
        ofstream write(outputFile.c_str());
        int temp = 0;
        while (read>>temp)
            set(temp);
        for (int i = 0; i < maxNumer; ++i)
        {
            if(test(i))
                write<<i<<endl;
        }
        read.close();
        write.close();
    }
    ~BitMap()
    {
        delete []pData;
        pData = NULL;
    }
private:
    int* pData;
    int maxNumer;
    enum{ SHIFT = 5, MASK = 0x1F, BITSPERWORD = 32};
};
class GenRandomNumber
{
public:
    static GenRandomNumber* genInstance()
    {
        if(!mInstance.get())
            mInstance.reset(new GenRandomNumber());
        return mInstance.get();
    }
    void generate1(string fileName, int m, int maxNumber)
    {
        ofstream outFile(fileName.c_str());
        int* arr = new int[maxNumber];
        for(int i = 0; i < maxNumber; i++)
            arr[i] = i;
        int temp = 0;
        for(int j = 0; j < m; j++)
        {
            temp = randomRange(j, maxNumber - 1);
            cout<<temp<<endl;
            swap(arr[j], arr[temp]);
        }
        copy(arr, arr + m, ostream_iterator<int>(outFile, "n"));
        delete []arr;
        outFile.close();
    }
    void generate2(string fileName, int m, int maxNumber)
    {
        BitMap bitmap(maxNumber);
        ofstream outFile(fileName.c_str());
        int count = 0;
        int temp;
        while (count < m)
        {
            srand(time(NULL));
            temp = randomRange(0, maxNumber);
            cout<<temp<<endl;
            if (!bitmap.test(temp))
            {
                bitmap.set(temp);
                outFile<<temp<<endl;
                count++;
            }
        }
        outFile.close();
    }
private:
    GenRandomNumber(){};
    GenRandomNumber(const GenRandomNumber&);
    GenRandomNumber& operator=(const GenRandomNumber&);
    int randomRange(int low, int high)
    {
        srand(clock()); // better than srand(time(NULL))
        return low + (RAND_MAX * rand() + rand()) % (high + 1 - low);;
    }
    static auto_ptr<GenRandomNumber> mInstance;
};
auto_ptr<GenRandomNumber> GenRandomNumber::mInstance;

int main()
{
    const int MAX_NUMBER = 1000000;
    GenRandomNumber *pGen = GenRandomNumber::genInstance();
    pGen->generate1("test.txt", MAX_NUMBER, MAX_NUMBER);
    BitMap bitmap(MAX_NUMBER);
    bitmap.sort("test.txt", "sort.txt");
    return 0;
}
gdb已经向您提示了错误的来源。您使用swap的唯一位置在此函数中:
void generate1(string fileName, int m, int maxNumber)
{
    ofstream outFile(fileName);
    int* arr = new int[maxNumber];
    for(int i = 0; i < maxNumber; i++)
        arr[i] = i;
    int temp = 0;
    for(int j = 0; j < m; j++)
    {
        temp = randomRange(j, maxNumber - 1);
        cout<<temp<<endl;
        swap(arr[j], arr[temp]); // <----
    }
    copy(arr, arr + m, ostream_iterator<int>(outFile, "n"));
    delete []arr;
    outFile.close();
}

交换两个int不太可能是罪魁祸首,除非你一开始就给它无效的输入。arr[j]非常简单,应该可以,但arr[temp]呢?此处计算temp

temp = randomRange(j, maxNumber - 1);

randomRange函数如下所示:

int randomRange(int low, int high)
{
    srand(clock()); // better than srand(time(NULL))
    return low + (RAND_MAX * rand() + rand()) % (high + 1 - low);;
}

我认为这是你的问题。RAND_MAX * rand()可能会溢出并给你一个大负数。希望这不好的原因显而易见。

1000000可能不会在现代桌面上失败,所以我预计你会在其他地方失败。

查看问题所在:

$ gdb
gdb> file ./a.out
gdb> run
<wait for crash>
gdb> bt full

如果分配失败,您应该会看到一个未捕获的bad_alloc异常。

否则,请发布回溯的源代码和结果。

问题出在randomRange函数中。

return low + (RAND_MAX * rand() + rand()) % (high + 1 - low);;

我不知道,为什么你用rand()乘以(RAND_MAX + 1)(返回值在0RAND_MAX之间),但它会导致溢出,可能是负的。

如果您可以选择C++11,我可以建议使用uniform_int_distribution。它将返回一个介于传递的minmax值之间的数字。

#include <random>
#include <iostream>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(1, 6);
    for (int n=0; n<10; ++n)
        std::cout << dis(gen) << ' ';
    std::cout << 'n';
}

这里有一个问题。CCD_ 19过大,超过了CCD_。当j=m时,arr[j]超出了其边界,因为arr的大小仅为maxNumber。参见堆栈帧#1的信息:m=1606416912, maxNumber=999999

顺便说一句,一个恰当的断言会提醒你这个问题(我是自调试代码的忠实粉丝——我讨厌花时间在调试器下):

void generate1(string fileName, int m, int maxNumber)
{
  assert(!fileName.empty());
  assert(m > 0 && maxNumber > 0);
  assert(m <= maxNumber);
  ...
}

以及回溯:

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x000000010007eef8
std::swap<int> (__a=@0x100200000, __b=@0x10007eef8) at stl_algobase.h:99
99        __a = __b;
(gdb) bt full
#0  std::swap<int> (__a=@0x100200000, __b=@0x10007eef8) at stl_algobase.h:99
    __tmp = 0
#1  0x0000000100000ff1 in GenRandomNumber::generate1 (this=0x7fff5fbffa10, fileName=@0x100200000, m=1606416912, maxNumber=999999) at t.cpp:91
    outFile = {
  <std::basic_ostream<char,std::char_traits<char> >> = {
    <std::basic_ios<char,std::char_traits<char> >> = {
      <std::ios_base> = {
        _vptr$ios_base = 0x7fff745bc350, 
        _M_precision = 6, 
        _M_width = 0, 
        _M_flags = 4098, 
        _M_exception = std::_S_goodbit, 
        _M_streambuf_state = std::_S_goodbit, 
        _M_callbacks = 0x0, 
        _M_word_zero = {
          _M_pword = 0x0, 
          _M_iword = 0
        }, 
        _M_local_word = {{
            _M_pword = 0x0, 
            _M_iword = 0
          }, {
            _M_pword = 0x0, 
            _M_iword = 0
          }, {
            _M_pword = 0x0, 
            _M_iword = 0
          }, {
            _M_pword = 0x0, 
            _M_iword = 0
          }, {
            _M_pword = 0x0, 
            _M_iword = 0
          }, {
            _M_pword = 0x0, 
            _M_iword = 0
          }, {
            _M_pword = 0x0, 
            _M_iword = 0
          }, {
            _M_pword = 0x0, 
            _M_iword = 0
          }}, 
        _M_word_size = 8, 
        _M_word = 0x7fff5fbff910, 
        _M_ios_locale = {
          _M_impl = 0x7fff745c1880
        }
      }, 
      members of std::basic_ios<char,std::char_traits<char> >: 
      _M_tie = 0x0, 
      _M_fill = 0 '', 
      _M_fill_init = false, 
      _M_streambuf = 0x7fff5fbff660, 
      _M_ctype = 0x7fff745c1ab0, 
      _M_num_put = 0x7fff745c1dd0, 
      _M_num_get = 0x7fff745c1dc0
    }, 
    members of std::basic_ostream<char,std::char_traits<char> >: 
    _vptr$basic_ostream = 0x7fff745bc328
  }, 
  members of std::basic_ofstream<char,std::char_traits<char> >: 
  _M_filebuf = {
    <std::basic_streambuf<char,std::char_traits<char> >> = {
      _vptr$basic_streambuf = 0x7fff745bc230, 
      _M_in_beg = 0x100803200 "", 
      _M_in_cur = 0x100803200 "", 
      _M_in_end = 0x100803200 "", 
      _M_out_beg = 0x0, 
      _M_out_cur = 0x0, 
      _M_out_end = 0x0, 
      _M_buf_locale = {
        _M_impl = 0x7fff745c1880
      }
    }, 
    members of std::basic_filebuf<char,std::char_traits<char> >: 
    _M_lock = {
      __sig = 0, 
      __opaque = '' <repeats 55 times>
    }, 
    _M_file = {
      _M_cfile = 0x7fff756bf0a0, 
      _M_cfile_created = true
    }, 
    _M_mode = 48, 
    _M_state_beg = {
      __mbstate8 = '' <repeats 127 times>, 
      _mbstateL = 0
    }, 
    _M_state_cur = {
      __mbstate8 = '' <repeats 127 times>, 
      _mbstateL = 0
    }, 
    _M_state_last = {
      __mbstate8 = '' <repeats 127 times>, 
      _mbstateL = 0
    }, 
    _M_buf = 0x100803200 "", 
    _M_buf_size = 1024, 
    _M_buf_allocated = true, 
    _M_reading = false, 
    _M_writing = false, 
    _M_pback = 0 '', 
    _M_pback_cur_save = 0x0, 
    _M_pback_end_save = 0x0, 
    _M_pback_init = false, 
    _M_codecvt = 0x7fff745c1cf0, 
    _M_ext_buf = 0x0, 
    _M_ext_buf_size = 0, 
    _M_ext_next = 0x0, 
    _M_ext_end = 0x0
  }
}
#2  0x0000000100000a18 in main () at t.cpp:140
    bitmap = {
  pData = 0x7fff5fc005a8, 
  maxNumer = 17
}
    pGen = (GenRandomNumber *) 0x1001000e0

代码中有一个问题可能无法直接解释段故障,但也应引起您的注意。注意,在类BitMap中,构造函数:

BitMap(int n):maxNumer(n)
{
    int length = 1 + n / BITSPERWORD;
    pData = new int[length];
    memset(pData, 0, length);
}

memset的第三个参数是指分配的数组的大小,而不是元素的数量,所以它应该是:

BitMap(int n):maxNumer(n)
{
    int length = 1 + n / BITSPERWORD;
    pData = new int[length];
    memset(pData, 0, length * sizeof(int));
}

原始代码可能会导致问题,因为memset只将分配的数组的一部分初始化为零。剩下的代码可能在逻辑上是错误的,因为类BitMap在成员函数(set、clear、test)中执行二进制运算符,其中所有类都假定pData指向的数组的所有元素都设置为零。