2017-05-10 2 views
0

그래서 오늘 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의 insertionSort.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 
로 컴파일 된 후3210

xubuntu 16.04를 사용하고 있습니다. gcc 구성입니다.

내장 사양 사용. COLLECT_GCC = GCC COLLECT_LTO_WRAPPER =/USR/LIB/GCC/x86_64에-리눅스 GNU 대상/5/LTO-래퍼 : ../src/configure -v --with-pkgversion : x86_64에-리눅스 GNU 함께 구성된 = 'Ubuntu 5.4.0-6ubuntu1 ~ 16.04.4'--with-bugurl = file : ///usr/share/doc/gcc-5/README.Bugs --enable-languages ​​= c, ada, C++, java/lib/lib/lib/lib/lib/lib/lib/lib/lib/lib/lib/-libdir =/usr/lib --enable-nls --with-sysroot =/--enable-clocale = gnu --enable-libstdcxx-debug - libstdcxx-time = yes --with-default-libstdcxx-abi = new - 사용 가능 -gnu-unique-object - 사용 불가 -vtable-verify - 사용 가능 -libmpx - 사용 가능 - 플러그인 --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-arch-directory = amd64 --with-ecj-jar =/usr/share/java/eclipse-ecj.jar - 사용 가능 -objc-gc - 사용 가능 -multarch - 사용 불가능 - werror --with-arch- 32 = i686 --with-abi = m64 --with-multilib-list = m32, m64, mx32 - enableable-multilib --with-tune = 일반 - 사용 가능 확인 = release --build = x86_64-linux- GNU --host = x86_64에-리눅스 GNU --target = x86_64에-리눅스 GNU 스레드 모델 : POSIX GCC 버전이 라인에서 5.4.0 20160609 (우분투 5.4.0-6ubuntu1 ~ 16.04.4)

+0

누군가가 오류를 설명하기 위해 비디오를 게시 한 * 처음 * 시간이어야합니다. 그래서 축하해! –

+0

for (int j = i; array [j] <= 배열 [j - 1]; j--)'이것은 범인입니다. –

+0

'j'를 줄이면'j-1'이 0 이하로 떨어지지 않도록주의해야합니다. –

답변

1

-

j는 잠재적으로 0보다 작아 질 수 있으며, 이로 인해 아웃 오브 바운드 엑세스 정의되지 않은 행동으로 이어진다.

UB를 이해하고 싶지는 않지만 arraySize과 같은 스택의 다른 값을 변경하면 어떻게됩니까? 대신에 위에서 언급 한 라인의

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

-이 될 것이라고위한

하나 개의 간단한 수정.

이제이 조건이 논리에 적합한 지 여부를 알아 내야합니다.

+0

'array [j - 1]'에 접근 했으므로 조건은''j> 0'이되어야합니다. –

+0

@JohnBollinger 예. 고칠 것입니다. –

+0

고마워요! 나는 결코 그것을 상상하지 않을 것이다. 롤! –

0

이 루프 :

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

는 정의되지 않은 동작 결과 (j이 0 미만이되는) 어레이의 시작을 실행할 수있다.루프 종료 조건을 평가하면 j이 정확히 0이지만 UB가 모두 발생하지만 다른 변수의 값을 변경하는 가장 큰 원인은 루프 본문에서 수행 된 배열에 대한 범위를 벗어난 수정입니다.

배열 시작 부분에서 정렬을 중지해야합니다.

관련 문제