2010-08-13 4 views
89

난 그냥 몇 가지 코드를 읽고과 같이, 사람이 arr 전에 2 요소에 액세스 할 수 arr[-2]를 사용하는 것을 알 수 있었다 : C에서 음수 배열 색인을 사용할 수 있습니까?

|a|b|c|d|e|f|g| 
     ^------------ arr[0] 
     ^---------- arr[1] 
    ^---------------- arr[-2] 

이 그

를 사용할 수 있습니까?

나는 arr[x]*(arr + x)과 동일하다는 것을 알고 있습니다. 따라서 arr[-2]*(arr - 2)입니다. 괜찮아 보입니다. 어떻게 생각해?

답변

146

맞습니다. C99에서 §6.5.2.1/2

첨자 연산자 []의 정의상가 E1 [E2]을 동일한 때문이다 (* ((E1) + (E2))).

마술이 없습니다. 1-1 등가입니다. 언제나 포인터를 역 참조 (dereferencing) 할 때, 유효한 주소를 가리키고 있는지 확인해야합니다.

+1

UB를 얻기 위해 포인터를 역 참조 할 필요가 없습니다. 'somearray-2' 만 계산하는 것은 결과가 somearray의 시작에서부터 끝까지 1을 넘지 않는 한 정의되지 않습니다. – RBerteig

+20

오래된 책에서'[]'는 포인터 연산을 위해 * 구문 sugar *으로 참조되었습니다. * 즐겨 찾기 * 초보자를 혼란스럽게하는 방법은'arr [1] '대신'1 [arr]'을 쓰고 그게 무슨 뜻인지 짐작하는 것입니다. – Dummy00001

+4

32 비트 int 인덱스가 음수 일 때 64 비트 시스템 (LP64)에서는 어떤 일이 발생합니까? 주소 계산 전에 색인이 64 비트 부호있는 int로 승격되어야합니까? –

10

나에게 잘 들립니다. 그러나 당신이 합법적으로 필요로하는 드문 경우입니다.

+6

예를 들어, 매우 유용합니다. 이웃 운영자와의 이미지 처리. –

59

arr이 배열 또는 그 이후 요소의 두 번째 요소를 가리키는 포인터 인 경우에만 유효합니다. 그렇지 않으면 배열 범위를 벗어나는 메모리에 액세스 할 것이므로 유효하지 않습니다. 따라서, 예를 들어, 이것은 잘못된 것입니다 :

int arr[10]; 

int x = arr[-2]; // invalid; out of range 

그러나 이것은 괜찮을 것 :

int arr[10]; 
int* p = &arr[2]; 

int x = p[-2]; // valid: accesses arr[0] 

음의 첨자를 사용하지만, 이례적인 일이다.

+0

나는 그것이 멀고, 잠재적으로 지저분하다고 말할만큼 멀지 않았다. –

+10

@Matt : 첫 번째 예제의 코드는 정의되지 않은 동작을 산출한다. –

+0

BSTR은 Windows에서 좋은 예입니다. 모든 디버그 할당 자. 그게 잘못이 아니야. –

7

아마도 arr은 배열 중간을 가리키고 있었으므로 arr[-2]은 범위를 벗어나지 않고 원래 배열의 내용을 가리키고있었습니다.

7

나는이게 얼마나 믿을 수 있는지 모르겠지만, 난 그냥 (아마도 LP64)를 64 비트 시스템에 부정적인 배열 인덱스에 대한 다음과 같은 경고를 읽어 http://www.devx.com/tips/Tip/41349

저자는 말하는 것 같다 32 비트 INT 배열 인덱스가 64 비트 주소로 명시 적으로 64 비트 (예 : ptrdiff_t 캐스트)로 승격되지 않으면 64 비트 주소 지정을 사용하는 배열 인덱스가 잘못된 주소 계산을 초래할 수 있습니다. 실제로 PowerPC 버전의 gcc 4.1.0을 사용하여 본성의 버그를 보았습니다. 그러나 컴파일러 버그 (C99 표준에 따라 작동해야합니다) 또는 올바른 동작 (예 : 인덱스가 64로 캐스트해야하는지 여부)을 알지 못합니다. 올바른 행동을위한 비트)?

+3

이것은 컴파일러 버그처럼 들립니다. – tbleher

1

질문에 답을 얻었지만이 설명을 공유하는 데 저항 할 수 없었습니다.

내가 컴파일러 디자인의 원칙을 기억 이의 a를 int 배열 및 INT의 크기입니다 가정 해 봅시다이다 2는 대한 & 자료 주소는 1000

a[5]이 작동 방법 ->

Base Address of your Array a + (index of array *size of(data type for array a)) 
Base Address of your Array a + (5*size of(data type for array a)) 
i.e. 1000 + (5*2) = 1010 

이 설명은 배열의 음수 인덱스가 C에서 작동하는 이유이기도합니다.

내가 a[-5]에 액세스하는 경우 그것은 나에게

Base Address of your Array a + (index of array *size of(data type for array a)) 
Base Address of your Array a + (-5 * size of(data type for array a)) 
i.e. 1000 + (-5*2) = 990 

을 줄 것이다 즉 우리가 왜 정보 C.

1

에 배열에 부정적인 인덱스를 액세스 할 수있는 날이 논리에 의해 위치 990 에 반대 것입니다 돌아갑니다 누군가 음수 인덱스를 사용하고자한다면, 나는 두 가지 상황에서 그들을 사용했다 :

  1. 테이블에 콤비네이션 번호 th at는 당신에게 comb [1] [- 1] = 0; 당신은 항상 테이블에 접근하기 전에 인덱스를 검사 할 수 있지만, 이렇게하면 코드가보다 깨끗 해지고 더 빠르게 실행됩니다.

  2. 테이블의 시작 부분에 센티널을 넣습니다. 예를 들어,

    while (x < a[i]) i--; 
    

같은 것을 사용하고 싶지만 당신은 또한 i이 긍정적임을 확인해야합니다.
해결 방법 : a[-1]-DBLE_MAX이되도록 x&lt;a[-1]이 항상 거짓이되도록하십시오.

관련 문제