-2

I have made a simple code to try enigma in C++. I am getting this error on rotor passing function (it is supposed to modify letter depending on the given rotor's letters array)

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

The function is a member of class rotor, I thought the cause is too small stack size, so I changed class constructor to work on dynamic memory - nothing changed

I tried different initalizations. All these produce same error

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

I know that using initalizer list for 28 arguments is not a proper way to initalize such class. Then which method should I use to initalize each rotor with given 26 letters and <=2 notch letters? char array or std::string? Its strange for me to receive sigsegv on accessing class own array inside class function.

I tried checking values

int(letter - 'A')

It produces numbers 0 - 25 which are exactly what I wanted I tried creating whole enigma class both as stack and heap variable, nothing changes.

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}
{}

of course its different for dynamic version

MCVE - compiles and runs perfectly

#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);
}   

I have placed some cout's to see if the class enigma works well with it's rotors members. Now I see something get's wrong

 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];

result

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

Solved
I have found the cause - in a long way program one function was passing indexes 0, 1, 2 instead of 1, 2, 3 (I wanted to enumerate rotors exactly as Wikipedia to avoid confusion)

some pointers are initalized by many **if()**s (for user specefication)

the if() couldnt find any matching instruction for argument 0 which resulted in leaving uninitialized pointer poniting to NULL

Cœur
  • 37,241
  • 25
  • 195
  • 267
Xeverous
  • 973
  • 1
  • 12
  • 25
  • Can you show the code where you initialise `t`? In fact, just show us the class if it's not too complicated. The examples you gave have the type in them, which suggests that maybe you're just hiding the member variable `t` with a local variable? Alternatively, are you copying your `rotor` object and you don't have a proper copy constructor implemented? – Joseph Mansfield Apr 22 '15 at 10:35
  • 1
    Please also add the code where you create the rotor and call that function. – Mat Apr 22 '15 at 10:39
  • `int(letter - 'A')` - That's not how you cast things in C++ – Sinkingpoint Apr 22 '15 at 10:41
  • Have you ever heard about debugger? – SChepurin Apr 22 '15 at 10:47
  • 3
    @SChepurin Their debugger told them "Have you ever heard of Stack Overflow?" – Joseph Mansfield Apr 22 '15 at 10:49
  • The debugger says SIGSEGV, segmentation fault; I have no skill with assembler. Do you mean that class is not being successfully initalized? – Xeverous Apr 22 '15 at 10:51
  • I mean, try to check what you pass as "letter" in the function. – SChepurin Apr 22 '15 at 10:53
  • I tried, std::cout outputs A (which is right) – Xeverous Apr 22 '15 at 10:55
  • @Xeverous It will really help if you can provide an [MCVE](http://stackoverflow.com/help/mcve). We need to see the class and how you use it. – Joseph Mansfield Apr 22 '15 at 10:56
  • Then, show us the class itself. Or even better as Josef Mansfielld and others ask - MCVE. It doesn't help as your info says - "Apparently, this user prefers to keep an air of mystery about them." – SChepurin Apr 22 '15 at 10:56
  • Can you provide the full code please? Something tells me that it's the deferencing of `this` that may be causing the segfault... – brettwhiteman Apr 22 '15 at 11:03

1 Answers1

0

So you haven't provided enough information to solve the problem directly. Perhaps the best answer is to explain how to debug this SIGSEGV.

A SIGSEGV is a Segmentation Fault. (It's called a segmentation fault because the processor architecture uses defines 'segments' for dividing up memory). The operating system generates it when have requested access to an invalid memory location (or attempted to write to a read-only memory location).

Taking your example:

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

And reducing it to the slightly more general case:

a = this->b[c];

The computer is going to do four memory accesses here (in an unoptimized build anyway):

  • Look up the this pointer.
  • Using the this pointer as a base address load the address of b from memory.
  • Add c, multiplied by the size of each element of b, to the b pointer. Read that location.
  • Write to the location of a.

Any one of them could be at fault.

The most common fault

But, the most common mistake is to index outside the array. It's a very common mistake we all make. The easiest way to double check this is to split your instruction into two parts and insert an assert statement:

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

Where that (sizeof(t) / sizeof(*t)) will just be the size of your array. And you may need to just put the number in if you've allocated the array dynamically, e.g.

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

The null pointer

Probably the next most common problem is that something is a null pointer. Have your debugger stop on the problem line and print the values of all the pointers. In this case t and this. If any of them are null or 0 then there's your problem*.

Again it frequently helps to split a complex problem line into multiple statements with an intermediate variable or two.

You can of course insert assert statements to check for null pointers as well. And it's pretty good practice to use them generously in any complicated code. See What is the "assert" function?

Other harder possibilities

It's also perfectly possible that the this pointer, or any other pointer involved was either:

  • Valid and now been deleted.
  • Uninitialized and contains garbage having never referred to a valid location.

These are more of a pain to debug!

However these errors can largely be avoided by using the unique_ptr and shared_ptr classes in later versions of C++.

Worst case

There's also the very awkward possibility that:

Your pointer was overwritten with garbage as as result of a previous error somewhere else in the software.

Clean and rebuild

And finally, if the error makes no sense, always do a clean and rebuild of the whole project. If you are unlucky or your toolchain doesn't properly understand the dependencies of your project, sometimes the code being generated is just wrong.

(* Actually it is possible in some environments to have an valid object at address zero - and also for a null pointer to not be zero - but they are both obscure edge cases ... When was the NULL macro not 0?)

Community
  • 1
  • 1
JCx
  • 2,689
  • 22
  • 32
  • my code does't use other pointers in this scope, and I said earlier, that int(letter - 'A') proudes right (0-25) indexes I will test now if the class is properly initalized by trying to access/set up some values – Xeverous Apr 22 '15 at 12:45
  • Cool - see how you get on - I think I've covered all the possibilities for your crash though. On that initializer question - how about using a straight string "ABCDEFGHIJKLMNOPQRSTUVWXYZ" and indexing it ? The code would be easier to maintain and read I think. – JCx Apr 22 '15 at 12:49