【问题标题】:How to Initialize Pointer to a Pointer to NULL Segmentation Fault 11如何初始化指向 NULL 的指针的指针 分段错误 11
【发布时间】:2019-08-19 08:59:53
【问题描述】:

我正在尝试实现一个 van emde boas 树,但是当我调用我的插入函数两次以上时,我得到了分段错误 11。当我尝试在我的插入函数中打印值时,我意识到问题出在我将集群初始化为 NULL 时。我不明白为什么当我使用 for 循环时会出现这种情况。我也尝试使用 calloc 但它给了我同样的错误。我的代码如下所示:

class vEB
{
    int u;
    int *m;
    int *M;
    vEB *summary;
    vEB **cluster;
public:
    vEB(int);
    bool member(int);
    void insert(int);
    void Delete(int);
    int min();
    int max();
    int* pred(int);
    int* succ(int);
};

vEB::vEB(int u){
    this -> u = u;
    this -> m = NULL;
    this -> M = NULL;

    if (u == 2){
        this -> summary = NULL;
        this -> cluster = NULL;
    } else {
        int subSize = (int)sqrt(u);
        this -> summary = new vEB(subSize);
        this -> cluster = new vEB*[subSize];
        for (int i=0;i<=subSize;i++){
            cluster[i]=NULL;
        }

    }
}

bool vEB::member(int x){
    if (u == 2){
        if (m == NULL){
            return false;
        } 
        if (x == 0){
            return ((*m) == 0);
        } else if (x == 1){
            return ((*M) == 1);
        } 
        return false;
    }else{
        if (m == NULL) {
            return false;
        }
        if (x < (*m) || x > (*M)){
            return false;
        }else if (x == (*m) || (x == (*M))){
            return true;
        }else{
            int subSize = (int)sqrt(u);
            int hi = x / subSize;
            int lo = x % subSize;
            if (cluster[hi] == NULL){
                return false;
            } else{
                return cluster[hi] -> member(lo);
            } 
        }

    }
}

void vEB::insert(int x) {
    if (u == 2) {
        if (x == 0) {
            if (m == NULL){
                m = new int;
                M = new int;
                (*m) = (*M) = x;
            } else {
                (*m) = x;
            }
        } else if (x == 1) {
            if (M == NULL){
                m = new int;
                M = new int;
                (*m) = (*M) = x;
            } else{
                (*M) = x;
            } 
        }
    } else {
        if (m == NULL) {
            m = new int;
            M = new int;
            (*m) = (*M) = x;
        } else {
            if (x < (*m)) {
                int currMin = (*m);
                (*m) = x;
                this -> insert(currMin);
            }else {
                int subSize = (int)sqrt(u);
                int hi = x / subSize;
                printf("%d - %d\n",x, hi);
                int lo = x % subSize;
                printf("%d - %d\n",x, hi);
                if (cluster[hi] == NULL){
                    cluster[hi] = new vEB(subSize);
                    cluster[hi] -> insert(lo);
                    summary -> insert(hi);
                }else {
                    cluster[hi] -> insert(lo);
                }
                if (x > (*M)){
                    (*M) = x;
                } 
            }
        }
    }
}

void vEB::Delete(int x){
    if (u == 2) {
        if (x == 0) {
            if ((*M) == 0){
                m = M = NULL;
            } else{
                (*m) = 1;
            } 
        } else if (x == 1) {
            if ((*m) == 1) {
                m = M = NULL;
            }
            else {
                (*M) = 0;
            }
        }
    }else{
        int subSize = (int)sqrt(u);
        int hi = x / subSize;
        int lo = x % subSize;

        if (x == (*m)){
            if (x == (*M)){
                m = M = NULL;
            } else {
                int nextMinHi = summary -> min();
                int nextMinLo = cluster[summary -> min()] -> min();
                int nextMin = nextMinHi * subSize + nextMinLo;
                this -> Delete(nextMin);
                (*m) = nextMin;
            }
        } else {
            cluster[hi] -> Delete(lo);
            if (cluster[hi] -> m == NULL){
                summary -> Delete(hi);
                delete cluster[hi];
                cluster[hi] = NULL;
            }
            if (x == (*M)){
                if (summary -> m == NULL) {
                    (*M) = (*m);
                } else{
                    int nextMaxHi = summary -> max();
                    int nextMaxLo = cluster[summary -> max()] -> max();
                    (*M) = nextMaxHi * subSize + nextMaxLo;
                }
            }
        }
    }
}

