【问题标题】:Segmentation fault: arr[(i * 16) % arrLen] vs arr[i % arrLen]分段错误:arr[(i * 16) % arrLen] vs arr[i % arrLen]
【发布时间】:2012-09-26 10:59:20
【问题描述】:

完成我的任务,another question 中的更多详细信息。如果我使用

arr[(i * 16) % arrLen] *= 2; // seg fault

对比

arr[i % arrLen] *= 2; // OK!

为什么? Full source 见第 31 行。为什么?我对数组长度取模,所以应该没问题?

【问题讨论】:

  • 他们会给你 2 个不同的地址 - 第一个可能无效?
  • 溢出是一种失败模式,它产生负数。
  • 您在 32 位环境中(例如 x86)吗?我在我的 x64 机器上尝试了您的代码,但没有收到任何错误。所以,Hans Passant 和 Alexey Frunze 似乎是对的。

标签: c


【解决方案1】:

i * 16 可以溢出到有符号整数的负范围。当您对负整数取模时,您可以获得负余数,这将使您的数组下标为负数,并导致访问数组分配的内存之外,有时还会导致崩溃。

【讨论】:

    【解决方案2】:

    查看您的完整来源:

    1. 您应该检查 malloc 的返回以确保您能够获得该内存
    2. 你应该释放内存,你有泄漏
    3. 您的 arr 数组中的内存未初始化,您分配它但未将其设置为任何内容,因此您(很可能)得到一个很大的负数。这可以通过memset(arr,0,arrLen); 完成
    4. malloc(arrLen * sizeof(int)) 但是 arrLen 是用 /sizeof(int) 创建的,所以你要取消你在那里的工作......

    关于您的段错误,正如其他人所说的那样,您的数组溢出。您已经创建了一个整数数组。然后你从 0 循环到 reps (268,435,456),这是 int 的最大大小。当您尝试将其乘以 16 时,您会溢出并创建负偏移量。

    尝试将 16 乘以初始化次数:

    int reps = 256 * 1024 * 1024 * 16;
    

    您的编译器应该发出警告,让您知道这一点:

    warning: integer overflow in expression [-Woverflow]
    

    【讨论】:

    • 嗯我没有收到任何错误,我是 C 新手。我想我需要一个标志?关于(3)我怎样才能清零或初始化我的数组?
    • 嗯,这不是错误,而是警告,除非您使用我指出的* 16;,否则您不会看到它。您使用什么编译器/命令来构建?我用代码更新了 3(请注意,由于第 4 点,我只使用 arrLen 作为长度)。
    • RE: (4),实际上,我认为 malloc 是对的吗?我正在分配targetSizesInKB[sizeIndex] * 1024 字节?
    【解决方案3】:

    假设您系统上的int 的大小是32 位,那么您很可能会导致溢出并且i * 16 的结果变为负数。在二进制补码系统中,负值用较高的二进制值表示。

    int reps = 256 * 1024 * 1024;
    

    所以reps = 268,435,456,这是您循环到的值。因此i 的最大值是268,435,455268,435,455 * 16 = 4,294,967,280

    32 位 int 可以表示的最大正值是 2,147,483,6474,294,967,295 表示 unsigned int,因此您还没有环绕负数),这意味着结果被解释为负值。

    arr 访问负偏移量超出了分配的内存范围,这会导致未定义的行为,幸运的是会出现段错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-26
      • 2015-07-31
      • 1970-01-01
      • 2021-09-10
      • 1970-01-01
      • 2012-09-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多