5

Possible Duplicate:
Negative array indexes in C?

Can I use negative indices in arrays?

#include <stdio.h>

int main(void)
{
    char a[] = "pascual";
    char *p = a;

    p += 3;
    printf("%c\n", p[-1]); /* -1 is valid here? */
    return 0;
}
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • 3
    `p` is not an array, it's a pointer *into* an array. `a` is an array and a negative index for `a` will always be invalid. – Jim Balter Oct 05 '12 at 18:35
  • @JimBalter: Incorrect, a negative index for `a` is perfectly valid. What it points to is very good question -- in this example, it's very likely something beneath the current stack frame, and possibly a segfault -- but you can certainly compile `a[-1]` and try to dereference it. [This program](https://gist.github.com/3841654) (dereferencing a negative array) yields "5" on my system. YMMV, depending on struct alignment. – willglynn Oct 05 '12 at 18:47
  • @willglynn: If `a` is the entirety of the array (e.g., not a pointer into an array) then `a[-1]` is not valid. It is undefined per C 2011 6.5.6 8, which requires that addition or subtraction with a pointer into an array yield a pointer to an element within the array or one beyond the end of the array. The paragraph explicitly states “otherwise, the behavior is undefined.” (Further `a[-1]` is, by definition, `*(a+(-1))`, so it contains addition of -1 to the pointer.) – Eric Postpischil Oct 05 '12 at 19:00
  • 1
    @willglynn By "is valid" do you mean "will compile"? I think most of the others here interpret "is valid" to mean "will compile and run with predictable and repeatable results". – Code-Apprentice Oct 05 '12 at 19:29
  • 1
    @willglynn: Agreed with Jim and Code-Guru. You can also compile `int x = *(int*)NULL;` Would you call that valid? You can prove that the code results in UB via static analysis, so I would say no. – Ed S. Oct 05 '12 at 19:33
  • @EricPostpischil I agree that `a[-1]` is undefined, but I don't use the label "invalid" because you can still write, compile, and execute it. After all, "undefined" in C really means "implementation-dependent" -- if you're willing to assume things about your platform, the language will let you. As you point out, the standard doesn't define how array offsets work beyond size + 1, yet a common idiom for structs holding variable-length data is `struct { ...; int length; char variable_length_data[0]; }`. – willglynn Oct 05 '12 at 19:33
  • 1
    @willglynn: "Undefined" does not mean "implementation-dependent", it means "undefined", as in, is *never* defined. "unspecified" means "implementation-dependent". The standard takes care to use the correct term at the correct time, it doesn't just chose from those two randomly. – Ed S. Oct 05 '12 at 19:34
  • @EdS. Yes, that is a perfectly valid pointer dereference. Maybe you `mmap()`d something there (on a platform that permits such things), or maybe you're on an embedded platform where memory location 0 actually corresponds to a physical location in RAM or a memory-mapped peripheral. – willglynn Oct 05 '12 at 19:36
  • 1
    @willglynn: Um, no, it is never, ever valid to dereference a null pointer. Ever. I wrote `0` at first, but that was my mistake. I quickly edited and replaced it with `NULL`. Again, it comes down to what you define as "valid". I think most people would go beyond "does the program compile?", it is a more useful definition. – Ed S. Oct 05 '12 at 19:37
  • 1
    @willglynn 'Incorrect, a negative index for a is perfectly valid.' -- Completely and utterly wrong. 'I don't use the label "invalid" ' -- Lovely sophistry. When you're wrong, just admit it. '"undefined" in C really means "implementation-dependent"' -- completely and utterly wrong. – Jim Balter Oct 05 '12 at 21:02
  • @willglynn 'This program (dereferencing a negative array) yields "5" on my system.' -- It yielded 5 on that particular execution of that particular program at that particular moment. When I said "invalid", I obviously was not referring to whether it would compile ... which it need not. – Jim Balter Oct 05 '12 at 21:08

5 Answers5

8

Yes, -1 is valid in this context, because it points to a valid location in memory allocated to your char a[] array. p[-1] is equivalent to *(p-1). Following the chain of assignments in your example, it is the same as a+3-1, or a+2, which is valid.

EDIT : The general rule is that an addition / subtraction of an integer and a pointer (and by extension, the equivalent indexing operations on pointers) need to produce a result that points to the same array or one element beyond the end of the array in order to be valid. Thanks, Eric Postpischil for a great note.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
3

C 2011 online draft

6.5.6 Additive operators

8 ...if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist....

Emphasis mine. So, in your specific example, p[-1] is valid, since it points to an existing element of a; however, a[-1] would not be valid, since a[-1] points to a non-existent element of a. Similarly, p[-4] would not be valid, a[10] would not be valid, etc.

John Bode
  • 119,563
  • 19
  • 122
  • 198
2

Of course it is valid.

(C99, 6.5.2p1) "One of the expressions shall have type ‘‘pointer to object type’’, the other expression shall have integer type, and the result has type ‘‘type’’.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • You can use negative array indexes because the C language let you use negative integers with the array subscripting operator. IMHO, that's the real reason, after that of course there are restrictions related to pointer arithmetic and if you dereference the pointer, related to the indirection operator. – ouah Oct 05 '12 at 19:19
1

Generally using such negative indexes is a Bad Idea(TM). However, I found one place where this can be useful: trig lookup tables. For such a look up table, we need to use some angle measure as the index. For example, I can index sin values for angles between -180 degrees and +180 using degrees as an index. Or if I want to use radions instead, I can use a multiple of some fraction of PI, say PI/3, for the index. Then I can get cos values between -PI and PI by multiples of PI/3.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
-2

Yes, this is legal, as C lets you do unsafe pointer arithmetic all day. However, this is confusing, so don't do it. See also this answer to the same question.

Community
  • 1
  • 1
willglynn
  • 11,210
  • 48
  • 40
  • 3
    It's neither unsafe nor confusing. – Jim Balter Oct 05 '12 at 18:32
  • Not in the sample code, no -- it's provably safe and near enough to the definition to not be confusing. (Also, my statement is that C permits unsafe arithmetic, not that this is necessarily an example.) That said, I maintain that you'll likely run into trouble after you've broken the operation up across various functions and then hand it to a maintenance coder a few years later, and I argue that it's better to hang onto the original array pointer and use positive offsets instead. – willglynn Oct 05 '12 at 18:39
  • Have to agree mr @JimBalter. There has been occasions where I've done the same, tho not this literally, but doing negative indexing based on location by ptr. I.e. by complex data search. Even by proxy to helpers. – Morpfh Oct 05 '12 at 18:47
  • 'Also, my statement is that C permits unsafe arithmetic, not that this is necessarily an example.' -- You said "don't do it" -- that's a blanket condemnation. – Jim Balter Oct 05 '12 at 21:10