【问题标题】:C - Strange Characters Appear in a StringC - 奇怪的字符出现在字符串中
【发布时间】:2019-04-12 20:11:24
【问题描述】:

我正在尝试用 C 编写一个简单的凯撒密码。我正在创建一个加密函数,它接收一个字符串(char *,要加密的文本)和一个整数(密钥)。

在函数中,我为将接收移位字符的空字符串分配内存。然后,我遍历初始字符串中的每个字符并询问它是否是字母字符(A-z)。如果是,它会根据键移动。如果不是,它只是重复当前字符。问题是:当字符如 !, ?, .甚至空格出现在末尾,它会添加一些“?”给它。我已经放了 printf 语句,我的猜测是正在发生未定义的行为,但我自己无法弄清楚。我希望有一个人可以帮助我。下面是我写的代码和奇怪的结果。

char* encrypt(char* entry, int key) {
    int i = 0;
    key = key % 26;
    char * tmp = (char *)malloc(strlen(entry));
    if (!tmp) {
        printf("Error during allocation.\n");
        return entry;
    }
    //memset(tmp, 0, 1); // Tried with and without it.
    char t;
    while ((t = *(entry + i))) {
        printf("Current letter: %c\n",*(entry+i));
        if ((t >= 65 && t <= 90) || (t >= 97 && t <= 122)) { //is letter 
            *(tmp + i) = t + key > 90 ? t + key - 26 : t + key;
        }
        else { //isnt letter
            printf("No letter char appeared. Code = %d\n",t); 
            *(tmp+i) = t;
        }
        printf("tmp letter: %c\n",*(tmp+i));
        printf("current tmp: %s\n----------------\n",tmp);
        i++;
    }
    printf("final tmp = %s\n",tmp);
    entry = tmp;
    free(tmp);
    return entry;
}

调用函数: encrypt("你好!你好吗?!", 13);

预期(最终)结果:URYYB! UBJ NER LBH?! 实际上(最终)结果:URYYB! UBJ NER LBH?!? (有时它会添加更多的“?”)

调试 printf 语句:

Current letter: H
tmp letter: U
current tmp: U
----------------
Current letter: E
tmp letter: R
current tmp: UR
----------------
...
----------------
Current letter: !
No letter char appeared. Code = 33
tmp letter: !
current tmp: URYYB!
----------------
Current letter:  
No letter char appeared. Code = 32
tmp letter:  
current tmp: URYYB! ? // <<< It added a strange character to the string
----------------
Current letter: H
tmp letter: U
current tmp: URYYB! U // <<< '?' strange character gone
----------------
Current letter: O
tmp letter: B
current tmp: URYYB! UB
----------------
Current letter: W
tmp letter: J
current tmp: URYYB! UBJ // (I)
----------------
Current letter:  
No letter char appeared. Code = 32
tmp letter:  
current tmp: URYYB! UBJ // This time, space didn't raise a strange char after (I)
----------------
...
----------------
Current letter:  
No letter char appeared. Code = 32
tmp letter:  
current tmp: URYYB! UBJ NER ? // Missed me? I'm back
----------------
Current letter: Y
tmp letter: L
current tmp: URYYB! UBJ NER L // ...And gone again
----------------
Current letter: O
tmp letter: B
current tmp: URYYB! UBJ NER LB
----------------
Current letter: U
tmp letter: H
current tmp: URYYB! UBJ NER LBH???
----------------
Current letter: ?
No letter char appeared. Code = 63
tmp letter: ?
current tmp: URYYB! UBJ NER LBH???
----------------
Current letter: !
No letter char appeared. Code = 33
tmp letter: !
current tmp: URYYB! UBJ NER LBH?!?
----------------
final tmp = URYYB! UBJ NER LBH?!?

有人对这种情况有解释吗? 我的系统上的 GCC 信息:

gcc -v
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 9.1.0 (clang-902.0.39.1)
Target: x86_64-apple-darwin17.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

【问题讨论】:

  • 与此问题无关,但您在 free 之后返回了一个指针。释放后,你不能使用它指向的内存。
  • @xing 这确实解决了我的问题!你能给出更深层次的解释吗?谢谢你:)
  • 您将 entry 设置为指向与 tmp 相同的位置,然后释放它。 tmp 和 entry 都指向释放的内存,你不能使用它们。 在你不使用它之后释放内存
  • 如果没有其他内容使用内存,则内容可能可以访问并且相同。但它不能保证并且是未定义的行为。任何事情都可能发生,包括那里的数据。或者崩溃。或随机数据。任何东西。
  • 它不考虑null,它只给出字符串中的字符数。终结者必须始终手动添加,因为它并不总是需要。例如,如果您将字符串写入文件,您想知道要写入多少个字符,而不是多少个加一。

标签: c gcc


【解决方案1】:

tldr;您正在从从未初始化的内存中打印字符串。尝试使用calloc 而不是malloc。

我认为您的示例中发生的情况是您缺少零字节来终止您的字符串。为了了解发生了什么,您必须考虑以下两件事:

  1. C 字符串以零字节结束 (\0)。处理 C 字符串的函数总是期望字符串末尾有一个零字节。如果没有这样的终止符,他们只会假设你的字符串还没有结束。
  2. malloc 不初始化分配的内存。这意味着printf("%s", malloc(10)); 可能会打印或不打印某些内容。这取决于很多因素,因此通常称为“未定义行为”。

回到你的例子:你分配了tmp,但从来没有用零初始化它。但这对于您的打印语句起作用是必需的。所以使用calloc(1, strlen(entry)+1)之类的东西。 (请注意+1。字符串终止符(\0)需要多一个字节)

为了让您了解发生了什么,我建议您在您的malloc-line 之后添加一个memset(tmp, 'X', strlen(entry));。然后尝试理解输出。


旁注:以下内容不会将字符串从tmp 复制到entry。

entry = tmp;
free(tmp);
return entry;

您基本上只是在此处返回tmp,它指向一个已释放的内存块,并将导致函数外的无效内存访问。你要使用的是memcpy。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-13
    • 2021-11-19
    • 1970-01-01
    • 2012-08-15
    • 2011-01-16
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多