SIGSEGV访问类数组

时间:2015-04-22 10:32:35

标签: c++ arrays sigsegv

我已经编写了一个简单的代码来尝试使用C ++中的enigma。 我在转子传递函数上得到这个错误(它应该根据给定的转子字母数组修改字母)

        void pass_through(char& letter)
        {
            //this->t[0] tried it alone - its the cause (cant even std::cout)
            letter = this->t[int(letter - 'A')];
        }

该函数是类转子的成员,我认为原因是堆栈大小太小,所以我改变了类构造函数来处理动态内存 - 没有改变

我尝试了不同的初始化。所有这些产生相同的错误

const char t[26]; const char n[2]
char t[26]; char n[2]
char* t = new char[26]; char* n = new char[2]

我知道使用28个参数的initalizer列表并不是一个适当的方法来初始化这样的类。那么我应该使用哪种方法来给每个转子注入26个字母和< = 2个缺口字母? char数组还是std :: string?我很奇怪在类函数中访问类自己的数组时接收sigsegv。

我尝试检查值

int(letter - 'A')

它产生0到25的数字,这正是我想要的 我尝试将整个enigma类创建为堆栈和堆变量,没有任何变化。

class initalizer

rotor(char A, char B, char C, char D, char E, char F, char G, char H, char I, char J, char K, char L, char M, char N, char O, char P, char Q, char R, char S, char T, char U, char V, char W, char X, char Y, char Z, char n0, char n1)
: t{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z}, n{n0, n1}
{}

当然它与动态版本不同

MCVE - 编译并完美运行

#include <iostream>
#include <conio.h>

using namespace std;

class rotor{
    private:
         const  char t[26]; 
         const  char n[2];  
        //char* t = new char[26];
        //char* n = new char[2]; //NEED TO CREATE DESSTRUCTOR
    public:
        rotor(char A, char B, char C, char D, char E, char F, char G, char H, char I, char J,  char K,  char L,  char M,  char N,  char O,  char P,  char Q,  char R,  char S,  char T,  char U,  char V,  char W,  char X,  char Y,  char Z, char n0,  char n1)
      : t    {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z}, n{n0, n1}
         {}
    public: 
        void make_error(char& letter)
    {    
        cout<<"\n1 - acces letter: "<<letter;
        cout<<"\n2 - show t's index: "<<int(letter - 'A');
            cout<<"\n3 - access one loaction: "<<this->t[0];
        cout<<"\n4 - access desired location: "<<this->t[int(letter - 'A')];
            letter = this->t[int(letter - 'A')];
            cout<<"\n5 - letter after change: "<<letter;
    }    

};



rotor rotor_I('E', 'K', 'M', 'F', 'L', 'G', 'D', 'Q', 'V', 'Z', 'N', 'T', 'O', 'W', 'Y', 'H', 'X', 'U', 'S', 'P', 'A', 'I', 'B', 'R', 'C', 'J', 'Q', 'Q');



int main()
{
    char letter;
cout<<"enter letter: "; letter=getche();
rotor_I.make_error(letter);
}   

我已经放置了一些cout来看看这个类的谜是否适合它的转子成员。现在我看到了一些错误

 rotor* rotors[4]; //for the M4 enigma too, curently just building M3
 //DoAllSetupFunctions(); 
 cout<<"\nrotor[0] address"<<this->rotors[0];
 cout<<"\nrotor[1] address"<<this->rotors[1];
 cout<<"\nrotor[2] address"<<this->rotors[2];

结果

rotor[0]: 0
rotor[1]: 0x4a82d0
rotor[2]: 0x4a82c0

解决
我找到了原因 - 在很长的路程中,一个函数传递的是索引0,1,2而不是1,2,3(我想将转子枚举为维基百科,以避免混淆)

一些指针被许多** if()** s(用于用户识别)初始化

if()无法找到参数0的任何匹配指令,这导致将未初始化的指针留给NULL

1 个答案:

答案 0 :(得分:0)

因此,您没有提供足够的信息来直接解决问题。也许最好的答案是解释如何调试这个SIGSEGV。

SIGSEGV是一个分段错误。 (它被称为分段错误,因为处理器架构使用定义“段”来划分内存)。当请求访问无效的内存位置(或尝试写入只读内存位置)时,操作系统会生成它。

举个例子:

letter = this->t[int(letter) - 'A'];

将其减少到稍微更普遍的情况:

a = this->b[c];

计算机将在这里进行四次内存访问(无论如何都是未经优化的构建):

  • 查找指针。
  • 使用 this 指针作为基地址从内存中加载 b 的地址。
  • c (乘以b的每个元素的大小)添加到 b 指针。阅读该位置。
  • 写入 a 的位置。

他们中的任何一个都可能有过错。

最常见的错误

但是,最常见的错误是在数组外部索引。这是我们所犯的一个非常普遍的错误。仔细检查这个的最简单方法是将指令分成两部分并插入一个断言语句:

auto index = int(letter) - 'A'; 
assert(index >= 0 && index < (sizeof(t) / sizeof(*t));  
letter = this->t[index];

其中(sizeof(t)/ sizeof(* t))将只是数组的大小。如果您已动态分配数组,则可能需要输入数字,例如

auto index = int(letter) - 'A'; 
assert(index >= 0 && index < 26);  
letter = this->t[index];

空指针

可能下一个最常见的问题是某些东西是空指针。让调试器停在问题行上并打印所有指针的值。在这种情况下 t 这个。如果它们中的任何一个为null或0那么就是你的问题*。

同样,经常有助于将复杂问题行拆分为具有中间变量或两个变量的多个语句。

您当然可以插入断言语句来检查空指针。在任何复杂的代码中慷慨地使用它们都是很好的做法。见What is the "assert" function?

其他更难的可能性

这个指针或任何其他指针也很可能是:

  • 有效,现已删除。
  • 未初始化且包含从未提及有效位置的垃圾。

这些更难以调试!

但是,在较高版本的C ++中使用unique_ptr和shared_ptr类可以在很大程度上避免这些错误。

最坏情况

还有一个非常尴尬的可能性:

由于软件中其他地方的先前错误导致您的指针被垃圾覆盖。

清理并重建

最后,如果错误没有意义,请始终对整个项目进行清理和重建。如果您运气不好或者您的工具链无法正确理解项目的依赖关系,有时生成的代码是错误的。

(*实际上在某些环境中有可能在地址0处有一个有效的对象 - 并且对于一个不为零的空指针 - 但它们都是不明显的边缘情况...... When was the NULL macro not 0?