【问题标题】:variable arbitrary changing value变量任意变化值
【发布时间】:2017-10-09 13:55:56
【问题描述】:

所以,今天我在 C 中实现了一个插入排序算法,发现自己遇到了 THIS (video) 奇怪的错误。

整数变量 arraySize 只是在循环期间更改它自己的值,它甚至不会每次都发生,它是完全随机的,我唯一一次更改 arraySize 值是在代码的开头,当我用值 10。

代码:

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


int main () {
  int y = 0, arraySize = 10, array[1000];
  srand(time(NULL));
  for (int i = 0; i < arraySize; i++) {
    array[i] = rand() % 1000;
  }
  for (int i = 1; i < arraySize; i++) {
    for (int j = i; array[j] <= array[j - 1]; j--) {
      y = array[j - 1];
      array[j - 1] = array[j];
      array[j] = y;
    }
    printf("for externo i = %d, arraySize = %d \n", i, arraySize);
  }
  for (int i = 0; i < arraySize; i++) {
    printf("%d. i = %d ", array[i], i);
  }
  printf("\n");
  return 0;
}

用简单的“gcc insertSort.c”编译后这个确切的程序给我的输出示例

for externo i = 1, arraySize = 10 
for externo i = 2, arraySize = 10 
for externo i = 3, arraySize = 10 
for externo i = 4, arraySize = 5 
10. i = 0 22. i = 1 233. i = 2 343. i = 3 592. i = 4

for externo i = 1, arraySize = 10 
for externo i = 2, arraySize = 10 
for externo i = 3, arraySize = 10 
for externo i = 4, arraySize = 10 
for externo i = 5, arraySize = 10 
for externo i = 6, arraySize = 10 
for externo i = 7, arraySize = 10 
for externo i = 8, arraySize = 10 
for externo i = 9, arraySize = 10 
54. i = 0 239. i = 1 312. i = 2 313. i = 3 438. i = 4 465. i = 5 827. i = 6 839. i = 7 874. i = 8 935. i = 9

for externo i = 1, arraySize = 10 
for externo i = 2, arraySize = 10 
for externo i = 3, arraySize = 10 
for externo i = 4, arraySize = 10 
for externo i = 5, arraySize = 10 
for externo i = 6, arraySize = 10 
for externo i = 7, arraySize = 10 
for externo i = 8, arraySize = 10 
for externo i = 9, arraySize = 6 
10. i = 0 58. i = 1 135. i = 2 316. i = 3 411. i = 4 442. i = 5

我使用的是 xubuntu 16.04,这些是我的 gcc 配置:

使用内置规范。 COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper 目标:x86_64-linux-gnu 配置:../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.4' --with-bugurl=file:///usr/share/doc/gcc-5/ README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable -linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ -- enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify -- enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib /jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5- amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr /share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with -arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64 -linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu 线程模型:posix gcc 版本 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

【问题讨论】:

  • 这必须是第一次有人发布视频来演示错误。恭喜你!
  • for (int j = i; array[j] &lt;= array[j - 1]; j--) 这是罪魁祸首。
  • 当你减少j时,你必须注意j - 1不能低于0。

标签: c linux gcc


【解决方案1】:

在这一行-

for (int j = i; array[j] <= array[j - 1]; j--)  

j 可能会小于 0,这会导致越界访问导致未定义行为。

我不想从 UB 中理解,但结果是你最终会更改堆栈上的其他值,例如 arraySize

一个简单的解决方法是 -

for (int j = i; j > 0 && array[j] <= array[j - 1] ; j--) //Short circuiting prevents UB here. 

而不是上面提到的那一行。

现在这个条件是否适合你的逻辑,那就由你自己去判断了。

【讨论】:

  • 由于array[j - 1]被访问,条件需要为j &gt; 0
【解决方案2】:

这个循环:

for (int j = i; array[j] <= array[j - 1]; j--) {

可以跑出数组的开头(j 变得小于 0),导致未定义的行为。即使j 正好为零,评估循环终止条件也会导致 UB 本身,但更改另一个变量值的最可能的罪魁祸首是循环体中对数组执行的越界修改。

您需要确保您的排序在数组的开头停止。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多