使用不同长度的字符串进行崩溃并且不确定原因

时间:2017-07-14 16:22:58

标签: c

我需要取一个只包含十六进制数字的字符串并将其转换为40的int数组,其中每个空格包含字符串中的一个数字,该数组需要向后填充,因此最低有效数字是第一个数字数组。

如果字符串不包含40个数字,则需要将适量的零填充到数组的末尾。

以下是我正在使用的代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
  char *str = "0123456789aBcdef0123456";

  printf("%s\n", str);

  char *s = strdup(str);

  int i = 0;
  while (s[i]) {
    if (s[i] >= 97 && s[i] <= 122)
      s[i] -= 32;
    i++;
  }
  int amount = 40 - i, under40 = 0, k = 39;

  printf("%s\n   amount:%d\n", s, amount);

  int *digits = malloc(sizeof(int) * 40);

  for (i = 0; i < 40; i++) {

    if (amount > 0) {
      digits[k] = 0;
      under40 = 1;
      amount--;
      i--;
    } else {
      switch (s[i]) {
      case 'A':
        digits[k] = 10;
        break;

      case 'B':
        digits[k] = 11;
        break;

      case 'C':
        digits[k] = 12;
        break;

      case 'D':
        digits[k] = 13;
        break;

      case 'E':
        digits[k] = 14;
        break;

      case 'F':
        digits[k] = 15;
        break;

      default:
        digits[k] = s[i] - 48;
      }
    }
    k--;
  }
  for (i = 0; i < 40; i++)
    printf("%i ", digits[i]);

  if (under40 == 1) {
    fprintf(stderr, "\nUnder 40 digits passed\n");
  }

  return 0;
}

使用当前字符串,在main的第一行,程序崩溃,但任何字符串大于此,它很好,我真的不知道为什么。还有一些具有较短字符串的实例不会崩溃。

这真是令人困惑,因为我不知道为什么有些长度有效,有些长度。例如0123456789aBcdef0123456789869679866896AAAAdddd很好,01234很好。

1 个答案:

答案 0 :(得分:1)

当字符串的长度小于40时,您的循环实际运行超过40次,因为i只要amount为正,就会递减。结果,k变为负数,您最终会在digits数组开始之前写入。在数组范围之外读取和写入会调用undefined behavior

您的循环需要检查k的值,以确保它仍为非负数:

for (i = 0; i < 40 && k >= 0; i++) {

更好的方法是在循环中递减k并仅在需要时递增i

for (i = 0, k = 39; k >= 0; k--) {
    if (amount > 0) {
      digits[k] = 0;
      under40 = 1;
      amount--;
      // don't decrement i here
    } else {
        switch (s[i]) {
            ...
        }
        i++;  // increment here instead
    }
    // no need to decrement k here
}

此外,您可以将switch简化为单个条件(假设ASCII编码,其中'A' - 'F'是顺序的):

digits[k] = (s[i] >= 10) ? s[i] - 'A' + 10 : s[i] - '0';