【问题标题】:How to solve segmentation fault error C++如何解决分段错误错误 C++
【发布时间】:2018-09-17 03:54:59
【问题描述】:

我正在编写一个获取整数数组及其逻辑大小的程序。调用时,它会创建一个新数组,其中仅包含数组中的正数。

现在,为了做到这一点,我需要编写一个带有以下参数的 void 类型函数:

(int* arr, int arrSize, int** outPosArrPtr, int* outPosArrSizePTR)

我应该使用指针int** outPosArrPtr 来更新包含正数的数组的基地址,并使用指针outPosArrSizePtr 来更新数组的逻辑大小。

现在,当我在 xcode 编译器上运行我的代码时,逻辑大小会更新为一个非常大的数字。因此,当我尝试使用在线 gdb 编译器运行程序时,我收到错误“分段错误”。

通过阅读分段错误意味着什么,我了解到这意味着我正在尝试访问“不属于我”的内存或不在调用堆栈或程序堆部分中的内存。

我试图通过查看我是否引用任何空指针或查看我是否引用任何悬空指针来调试我的代码,但似乎问题出在另一个问题上。

我的代码:

#include <iostream>

typedef int* IntArrPtr;
using namespace std;


int main() {
    int arrSize;
    int *ptrSize;
    ptrSize = &arrSize;

    cout << "How many integers will this array hold:\n ";
    cin >> arrSize;

    IntArrPtr a;
    a = new int[arrSize];

    fillArr(a, arrSize);

    getPosNums4(a, arrSize,&a, ptrSize);
    cout << "The new size in main is: " << arrSize << endl;

    cout <<"The new array with positive integers is:\n";
    /*for(int i =0; i<arrSize;i++) // this runs for a large size of arrSize
        cout<< a[i] << " ";
    cout<<endl; */
    return 0;
}

void fillArr(int a[], int size){
    cout << "Please enter " << size << " Integers separated by spaces\n";
    cout << "Press enter when finished >\n";
    int i;

    for (i=0;i<size;i++)
        cin >> a[i];

}

void getPosNums4(int* arr, int arrSize, int** outPosArrPtr,int* outPosArrSizePtr){
    IntArrPtr newArr;
    newArr = new int[arrSize];
    int i;
    int newIndx = 0;
    outPosArrSizePtr = &newIndx;//initiliaze the pointer.
    for(i=0;i<arrSize;i++){
        if(arr[i] > 0){
            newArr[newIndx] =arr[i];
            newIndx++;
        }
    }
    arrSize = newIndx;
    *outPosArrSizePtr = arrSize;
    cout << "The new size is of *outPosArrSizeptr is: " << *outPosArrSizePtr << endl;

    for(int j=0;j<newIndx;j++)
        outPosArrPtr[j] = &newArr[j];
    delete []newArr;
    newArr = NULL;
    for(int i=0;i<newIndx;i++)
        arr[i] = *outPosArrPtr[i];

}

一个例子当我在 Xcode 上运行这个程序时:

How many integers will this array hold:
 6
Please enter 6 Integers separated by spaces
Press enter when finished >
3 -1 -3 0 6 4
The new size is of *outPosArrSizeptr is: 3
The new array with positive integers is:
The new size in main is: 7445512
The program ended with exit code: 0

【问题讨论】:

  • 为了说明显而易见的......你很可能应该在 C++ 中使用std::vector。您可以使用reserve 为向量提供大小提示。在使用cin &gt;&gt; x 读取元素后,您可以使用push_back 将元素添加到向量中。应该不会比How to cin to a vector难多少。

标签: c++ arrays pointers segmentation-fault


【解决方案1】:

那里有很多问题,但最关键的一个是为函数的参数赋值对作为参数传递的变量没有影响。
参数是指针并不重要——指针没有什么特别之处。

我认为正在发生的是函数中的“来回复制”循环(我不明白它应该做什么)正在输入数组之外写入,导致未定义的行为,在这种情况下,覆盖main 中的变量。

您的功能过于复杂了。它应该

  • 创建一个新数组
  • 将正值复制到此数组中
  • 使用此数组的地址及其(逻辑)大小更新输出参数

(将输出参数视为返回值并最后处理它们。)

类似这样的:

void getPosNums4(int* arr, int arrSize, int** outPosArrPtr,int* outPosArrSizePtr){
    int* newArr = new int[arrSize];
    int newIndx = 0;
    for (int i = 0; i < arrSize; i++){
        if (arr[i] > 0){
            newArr[newIndx] = arr[i];
            newIndx++;
        }
    }
    *outPosArrPtr = newArr;
    *outPosArrSizePtr = newIndx;
}

你也不应该将指针传递给你的“原始”来修改这个函数,你应该使用新的变量。

int main() {
    int arrSize = 0;
    cout << "How many integers will this array hold:\n ";
    cin >> arrSize;
    int* a = new int[arrSize];
    fillArr(a, arrSize);
    int * positives = nullptr;
    int positiveSize = 0;
    getPosNums4(a, arrSize, &positives, &positiveSize);
    cout << "The new size in main is: " << positiveSize << endl;

    delete [] a;
    delete [] positives;
}

【讨论】:

  • int * positives = nullptr; 和使用new操作符初始化指针一样吗?
  • @SimonGarfe 不,它正在将其初始化为空指针。内存将由getPosNums4 分配。始终初始化变量是一个非常好的习惯。
【解决方案2】:

现代 C++ 使用向量而不是手动分配数组。手动分配容易出现各种非常难以调试的错误。

您的 getPosNums4 方法中的逻辑似乎是个问题。如果我理解要求,它应该在输入数组中查找正整数并将它们复制到新分配的输出数组中。过度分配输出数组不是最优的,但不是实际的错误。

void getPosNums4(int* arr, int arrSize, int** outPosArrPtr,int* outPosArrSizePtr){
    IntArrPtr newArr;
    newArr = new int[arrSize];
    int i;
    int newIndx = 0;
    for(i=0;i<arrSize;i++){
        if(arr[i] > 0){
            newArr[newIndx] =arr[i];
            newIndx++;
        }
    }
    *outPosArrSizePtr = newIndx;
    cout << "The new size is of *outPosArrSizeptr is: " << *outPosArrSizePtr << endl;
    *outPosArrPtr = newArr;
}

注意新分配的数组需要被调用函数删除[],否则会导致内存泄漏。

这是现代 C++ 中的相同程序。请注意,没有使用 new/delete 可以节省很多痛苦。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    vector<int> integer_vector;
    vector<int> positive_vector;

    cout << "Type in integers. Type a Q to continue:" << endl;
    int an_int;
    while(cin >> an_int)
      integer_vector.push_back(an_int);

    for_each(integer_vector.begin(),integer_vector.end(),[&](int const& n){ 
       if(n > 0)
          positive_vector.push_back(n);
    });
    cout <<"The new array with positive integers is:\n";
    for(auto const & element:positive_vector)
        cout<< element << " ";
    cout<<endl; 
    return 0;
}

【讨论】:

  • for_each 是否比更简洁的范围更好?或者,copy_if 不会清楚地表明意图吗?
  • for 的范围很好,但我正在使用 套件和 lamdas,作为 OP 的介绍。 copy_if 有需要预先调用 vector.reserve() 的恼人问题,对吧?好主意,我总是在这里学到更多!
  • vector.reserve 是一种优化,或者可能缺乏过早的悲观化——取决于观点。不调用它不能改变行为,除了执行的复制/移动的数量和分配的数量。看来你还是用 range-for 吧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-29
  • 1970-01-01
  • 2021-11-02
相关资源
最近更新 更多