int vEB::min() {
    return (*m);
}

int vEB::max() {
    return (*M);
}

int* vEB::pred(int x){
    if (u == 2){
        if (x == 0) {
            return NULL;
        } else if (x == 1){
            if (m == NULL){
                return NULL;
            } 
            if ((*m) == 1){
                return NULL;
            } 
            return m;
        }
        else {
            return NULL;
        }
    } else {
        if (m == NULL) {
            return NULL;
        }
        if (x <= (*m)) {
            return NULL;
        }
        if (x > (*M)) {
            return M;
        }
        int subSize = (int)sqrt(u);
        int hi = x / subSize;
        int lo = x % subSize;
        if (cluster[hi] == NULL){
            int* prev = summary -> pred(hi);
            int* ret = new int;
            (*ret) = (*prev) * subSize + cluster[(*prev)] -> max();
            return ret;
        } else {
            int *newLo, *newHi;
            newHi = new int;
            newLo = new int;
            (*newHi) = hi;
            int minInCluster = cluster[hi] -> min();
            if (lo > minInCluster){
                 newLo = cluster[hi] -> pred(lo);
            }else {
                newHi = summary -> pred(hi);
                (*newLo) = cluster[(*newHi)] -> max();
            }
            int *ret = new int;
            (*ret) = (*newHi) * subSize + (*newLo);
            return ret;
        }
    }
}

int* vEB::succ(int x) {
    if (u == 2) {
        if (x == 1) {
            return NULL;
        }else if (x == 0) {
            if (M == NULL) {
                return NULL;
            }
            if ((*M) == 0) {
                return NULL;
            }
            return M;
        }else {
            return NULL;
        }
    }else{
        if (m == NULL) {
            return NULL;
        }
        if (x >= (*M)) {
            return NULL;
        }
        if (x < (*m)) {
            return m;
        }
        int subSize = (int)sqrt(u);
        int hi = x / subSize;
        int lo = x % subSize;
        if (cluster[hi] == NULL) {
            int* next = summary -> succ(hi);
            int* ret = new int;
            (*ret) = (*next) * subSize + cluster[(*next)] -> min();
            return ret;
        } else {
            int *newLo, *newHi;
            newHi = new int;
            newLo = new int;
            (*newHi) = hi;
            int maxInCluster = cluster[hi] -> max();
            if (lo < maxInCluster){
                newLo = cluster[hi] -> succ(lo);
            }else {
                newHi = summary -> succ(hi);
                (*newLo) = cluster[(*newHi)] -> min();
            }
            int *ret = new int;
            (*ret) = (*newHi) * subSize + (*newLo);
            return ret;
        }
    }
}

int main(){

    vEB *vEB = new class vEB(8);
    vEB -> insert(1);
    vEB -> insert(2);
    vEB -> insert(5);
    vEB -> insert(6);
    vEB -> insert(7);
    printf("%d\n", (*vEB -> pred(2)));
    printf("%d\n", (*vEB -> succ(2)));

    vEB -> Delete(2);

    return 0;
}

是否有适当的方法来初始化指向我不知道的指针的指针?任何建议将不胜感激。谢谢。

