创建密码扰码器
Creating a password scrambler
我正在尝试将密码加密器从 Javascript
复制到 C
。它所做的是获取字母的 ASCII 字符代码、将其取整、划分,然后从给定列表中获取一个随机字符。
Javascript版本:
function getScrambledPassword(pwd) {
var cipher = ['k', 's', 'z', 'h', 'x', 'b', 'p', 'j', 'v', 'c', 'g', 'f', 'q', 'n', 't', 'm'];
var result="";
if (pwd == null)
pwd = "";
pwd = encodeURIComponent(pwd);
//alert("encoded password: " + pwd);
for(var i=0;i<pwd.length;i++) {
var cc = pwd.charCodeAt(i);
result += cipher[Math.floor(cc/16)] + cipher[cc%16];
}
//alert("scrambled password: " + result);
return result;
}
扰码器示例 运行:https://jsfiddle.net/w5db66va/
到目前为止我做了什么:
#include <stdio.h>
#include <math.h>
#include <string.h>
static char *scramblePassword(char *pwd)
{
char *cipher[] = {
"k", "s", "z", "h",
"x", "b", "p", "j",
"v", "c", "g", "f",
"q", "n", "t", "m"
};
char *result = "";
for(int i=0; i < strlen(pwd); i++)
{
int cc = (int) pwd[i];
printf("%d", cc);
result + cipher[floor(cc/16)] + cipher[cc%16];
}
return *result;
}
int main(void)
{
char *test[] = {"test", "testtwo", "testthree"};
for (int i=0;i < sizeof(test); i++)
{
printf("Original: %s", test[i]);
printf("Scrambled: %s", scramblePassword(test[i]));
}
}
我遇到的问题是,当我 运行 c
文件(编译后)时,它根本不会输出任何内容。我做错了什么以至于我无法像我期望的那样将其设置为 运行?
发生的事情是你变得非常幸运。您的程序调用了 C 中的未定义行为。
先看这一行
result + cipher[floor(cc/16)] + cipher[cc%16];
首先,它什么都不做。那只是一个被扔掉的表达。你真正想要的是:
result += cipher[floor(cc/16)] + cipher[cc%16];
但它仍然行不通,因为 C 并没有真正的字符串概念。字符串实际上只是以“\0”结尾的字符序列。 result
只是一个指向这样一个序列的指针,和任何其他指针一样,当你向它添加一些东西时,你只是增加了指针指向的位置。
此外,returning *result
实际上取消了指针的引用,return它指向的是什么。
声明
result = "";
在某处分配一些内存,其中包含以 [=15=]
结尾的空字节序列,即单个 nul 字节。在堆栈上(或在寄存器中,具体取决于实现),结果被分配并给出 nul 字节的地址。
当你 return *result
你 return nul 字节但调用者认为你是 return 一个指针,所以它会将那个 nul 字节解释为一个指针(我很惊讶你的代码在实际编译时没有给出错误)并且该指针可能是一个空指针。
在 C 中连接字符串是一个棘手的操作。您必须使用 strcat
或其更安全的衍生物之一。您必须确保为结果分配足够的 space 并且您必须使用 malloc 动态地执行它,因为当您从分配它们的函数中 return 时,本地分配的字符串就会消失。
编辑
还有一件事....
C 有不止一种数字数据类型。当您将一个整数除以另一个整数时,您会得到一个整数结果。如果 cc 不能被 16 整除,结果已经是 floor(cc/16)
C 不是 JS。
有很多细微的问题,您的程序甚至无法编译。
你可能想要这个:
#include <stdio.h>
#include <math.h>
#include <string.h>
static char *scramblePassword(char *pwd, char *result)
{
char cipher[] = { // you need an array of chars here, not an
// array of pointers to char
'k', 's', 'z', 'h',
'x', 'b', 'p', 'j',
'v', 'c', 'g', 'f',
'q', 'n', 't', 'm'
};
size_t i;
for (i = 0; i < strlen(pwd); i++)
{
int cc = (int)pwd[i];
//printf("%d", cc);
result[i] = cipher[/*(int)floor*/(cc / 16)] + cipher[cc % 16];
// ^ actually you can drop the floor function,
// there is no floating point here, so integer
// division will do the job
}
result[i] = 0; // this will NUL terminate the string
return result;
}
int main(void)
{
char *test[] = { "test", "testtwo", "testthree" };
for (int i = 0; i < sizeof(test) / sizeof(test[0]); i++)
// ^ the number of elements is not sizeof(test)
// (that's the number of bytes the array takes in memory
// but sizeof(test) / sizeof(test[0])
{
char result[100]; // you cannot return arrays in C, you need to provide
// the array and pass the pointer to your function
printf("Original: %s\n", test[i]);
printf("Scrambled: %s\n", scramblePassword(test[i], result));
}
}
继续评论,您的问题 运行 比您最初想象的要深一些。首先,您不希望 cipher
是一个 字符串数组 ,您只是希望它是一个字符数组,例如:
char cipher[] = "kszhxbpjvcgfqnm";
接下来,您不能 return 在函数体内声明的数组。 result
的内存在 scramblePassword
return 时被销毁。您的选择是 (1) 在 scramblePassword
中动态分配 result
(并在 main
中释放它),或 (2) 在 main
中为 result
声明存储和将其作为参数传递给 scramblePassword
。例如:
#define MAX 32
static char *scramblePassword (char *pwd, char *result)
{
...
return result;
}
int main(void)
{
char result[MAX] = "";
...
printf ("Scrambled: %s\n", scramblePassword (test[i], result));
最后,如果您的算法打算从 cipher
构建一个乱序字符数组,将导致选择超出 cipher
范围的索引,从而导致 未定义的行为。如果目的只是为 result[x]
分配一个值,而不管它是否是有效的可打印 ASCII 值,那么它可能没问题。但是,如果第一个是您的目标,则算法的结果必须始终产生一个在 cipher
范围内的值,例如类似于:
result[i] = cipher[((int)floor (cc / 16) + cc % 16) % sizeof cipher];
将所有这些部分放在一起,回想一下 main
是 int
类型,因此 return 是一个值,您可以这样做:
#include <stdio.h>
#include <math.h>
#include <string.h>
#define MAX 32
static char *scramblePassword (char *pwd, char *result)
{
char cipher[] = "kszhxbpjvcgfqnm";
int i;
for (i = 0; i < (int)strlen (pwd); i++)
{
int cc = (int) pwd[i];
// result[i] = cipher[(int)floor (cc / 16)] + cipher[cc % 16];
result[i] = cipher[((int)floor (cc / 16) + cc % 16) % sizeof cipher];
}
result[i] = 0; /* you MUST nul-terminate to use as a string */
return result;
}
int main(void)
{
char *test[] = {"test", "testtwo", "testthree"};
char result[MAX] = "";
for (int i = 0; i < (int)(sizeof test/sizeof *test); i++)
{
printf ("\nOriginal : %s\n", test[i]);
printf ("Scrambled: %s\n", scramblePassword (test[i], result));
}
return 0;
}
例子Use/Output
这将导致可读输出:
$ ./bin/pwscramble
Original : test
Scrambled: ffgf
Original : testtwo
Scrambled: ffgffmb
Original : testthree
Scrambled: ffgffmcff
我将留给您研究该算法实际应该做什么。如果您还有其他问题,请告诉我。
我正在尝试将密码加密器从 Javascript
复制到 C
。它所做的是获取字母的 ASCII 字符代码、将其取整、划分,然后从给定列表中获取一个随机字符。
Javascript版本:
function getScrambledPassword(pwd) {
var cipher = ['k', 's', 'z', 'h', 'x', 'b', 'p', 'j', 'v', 'c', 'g', 'f', 'q', 'n', 't', 'm'];
var result="";
if (pwd == null)
pwd = "";
pwd = encodeURIComponent(pwd);
//alert("encoded password: " + pwd);
for(var i=0;i<pwd.length;i++) {
var cc = pwd.charCodeAt(i);
result += cipher[Math.floor(cc/16)] + cipher[cc%16];
}
//alert("scrambled password: " + result);
return result;
}
扰码器示例 运行:https://jsfiddle.net/w5db66va/
到目前为止我做了什么:
#include <stdio.h>
#include <math.h>
#include <string.h>
static char *scramblePassword(char *pwd)
{
char *cipher[] = {
"k", "s", "z", "h",
"x", "b", "p", "j",
"v", "c", "g", "f",
"q", "n", "t", "m"
};
char *result = "";
for(int i=0; i < strlen(pwd); i++)
{
int cc = (int) pwd[i];
printf("%d", cc);
result + cipher[floor(cc/16)] + cipher[cc%16];
}
return *result;
}
int main(void)
{
char *test[] = {"test", "testtwo", "testthree"};
for (int i=0;i < sizeof(test); i++)
{
printf("Original: %s", test[i]);
printf("Scrambled: %s", scramblePassword(test[i]));
}
}
我遇到的问题是,当我 运行 c
文件(编译后)时,它根本不会输出任何内容。我做错了什么以至于我无法像我期望的那样将其设置为 运行?
发生的事情是你变得非常幸运。您的程序调用了 C 中的未定义行为。
先看这一行
result + cipher[floor(cc/16)] + cipher[cc%16];
首先,它什么都不做。那只是一个被扔掉的表达。你真正想要的是:
result += cipher[floor(cc/16)] + cipher[cc%16];
但它仍然行不通,因为 C 并没有真正的字符串概念。字符串实际上只是以“\0”结尾的字符序列。 result
只是一个指向这样一个序列的指针,和任何其他指针一样,当你向它添加一些东西时,你只是增加了指针指向的位置。
此外,returning *result
实际上取消了指针的引用,return它指向的是什么。
声明
result = "";
在某处分配一些内存,其中包含以 [=15=]
结尾的空字节序列,即单个 nul 字节。在堆栈上(或在寄存器中,具体取决于实现),结果被分配并给出 nul 字节的地址。
当你 return *result
你 return nul 字节但调用者认为你是 return 一个指针,所以它会将那个 nul 字节解释为一个指针(我很惊讶你的代码在实际编译时没有给出错误)并且该指针可能是一个空指针。
在 C 中连接字符串是一个棘手的操作。您必须使用 strcat
或其更安全的衍生物之一。您必须确保为结果分配足够的 space 并且您必须使用 malloc 动态地执行它,因为当您从分配它们的函数中 return 时,本地分配的字符串就会消失。
编辑
还有一件事....
C 有不止一种数字数据类型。当您将一个整数除以另一个整数时,您会得到一个整数结果。如果 cc 不能被 16 整除,结果已经是 floor(cc/16)
C 不是 JS。
有很多细微的问题,您的程序甚至无法编译。
你可能想要这个:
#include <stdio.h>
#include <math.h>
#include <string.h>
static char *scramblePassword(char *pwd, char *result)
{
char cipher[] = { // you need an array of chars here, not an
// array of pointers to char
'k', 's', 'z', 'h',
'x', 'b', 'p', 'j',
'v', 'c', 'g', 'f',
'q', 'n', 't', 'm'
};
size_t i;
for (i = 0; i < strlen(pwd); i++)
{
int cc = (int)pwd[i];
//printf("%d", cc);
result[i] = cipher[/*(int)floor*/(cc / 16)] + cipher[cc % 16];
// ^ actually you can drop the floor function,
// there is no floating point here, so integer
// division will do the job
}
result[i] = 0; // this will NUL terminate the string
return result;
}
int main(void)
{
char *test[] = { "test", "testtwo", "testthree" };
for (int i = 0; i < sizeof(test) / sizeof(test[0]); i++)
// ^ the number of elements is not sizeof(test)
// (that's the number of bytes the array takes in memory
// but sizeof(test) / sizeof(test[0])
{
char result[100]; // you cannot return arrays in C, you need to provide
// the array and pass the pointer to your function
printf("Original: %s\n", test[i]);
printf("Scrambled: %s\n", scramblePassword(test[i], result));
}
}
继续评论,您的问题 运行 比您最初想象的要深一些。首先,您不希望 cipher
是一个 字符串数组 ,您只是希望它是一个字符数组,例如:
char cipher[] = "kszhxbpjvcgfqnm";
接下来,您不能 return 在函数体内声明的数组。 result
的内存在 scramblePassword
return 时被销毁。您的选择是 (1) 在 scramblePassword
中动态分配 result
(并在 main
中释放它),或 (2) 在 main
中为 result
声明存储和将其作为参数传递给 scramblePassword
。例如:
#define MAX 32
static char *scramblePassword (char *pwd, char *result)
{
...
return result;
}
int main(void)
{
char result[MAX] = "";
...
printf ("Scrambled: %s\n", scramblePassword (test[i], result));
最后,如果您的算法打算从 cipher
构建一个乱序字符数组,将导致选择超出 cipher
范围的索引,从而导致 未定义的行为。如果目的只是为 result[x]
分配一个值,而不管它是否是有效的可打印 ASCII 值,那么它可能没问题。但是,如果第一个是您的目标,则算法的结果必须始终产生一个在 cipher
范围内的值,例如类似于:
result[i] = cipher[((int)floor (cc / 16) + cc % 16) % sizeof cipher];
将所有这些部分放在一起,回想一下 main
是 int
类型,因此 return 是一个值,您可以这样做:
#include <stdio.h>
#include <math.h>
#include <string.h>
#define MAX 32
static char *scramblePassword (char *pwd, char *result)
{
char cipher[] = "kszhxbpjvcgfqnm";
int i;
for (i = 0; i < (int)strlen (pwd); i++)
{
int cc = (int) pwd[i];
// result[i] = cipher[(int)floor (cc / 16)] + cipher[cc % 16];
result[i] = cipher[((int)floor (cc / 16) + cc % 16) % sizeof cipher];
}
result[i] = 0; /* you MUST nul-terminate to use as a string */
return result;
}
int main(void)
{
char *test[] = {"test", "testtwo", "testthree"};
char result[MAX] = "";
for (int i = 0; i < (int)(sizeof test/sizeof *test); i++)
{
printf ("\nOriginal : %s\n", test[i]);
printf ("Scrambled: %s\n", scramblePassword (test[i], result));
}
return 0;
}
例子Use/Output
这将导致可读输出:
$ ./bin/pwscramble
Original : test
Scrambled: ffgf
Original : testtwo
Scrambled: ffgffmb
Original : testthree
Scrambled: ffgffmcff
我将留给您研究该算法实际应该做什么。如果您还有其他问题,请告诉我。