Frage

I'm writing a password program. Program starts by asking user to input password that includes 8 or more characters that includes a character and punctuation.

After that the program will "encrypt" the password by moving the second half of the password to the front adding a "+" in the middle and then appending the first half to the end.

The problem I'm getting is that whenever I enter a password that is of odd characters it copies the last character twice and is breaking my program. How do I fix this? I know I have to add a condition incase there are odd characters but idk what it should include. Here is my code:

// write a function to encrypt the password:
// return a dynamically allocated C string of the exact size (no extra room) with:
// the last half of the password, the + symbol, and then the first half of the password
char * encrypt (char pw[])
 {
int exactsize = strlen(pw) + 2;
char * encPW = new char[exactsize];
int mid = exactsize / 2;


strcpy(encPW, pw + mid);
strcat(encPW, "+");
strncat(encPW, pw, exactsize - mid);

return encPW;

 }

 // write the same (overloaded) function for a C++ String
 char * encrypt (string pw)
 {
int exactsize = pw.length() + 2;
char * encPW = new char[exactsize];
int mid = exactsize / 2;

string temp(pw, mid);
string temp2(pw, 0 ,mid);
temp = temp + "+" + temp2;

strcpy(encPW, temp.c_str());


return encPW;
}

here is the output i am getting and what i am talking about:
Enter your password: salehrocks93
add punctuation
Enter your password: salehrocks93/
Valid password format. Encrypting...

Encrypted password: cks93/+salehroc

Enter your new password: salehrocks93/
New Encrypted password: cks93/+salehro
1
Press any key to continue . . .

when it asks for the password the first time and encrypts it the c is repeated twice

War es hilfreich?

Lösung

What do I like to do with problems like these? Step through them. I find it often helps to draw things out. Good ole' pen and paper debugging. If you can't figure it out on paper, how will you figure it out in a computer?! There are so many wires!

So. Let's step through it. First we'll need to pick a fake argument to pass it.


For the purposes of this demonstration, let's use the C-style, NULL-terminated string "PASSWOR". If I were to draw this array it might look like this:

['P'].['A'].['S'].['S'].['W'].['O'].['R']

Ok, now onto your code.

char * encrypt (char pw[])
 {
  int exactsize = strlen(pw) + 2;
  char * encPW = new char[exactsize];
  int mid = exactsize / 2;

Here we are at the start of your function. You've declared a variable exactsize using the string's length and a magic number. My guess is you are using this magic number to account for the NULL terminator and the '+' you wish to add.

So, with our fake argument "PASSWOR", we should get a strlen() of 7, making our 'exactsize' 9.

Then you allocate an array of characters, encPW, as this new 'exact' size. Here is what encPW now looks like, as an array of characters

// initial value
[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]
// with indices
  0     1     2     3     4     5     6     7     8

Then you declare mid, which I think we can safely assume means the midpoint. It's a little tricky though because you are determining mid in reference to your new size. But let's stick to the code at hand. Because our exactsize is 9, then mid should be 4.5. But it's an integer, so the end result is 4. We proceed.

strcpy(encPW, pw + mid);

Now you strcpy into the destination of encPW, starting at pw + mid. pw + mid gives us a pointer to the character 'W' from the original string. It will copy up to and including the NULL terminator.

// now what do we have?
['W'].['O'].['R'].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]

Then you append the '+' to the string:

strcat(encPW, "+");
// now what do we have?
[ 'W' ].[ 'O' ].[ 'R' ].[ '+' ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]

Finally, you call strncat(), which appends num characters to a C-style string, plus a NULL terminator.

You are telling it to write exactsize - mid characters to the string. Since exactsize is 9, and mid is 4, we are telling it to write 5 characters.

As we saw above, strncat also writes a NULL terminator. That's 6 characters! However, as we can see (by counting the 0's left in the string above), there are only 5 characters left before we are writing into memory that isn't ours!

Here's what happens under the hood (at a high level)

