【问题标题】:Creating a password scrambler创建密码扰码器
【发布时间】:2017-08-25 21:07:23
【问题描述】:

我正在尝试将密码扰码器从 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 文件(编译后)时,它根本不会输出任何内容。我做错了什么以至于无法按预期运行?

【问题讨论】:

  • char cipher[] = { 'k', 's', ..... }char cipher[] = "ksz..."; 怎么样
  • 最好是sizeof(test) / sizeof(char*),这样你实际上得到了数组的长度,而不是它的字节大小。
  • @DavidC.Rankin 为什么' 超过"
  • 在发布的代码中,在 for 循环中,以 result + 开头的行什么也不做。应该是result[i] =

标签: javascript c code-conversion scramble


【解决方案1】:

从评论开始,您的问题比您最初想象的要深一些。首先,您不希望cipher 是一个字符串数组,您只希望它是一个字符数组,例如:

    char cipher[] = "kszhxbpjvcgfqnm";

接下来,您不能返回在函数体中声明的数组。当scramblePassword 返回时,result 的内存被销毁。您的选择是(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];

将所有这些部分放在一起,并回想 mainint 类型并因此返回一个值,您可以执行以下操作:

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

使用/输出示例

这将导致以下内容的可读输出:

$ ./bin/pwscramble

Original : test
Scrambled: ffgf

Original : testtwo
Scrambled: ffgffmb

Original : testthree
Scrambled: ffgffmcff

我将留给您研究该算法实际上应该做什么。如果您还有其他问题,请告诉我。

【讨论】:

  • 另外,确保编译时启用警告,例如-Wall -Wextra 在您的编译字符串中,并且在编译没有任何警告之前从不接受代码。你的代码对你大喊大叫:)我很乐意回答问题,直到你明白为止。了解 C 中的每个字符很重要。
  • 我有一个问题,为什么要使用(int)strlen(string) 而不是strlen(string)
  • 那是一个'nit',但是一个正确的'nit'。 strlen 的返回是 size_t 类型(unsigned 值)。当用于与 iint 进行比较时,将导致 signedunsignedwarning 比较i> 使用-pedantic 编译器选项(我这样做)时的值。所以为了消除警告,我将strlen 的返回值转换为int。这同样适用于(int)(sizeof test/sizeof *test)
  • 嗨,编译时出现以下错误:/tmp/ccII9slW.o: In function scramblePassword': ciph.c:(.text+0x80): undefined reference to floor' collect2: error: ld returned 1 exit status 知道为什么吗?
  • 您需要编译并链接数学库。将-lm添加到编译字符串:)(如果字体显示不清晰,则为小写-LM
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    发生的事情是你变得非常幸运。您的程序在 C 中调用未定义的行为。

    先看这一行

    result + cipher[floor(cc/16)] + cipher[cc%16];
    

    首先,它没有做任何事情。那只是一个被抛弃的表达方式。你真正想要的是:

    result += cipher[floor(cc/16)] + cipher[cc%16];
    

    但它仍然行不通,因为 C 并没有真正的字符串概念。字符串实际上只是以 '\0' 结尾的字符序列。 result 只是一个指向这样一个序列的指针,与任何其他指针一样,当您向其中添加内容时,您只需增加指针指向的位置。

    此外,返回 *result 实际上会取消引用指针并返回它所指向的内容。

    声明

    result = "";
    

    在某处分配一点内存,空字节序列以\0 结尾,即单个 nul 字节。在堆栈上(或在寄存器中,取决于实现),结果被分配并给出 nul 字节的地址。

    当您返回 *result 时,您会返回 nul 字节,但调用者认为您正在返回一个指针,因此它将将该 nul 字节解释为指针(我很惊讶您的代码在实际编译时没有给出错误)和该指针可能是一个空指针。

    在 C 中连接字符串是一个棘手的操作。您必须使用strcat 或其更安全的衍生产品之一。您必须确保为结果分配足够的空间,并且必须使用 malloc 动态执行此操作,因为当您从分配它们的函数返回时,本地分配的字符串会消失。

    编辑

    还有一件事....

    C 有不止一种数字数据类型。当您将一个整数除以另一个时,您会得到一个整数结果。如果 cc 不能被 16 整除,则结果已经是 floor(cc/16)

    【讨论】:

    • 它会给出警告,但不会出现任何错误,我只是根据 cmets 稍微编辑了一下,得到了一个我还没有看到的新警告:ciph.c:(.text+0x5a): undefined reference to floor'`
    • floor 是一个 C 库函数。我之前用 gcc 看到过,如果程序中没有使用浮点的迹象,它不会链接浮点函数,这是另一个问题...
    • 你需要链接-lm才能使用floor功能,但是你真的需要地板功能吗?
    猜你喜欢
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    • 2014-09-13
    • 1970-01-01
    • 2013-09-06
    • 2010-11-28
    • 1970-01-01
    • 2014-06-27
    相关资源
    最近更新 更多