c - 奇怪的行为删除 C 字符串中的重复字符

标签 c string undefined-behavior null-terminated

我在用于简单的基于替换的加密的程序中使用以下方法。该方法专门用于去除加解密 key 中的重复字符。

该方法和程序的其余部分一样有效,它适用于我尝试过的 99% 的键。但是,当我向它传递键 "goodmorning" 或以任何顺序包含相同字母的任何键(例如 "dggimnnooor")时,它会失败。此外,包含比 "goodmorning" 更多字符的键,以及包含更少字符的键。

我使用相同的参数通过 lldb 运行了可执行文件,它运行正常。我已经在一台运行 CentOS 的机器上克隆了我的存储库,它可以正常工作。

但是我在编译时没有收到任何警告或错误。

//setting the key in main method
char * key;
key = removeDuplicates(argv[2]);

//return 1 if char in word
int targetFound(char * charArr, int num, char target){
  int found = 0;

  if(strchr(charArr,target))
    found = 1;

  return found;
}

//remove duplicate chars
char * removeDuplicates(char * word){
  char * result;
  int len = strlen(word);
  result = malloc (len * sizeof(char));
  if (result == NULL)
    errorHandler(2);

  char ch;
  int i;
  int j;
  for( i = 0, j = 0; i < len; i++){
    ch = word[i];
    if(!targetFound(result, i, ch)){
      result[j] = ch;
      j++;
    }
  }

  return result;
}

根据请求:如果将 "feather" 传递给此函数,则生成的字符串将为 "feather"

最佳答案

作为R Sahu已经说过,您没有使用 NUL 字符终止您的字符串。现在我不打算解释为什么你需要这样做,但是你总是需要用 NUL 字符来终止你的字符串,也就是 '\0'。如果你想知道为什么,head over here一个很好的解释。然而,这不是您的代码的唯一问题。

主要问题是您调用的函数 strchr 是为了查明您的 result 是否已经包含一些字符 希望您传递一个 NUL 终止字符串,但您的变量未以NUL 终止,因为您不断向其附加字符。

为了解决您的问题,我建议您改用 map 。映射您已经使用的所有字符,如果它们不在 map 中,则将它们同时添加到 map 和结果中。这更简单(无需调用 strchr 或任何其他函数)、更快(无需每次都扫描所有字符串),最重要的是正确。

这是一个简单的解决方案:

char *removeDuplicates(char *word){
    char *result, *map, ch;
    int i, j;

    map = calloc(256, 1);
    if (map == NULL)
        // Maybe you want some other number here?
        errorHandler(2);

    // Add one char for the NUL terminator:
    result = malloc(strlen(word) + 1);
    if (result == NULL)
        errorHandler(2);

    for(i = 0, j = 0; word[i] != '\0'; i++) {
        ch = word[i];

        // Check if you already saw this character:
        if(map[(size_t)ch] == 0) {
            // If not, add it to the map:
            map[(size_t)ch] = 1;

            // And to your result string:
            result[j] = ch;
            j++;
        }
    }

    // Correctly NUL terminate the new string;
    result[j] = '\0';

    return result;
}

为什么这在其他机器上有效,但在您的机器上却无效?

您是未定义行为的受害者。不同系统上的不同编译器以不同方式处理未定义的行为。例如,GCC 可能决定在这种特殊情况下不做任何事情,并让 strchr 继续在内存中搜索,直到找到 '\0' 字符,这是到底发生了什么。您的程序一直在搜索 NUL 终止符并且永远不会停止,因为谁知道 '\0' 可能在您的字符串之后的内存位置?这既危险又不正确,因为程序没有读取为它保留的内存,例如,另一个编译器可能决定在那里停止搜索,并给你一个正确的结果。然而,这不是理所当然的事情,您应该始终避免未定义的行为

关于c - 奇怪的行为删除 C 字符串中的重复字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48821528/

相关文章:

c - 运行时不可整除循环大小对 openMP SIMD 的影响

java - 将字母数字字符串转换为 double

java - 将字符串拆分为 unicode 单词? (特别是越南语)

c++ - 正在通过 const ref undefined 行为捕获新构造的对象

c 程序没有给我错误

c - 为什么在函数中使用字符串参数时退出程序后我的变量损坏(运行时检查失败)

无法编译c代码

objective-c - Cocoa Where to store a secret file 存放Demo安装日期

c++ - 从包含特定字符串的行开始读取

C 编程段错误 : 11