Что мне нравится делать с такими проблемами? Пройдитесь по ним. Я считаю, что это часто помогает сделать выводы. Старая добрая отладка с помощью ручки и бумаги. Если вы не можете понять это на бумаге, как вы поймете это на компьютере?! Столько проводов!
Так. Давайте пройдем через это. Сначала нам нужно выбрать поддельный аргумент, чтобы передать его.
Для целей этой демонстрации давайте воспользуемся строкой в стиле C, заканчивающейся NULL, "PASSWOR". Если бы я рисовал этот массив, он мог бы выглядеть так:
['P'].['A'].['S'].['S'].['W'].['O'].['R']
Хорошо, теперь о вашем коде.
char * encrypt (char pw[])
{
int exactsize = strlen(pw) + 2;
char * encPW = new char[exactsize];
int mid = exactsize / 2;
Вот мы и в начале вашей функции. Вы объявили переменную exactsize, используя длину строки и магическое число. Я предполагаю, что вы используете это магическое число для учета терминатора NULL и знака «+», который вы хотите добавить.
Таким образом, с нашим поддельным аргументом «ПАРОЛЬ» мы должны получить strlen() 7, что делает наш «точный размер» 9.
Затем вы выделяете массив символов encPW в качестве этого нового «точного» размера. Вот как теперь выглядит encPW в виде массива символов
// initial value
[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]
// with indices
0 1 2 3 4 5 6 7 8
Затем вы объявляете mid, что, я думаю, мы можем с уверенностью предположить, означает середину. Это немного сложно, потому что вы определяете середину по отношению к вашему новому размеру. Но давайте придерживаться кода под рукой. Поскольку наш exactsize равен 9, средний должен быть 4,5. Но это целое число, поэтому конечный результат равен 4. Мы продолжаем.
strcpy(encPW, pw + mid);
Теперь вы выполняете strcpy в место назначения encPW, начиная с pw + mid
. pw + mid
дает нам указатель на символ 'W' из исходной строки. Он будет копироваться вплоть до терминатора NULL включительно.
// now what do we have?
['W'].['O'].['R'].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]
Затем вы добавляете '+' к строке:
strcat(encPW, "+");
// now what do we have?
[ 'W' ].[ 'O' ].[ 'R' ].[ '+' ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]
Наконец, вы вызываете strncat(), которая добавляет число символов к строке в стиле C, плюс разделитель NULL.
Вы говорите ему записать в строку exactsize - mid
символов. Так как exactsize равен 9, а mid равен 4, мы говорим ему писать 5 символов.
Как мы видели выше, strncat также записывает терминатор NULL. Это 6 символов! Однако, как мы видим (подсчитав 0 в приведенной выше строке), осталось всего 5 символов, прежде чем мы начнем запись в чужую память!
Вот что происходит под капотом (на высоком уровне)
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!
Однако, даже если бы мы не записывались в страшную, загадочную память, алгоритм все равно кажется в корне ошибочным, потому что один из наших персонажей появляется дважды!
Мой вопрос к вам: что такое мид? Как вы намеревались использовать его, когда объявили об этом?
Итак, теперь мы придумали наше простое решение с ручкой и бумагой.
Как бы я решил это:
int mid = strlen(pw) / 2;
И для вашего strncat() я бы использовал
strncat(encPW, pw, mid)
Это решает несколько проблем для нас. Давайте используем два примера: «ПАРОЛЬ» и «ПАРОЛЬ».
При использовании PASSWOR mid будет равен 3
pw + mid будет 'S' (вторая s)
После strcpy encPW будет "SWOR"
После первого strcat будет "SWOR+"
После strncat(encPW, pw, mid)
будет "SWOR+PAS".
Идеал, да?
При использовании PASSWORD mid будет равен 4
pw + mid будет 'W'
После strcpy encPW будет "WORD"
После первого strcat будет "WORD+"
После strncat(encPW, pw, mid)
будет "WORD+PASS".
person
Robert Kelly
schedule
28.01.2014
std::string
по значению — это означает, что она создает локальную копию при вызове, что делает ее использование в качестве перегрузки плохим выбором дизайна. Сделайте этоconst std::string&
, чтобы взять его по ссылке. 3.temp = temp + "+" + temp2;
подумайте о том, что это делает... - person kfsone   schedule 28.01.2014