【问题讨论】:

  • 对于subSize 元素的数组,最小和最大有效索引是多少?请在构造函数中为你的循环做一些rubber duck debugging
  • 您的调试器显示什么?分段错误发生在哪一行?
  • 它在 cluster[i]=NULL 元素中停止。我的调试器只显示它遇到问题的地方。
  • 这里有一个通用提示,可以更轻松地调试和查找/修复代码中的错误:不要在没有测试的情况下编写大段代码。从一个很小的部分开始,构建它(启用大量警告),修复构建错误和警告,测试。一旦一切正常,编写下一段代码,构建和测试。等等。当出现问题(如崩溃)时,您只有很少的代码可以找到错误,这使得找出错误变得更加容易。

标签: c++ pointers null insert segmentation-fault


【解决方案1】:

虽然逐一错误很糟糕,但您还有一个更严重的错误:可能无限递归。

在您的VEC 构造函数中,您可以检查u == 2,但如果u 是例如3?然后你会进入else 的情况,你会得到3 的平方根,它将被截断为整数1。然后你做new VEC(1),它调用带有值1(不等于2)的构造函数,进入else分支并得到1的平方根,等于1 .然后你就继续new VEC(1)(再一次!)等等。

您需要检查 u &lt;= 2 是否可以避免这种情况。

【讨论】:

    【解决方案2】:

    vEB::vEB(int u)

    for (int i=0;i<=subSize;i++){
           cluster[i]=NULL;
       }
    

    必须

    for (int i=0;i<subSize;i++){
           cluster[i]=NULL;
       }
    

    因为this -&gt; cluster = new vEB*[subSize]; 而不是this -&gt; cluster = new vEB*[subSize+1];

    当我调用我的插入函数两次以上时,我遇到了分段错误 11。

    当您执行vEB -&gt; insert(5); 时,hi 的值太高,cluster[hi] 不在集群 中。

    【讨论】:

    • 我尝试了 i
    • @Aciel 我说的第一个错误是微不足道的,但是是的,您还有其他错误,我编辑了答案,我继续搜索...
    • @Aciel 很难理解你程序的逻辑,然后查找下一个错误的原因。
    • 非常感谢@bruno。我会尽量记下你说的话。
    【解决方案3】:

    这不是您的问题的解决方案,但我希望它有所帮助。 通过一些调试,我发现您的问题出在您调用 insert(5) 时。 产生段错误的代码是:

                    if (cluster[hi] == NULL) {
                    cluster[hi] = new vEB(subSize);
                    cluster[hi]->insert(lo);
                    summary->insert(hi);
                }
                else {
                    cluster[hi]->insert(lo);  //here something is wrong with cluster[hi]
                }
    

    我不知道答案是什么,但是如果您将代码放入 IDE 中并对其进行调试,您就有更好的机会解决问题,因为您比我更了解您的代码。

    【讨论】:

      【解决方案4】:

      我的发现与布鲁诺的相同。这是live test of your code。您可以修复它并再次测试它。

      =========== #0 stensal 运行时消息的开始 ===========

      运行时错误:[越界写入]
      继续执行会导致未定义的行为,中止!

      -
      - Writing 4 bytes to 0x8aaa078 will corrupt the adjacent data.
      - 
      - The memory-space-to-be-written (start:0x8aaa070, size:8 bytes) is allocated at
      -     file:/src/new.cpp::54, 17
      - 
      -  0x8aaa070               0x8aaa077
      -  +------------------------------+
      -  |the memory-space-to-be-written|......
      -  +------------------------------+
      -                                  ^~~~~~~~~~
      -        the write starts at 0x8aaa078 that is right after the memory end.
      - 
      - Stack trace (most recent call first) of the write.
      - [1]  file:/prog.cc::35, 13
      - [2]  file:/prog.cc::290, 10
      
      - [3]  [libc-start-main]
      -
      

      ============#0 stensal 运行时消息结束 ============

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-09
        • 1970-01-01
        • 2019-09-02
        • 1970-01-01
        • 2010-10-11
        • 1970-01-01
        • 1970-01-01
        • 2015-04-28
        相关资源
        最近更新 更多