Accessing Arrays by Index[Array] in C and C++

Accessing arrays by index[array] in C and C++

Yes. 6.5.2.1 paragraph 1 (C99 standard) describes the arguments to the [] operator:

One of the expressions shall have type "pointer to object type", the other expression shall have integer type, and the result has type "type".

6.5.2.1 paragraph 2 (emphasis added):

A postfix expression followed by an expression in square brackets [] is a subscripted
designation of an element of an array object. The definition of the subscript operator []
is that E1[E2] is identical to (*((E1)+(E2)))
. Because of the conversion rules that
apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the
initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th
element of E1 (counting from zero).

It says nothing requiring the order of the arguments to [] to be sane.

Accessing array elements in c

arr++ is not working but i want to know why?

arr stores the base address that is &arr[0] therefore, arr always points to the starting position of the array and can't be changed. that's the reason why arr++ is invalid and doesn't work.


Solution:

you can instead use arr with the help of * (referencing operator) operator to print the array elements

for(i=0;i<5;i++)
{
printf("%d\n",*(arr+i));
//pointer arithmetic *(arr+i)=*(&arr[0]+i*sizeof(data_type_of_arr))
}

here, pointer arithmetic is helpful to understand


or else, in order to print the data instead use the index i this way :

for(i=0;i<5;i++)
{
printf("%d\n",arr[i]);
}

One more way to do it is to consider a new pointer to &arr[0] and increment.

int *p=&arr[0];
for(i=0;i<5;i++)
{
printf("%d\n",*p);
p++;
//pointer arithmetic *(p)=*((&p)+1*sizeof(data_type_of_arr))
//NOTE: address of p updates for every iteration
}

For further reading on pointer arithmetic : here

Why an array pointer with index returns the value in that index instead of returning the specific index adress?

The misunderstanding here is that pointers and arrays have similar behaviours in C, as in you can treat a pointer like an array, and an array like a pointer.

In effect x[n] is the same as *(x + n) and vice-versa. x[0] is just *x.

As such, ptr[1] will return a de-referenced int* or in other words an int.

If you want the actual address you need to do either ptr + n or &ptr[n], both of which are equivalent, they're int*.

How does this array element access syntax work?

In C, the arrays and pointers have similarities. When you access an array element array[3]. This is equivalent to:

*(array + 3) // Dereferencing the 3rd index from beginning

Similarly, when you try to access it like 3[array], the statement goes like:

*(3 + array) // Identical to the first example

Which is identical. Lastly, when you want to obtain the N-th element of an array N[array], the syntax becomes:

*(N + array)

That's why you get your expected output.

Access array beyond the limit in C and C++

Accessing outside the array bounds is undefined behavior, from the c99 draft standard section Annex J.2 J.2 Undefined behavior includes the follow point:

An array subscript is out of range, even if an object is apparently accessible with the
given subscript (as in the lvalue expression a[1][7] given the declaration int
a[4][5]) (6.5.6).

and the draft C++ standard in section 5.7 Additive operators paragraph 5 says:

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression. [...] If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

For completeness sake, section 5.2.1 Subscripting paragraph 1 says:

[...]The expression E1[E2] is identical (by definition) to *((E1)+(E2)) [ Note: see 5.3 and 5.7 for details of * and + and 8.3.4 for details of arrays. —end note ]

It is important to note that the compiler is not required to produce a warning(diagnostic) for undefined behavior, the draft C++ standard in section 1.4 Implementation compliance paragraph 1 says:

The set of diagnosable rules consists of all syntactic and semantic rules in this International Standard except for those rules containing an explicit notation that “no diagnostic is required” or which are described as resulting in “undefined behavior.”

What is the correct type for array indexes in C?

I almost always use size_t for array indices/loop counters. Sure there are some special instances where you may want signed offsets, but in general using a signed type has a lot of problems:

The biggest risk is that if you're passed a huge size/offset by a caller treating things as unsigned (or if you read it from a wrongly-trusted file), you may interpret it as a negative number and fail to catch that it's out of bounds. For instance if (offset<size) array[offset]=foo; else error(); will write somewhere it shouldn't.

Another problem is the possibility of undefined behavior with signed integer overflow. Whether you use unsigned or signed arithmetic, there are overflow issues to be aware of and check for, but personally I find the unsigned behavior a lot easier to deal with.

Yet another reason to use unsigned arithmetic (in general) - sometimes I'm using indices as offsets into a bit array and I want to use %8 and /8 or %32 and /32. With signed types, these will be actual division operations. With unsigned, the expected bitwise-and/bitshift operations can be generated.

Accessing an array out of bounds gives no error, why?

Welcome to every C/C++ programmer's bestest friend: Undefined Behavior.

There is a lot that is not specified by the language standard, for a variety of reasons. This is one of them.

In general, whenever you encounter undefined behavior, anything might happen. The application may crash, it may freeze, it may eject your CD-ROM drive or make demons come out of your nose. It may format your harddrive or email all your porn to your grandmother.

It may even, if you are really unlucky, appear to work correctly.

The language simply says what should happen if you access the elements within the bounds of an array. It is left undefined what happens if you go out of bounds. It might seem to work today, on your compiler, but it is not legal C or C++, and there is no guarantee that it'll still work the next time you run the program. Or that it hasn't overwritten essential data even now, and you just haven't encountered the problems, that it is going to cause — yet.

As for why there is no bounds checking, there are a couple aspects to the answer:

  • An array is a leftover from C. C arrays are about as primitive as you can get. Just a sequence of elements with contiguous addresses. There is no bounds checking because it is simply exposing raw memory. Implementing a robust bounds-checking mechanism would have been almost impossible in C.
  • In C++, bounds-checking is possible on class types. But an array is still the plain old C-compatible one. It is not a class. Further, C++ is also built on another rule which makes bounds-checking non-ideal. The C++ guiding principle is "you don't pay for what you don't use". If your code is correct, you don't need bounds-checking, and you shouldn't be forced to pay for the overhead of runtime bounds-checking.
  • So C++ offers the std::vector class template, which allows both. operator[] is designed to be efficient. The language standard does not require that it performs bounds checking (although it does not forbid it either). A vector also has the at() member function which is guaranteed to perform bounds-checking. So in C++, you get the best of both worlds if you use a vector. You get array-like performance without bounds-checking, and you get the ability to use bounds-checked access when you want it.


Related Topics



Leave a reply



Submit