strncat(encPW, pw, exactsize - mid)
// strncat tries to write this stuff at the end
[ 'W' ].[ 'O' ].[ 'R' ].[ '+' ].[ 'P' ].[ 'A' ].[ 'S' ].[ 'S' ].[ 'W' ].[ 0 ]
                                                                         .^
                                      Uh oh, somebody call the memory police!

However, even if we didn't write into scary, mysterious memory, the algorithm still appears fundamentally flawed, because one of our characters appears twice!


My question for you: what is mid? How did you intend to use it when you declared it?

So now, we come up with our simple pen and paper fix.


How I would solve this:

int mid = strlen(pw) / 2;

And for your strncat() I would use

strncat(encPW, pw, mid)

This solves a few problems for us. Let's use two examples, "PASSWOR" and "PASSWORD".

Using "PASSWOR", mid would be 3

pw + mid would be 'S' (the second s)

After the strcpy encPW would be "SWOR"

After the first strcat, it would be "SWOR+"

After strncat(encPW, pw, mid) it would be "SWOR+PAS".

Ideal, yes?

Using "PASSWORD", mid would be 4

pw + mid would be 'W'

After strcpy encPW would be "WORD"

After the first strcat, it would be "WORD+"

After strncat(encPW, pw, mid) it would be "WORD+PASS".

Andere Tipps

#include <iostream>
#include <string>

void encrypt(const std::string& password)
{
    size_t exactSize = password.length() + sizeof('+') + sizeof('\0');
    size_t mid = exactSize / 2;

    std::cout << "password = " << password
              << ", exactSize = " << exactSize
              << ", mid = " << mid
              << ", password[0,mid) = " << password.substr(0, mid)
              << ", password[mid,npos) = " << password.substr(mid, std::string::npos)
              << '\n';

    std::string t1(password, mid);
    std::string t2(password, 0, mid);

    std::cout << "t1 = " << t1 << ", t2 = " << t2 << '\n';
}

int main()
{
    encrypt("12345678");
    encrypt("123456789");

    return 0;
}

Produces the output http://ideone.com/fork/Y9GsHM

password = 12345678,  exactSize = 10, mid = 5, password[0,mid) = 12345, password[mid,npos) = 678
t1 = 678, t2 = 12345
password = 123456789, exactSize = 11, mid = 5, password[0,mid) = 12345, password[mid,npos) = 6789
t1 = 6789, t2 = 12345

The problem is that exactSize is the result size including the '+' and '\0' and not the size of the source string.

#include <iostream>
#include <string>

void encrypt(const std::string& password)
{
    size_t mid = password.length() / 2;
    size_t exactSize = password.length() + sizeof('+') + sizeof('\0');

    std::cout << "password = " << password
              << ", exactSize = " << exactSize
              << ", mid = " << mid
              << ", password[0,mid) = " << password.substr(0, mid)
              << ", password[mid,npos) = " << password.substr(mid, std::string::npos)
              << '\n';

    std::string t1(password, mid);
    std::string t2(password, 0, mid);

    std::cout << "t1 = " << t1 << ", t2 = " << t2 << '\n';
}

int main()
{
    encrypt("12345678");
    encrypt("123456789");

    return 0;
}

http://ideone.com/E5YFKm

Your C-string version is pretty dodgy too, I made a matching C-string version of the above code.

#include <iostream>
#include <cstring>

void encrypt(const char* password)
{
    size_t len = strlen(password);
    size_t allocSize = strlen(password) + sizeof('+') + sizeof('\0');
    size_t mid = len / 2;

    char left[16];
    char right[16];

    strncpy(left, password, len - mid);
    left[len - mid] = '\0';
    strcpy(right, password + mid);

    std::cout << "password = " << password
              << ", len = " << len
              << ", remainder = " << (len - mid)
              << ", mid = " << mid
              << ", left = " << left
              << ", right = " << right
              << '\n';
}

int main()
{
    std::cout << "begin\n";
    encrypt("12345678");
    encrypt("123456789");

    return 0;
}

http://ideone.com/O6Na9t

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top