Does array[-1] give the last element in the array? - c

programming my arduino microcontroller board in C, I noticed a strange behaviour.
Because of an logic mistake in my program the controller accessed the -1th element of an integer array.
int array[5];
array[4] = 27;
// array[-1] gives 27 now.
Is it correct that I get the last element of an array by using -1 as the element selector?

No, accessing elements outside of the index range is undefined behavior. In your case, the element at the address just prior to the beginning of your array is set to 27.
Since accessing array elements in C is nothing more than doing "straight" pointer arithmetic, passing negative indexes is not disallowed. You could construct a legitimate use case where indexes are negative and positive:
int raw[21], *data = &raw[10];
for (int i = -10 ; i <= 10 ; i++) {
data[i] = i;
}

No; array[-1] will not access the last element. It's more likely that the memory location just before the array has 27 stored in it. Try this:
array[4] = 27;
array[-1] = 0;
Then test whether array[-1] == array[4]. They will not be equal (assuming your program doesn't crash when assigning to array[-1]).

Accessing arrays with index out of bounds does not always crash your program. If the memory accessed by -1 is under your program control than an undefined value will pop out (which was stored by some other data created by your program). In your case it is mere coincidence.

No, that is incorrect according to the Standard. Accessing an element outside the array invokes Undefined Behaviour.
Your implementation might (I doubt it!) provide that functionality; but you really should not rely on it.

Try this:
#include<stdio.h>
int main()
{
int raw[4], *data = &raw[2];
raw[0]=0;
raw[1]=1; // -1 index for data
raw[2]=2;
raw[3]=3;
for (int i = 0 ; i < 2 ; i++) {
printf("\nvalue =%d i=%d\n",data[i],i);
}
printf("\nIndex,[-1]=%d\n", data[-1]);
return 0;
}
EDIT: Conclusion is that -1 will access last memory location.

If you are referring to C (and you are), then no. If you try to access an array with a negative index, you will get an out of bounds exception. However, Lua implements this exact thing as a feature. If you access a Lua array with an index of -1, it will read the last element of the array. An index of -2 will read the second-to-last element, and so-on.
Side note: you can annoy your coworkers by writing this
foo = {1,2,3,4,5,6,7,8,9,0}
print(foo.length() * -1])
This prints 1. Annoying, isn't it.

Related

Accessing variable after an array by trying to access a position greater than its dimension in C [duplicate]

This question already has answers here:
How dangerous is it to access an array out of bounds?
(12 answers)
Accessing an array out of bounds gives no error, why?
(18 answers)
Closed 3 years ago.
Since in this example I'm able to read value of integer2 thanks to pointer arithmetic:
#include <stdio.h>
int main() {
int integer1 = 1;
int integer2 = 2;
int *p = &integer1;
p++;
printf("%d\n", *p);
}
with output:
$ ./test
2
I was wondering why in this example:
#include <stdio.h>
int main()
{
int array[2] = {0, 1};
int variable = 0;
for(int i = 0; i < 3; i++) {
printf("%d\n", array[i]);
}
}
then I'm not able to read the value of variable trying to point the next integer but that's what I get:
0
1
336859392
I tried printing the values of &array[0] &array[1] and &variable and this is what I got:
161695488
161695492
161695480
Not only the address of variable is less than the one of the first elements of the array, but it's not even the previous one.
Why in the first example variables address are contiguous and in the second one not?
There is probably something I don't understand on how variables and buffers are allocated in the stack.
EDIT:
I know this should not be done, but I'm trying to understand buffer overflows (more realistically the buffer should be of character, given as input by an user), and the goal should be to alter the value of the variable. So what I'm trying to understand is if it's possible to know exactly where the variable actually is in memory.
EDIT2:
Turns out that giving -fno-stack-protector makes it work as expected, so gcc is adding by default some sort of protection in order to avoid buffer overflows
The placement of local variables is a detail of the implementation. They may be placed in any order it deems appropriate.
Attempting to read past the bounds of an array invokes undefined behavior. The inconsistent results you see are a manifestation of that.
As an example, if I run your first code snippet, I do not get 2 as the output. When printing the addresses of each variable, I get:
&integer1=0x7ffcfa6e8c24, &integer2=0x7ffcfa6e8c20
So in my case the implementation puts integer1 after integer2.

Why do we initialize top of the stack as -1?

Why do I have to initialize one of the stacks to -1? Where would top1 point to?
int ar[SIZE];
int top1 = -1;
int top2 = SIZE;
void push_stack1 (int data)
{
if (top1 < top2 - 1)
{
ar[++top1] = data;
}
else
{
printf ("Stack Full! Cannot Push\n");
}
}
The difference is whether you let top1 point to the last used element or the first free element.
With -1 you let it point to the last used element.
With 0 you let it point to the first free element.
There is also symmetry in the use of pre-increment/decrement and post-increment/decrement.
Initializing to -1 implies ++top1 for push and top1-- for pop.
Initializing to 0 implies top1++ for push and --top1 for pop.
No, you wouldn't have to initialize top1 as -1 at all if your code would have been:
int ar[SIZE];
int top1 = 0; // 0 `here`
int top2 = SIZE;
void push_stack1 (int data)
{
// v conditional check with `<=` instead of `<`
if (top1 <= top2 - 1) // even better: `if (top1 < top2)`
{
ar[top1++] = data;
// ^ using "top1++" instead of "++top1"
}
else
{
printf ("Stack Full! Cannot Push\n");
}
}
++something (also known as pre-increment) will increment the value of something, and then return the incremented value.
Whereas, something++ (also known as post-increment) will increment the value of something, but return the original value that something held before being incremented.
But you must note here that whether it is ++top1 or top1++, we are always passing 0 as the first index to ar because the 0 is the first index of any array/list in all the languages.
This is really odd that you started to think that in stack datastructure's implementation - you would have to initialize top with -1. Whick book said that? If any book did, at it's best it can mostly mean that the implementation they showed is following that.
Where would top1 point to? If you directly index into an array object, then yes it would likely try to access a memory which is out of the array bound, which is surely an undefined behavior(Arrays are 0-indexed in C ). But in every scenarios, we see implementation where top is increased first (in case top is initialized with -1)++top and then that value is used to index into array (For the very first time this will result in 0), which is precisely the case here. (Array is mentioned here because it seems that underlying data structure the code you showed uses that).
So top=-1 will initially mean that it is in a empty state and you can say no member is being added to the stack data structure. Here you could have initialized top with 0 also provided that you would have to change your push,pop or isEmpty() and other auxiliary functions associated with this data structure implementation accordingly, as needed.
Also you can check your other function's implementation to get the justification of top=-1 for the implementation with which you are working on.
Also if you are in doubt about what ++ does here and how is it significant - Look what C11 standard has to say about it (N1570Draft)
In section §6.5.3.1¶2
The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation.
++top1 will result in the new incremented value which is 0 in case it was -1 earlier.

why does this C code outputs 1

Is there any reason why:
void function_foo(){
int k[8];
function_math(k, 8);
}
void function_math(int *k, int i){
printf("value: %d", k[i]);
}
The main execute function_foo();
The output will be 1? There's no initialization for elements of matrix k.
Maybe something with the length of int in memory?
I am new to C concepts, the pointers and everything.
It is undefined behaviour to evaluate k[8], since k only has 8 elements, not 9.
There is little point arguing about the consequences of undefined behaviour. Anything could happen. Your program is not well-formed.
(Note that it would even be undefined behaviour to evaluate k[0], ..., k[7], since they are unini­tia­lized. You have to write to them first, or initialize the array, such as int k[8] = { 1, 2 };.)
This is the value which is at the memory position after the last element of your declared array.
If you run this code in a week again, it could be 42 or anything else which is stored at this time on this specific memory address. Also a segmentation fault could be possible in this case.
You are stepping out of the bounds of the array k.
To access the last element of k try using function_math(k, 7)
The array is also not initialized so the values inside will be undefined.

C initializes and re-initializes arrays to zero at runtime when asked

#include <stdio.h>
int main(void) {
for (int i = 0; i < 5; i++) {
int arr[5] = {0};
// arr gets zeroed at runtime, and on every loop iteration!
printf("%d %d %d %d %d\n", arr[0], arr[1], arr[2], arr[3], arr[4]);
// overwrite arr with non-zero crap!
arr[0] = 3;
arr[1] = 5;
arr[2] = 2;
arr[3] = 4;
arr[4] = 1;
}
return 0;
}
Apparently this works:
> gcc -Wall -Wextra -pedantic -std=c99 -o test test.c;./test
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
But:
What's going on under the hood?
Is this guaranteed to work for arrays of any size?
Have I found the most elegant way of zeroing an array on every iteration of a loop?
You are creating a new array at each iteration, so there is no re-initialization.
This has been answered before:
how does array[100] = {0} set the entire array to 0?
What's going on under the hood?
The compiler will generate code equivalent to memset (see Strange assembly from array 0-initialization for full details).
Is this guaranteed to work for arrays of any size?
Up to the limit of your available stack size, yes.
Have I found the most elegant way of zeroing an array on every iteration of a loop?
I suppose so. :)
See according to me whenever you are iterating over a loop, then whatever variables you are declaring inside the loop are local to that loop. So at the end of the loop they are getting destroyed, and when the loop is again starting then they are being created again.
So,
1. answered above;
2. yes this should work for array of any size;
3. no...
The variable arr is created and initialized on every iteration of the loop because that's what you wrote. In your example, the code does something analogous to memset() to set the array to zero, but possibly more efficiently and inline. You could write a non-zero initializer too.
Yes, it works for 'any' size of array. If the arrays are bigger, the loop will be slower.
It is a very elegant way to achieve the effect. The compiler will do it as fast as possible. If you can write a function call that's quicker, the compiler writer's have goofed.
Yes, the C Standard guarantees that your array elememts are zeroed on each loop iteration. If you only want them zerored on the first iteration, make the array static, i.e. with
static int arr[5] = {0};
You may leave out the = { 0 } in this case, as static data is required to be initialized as if all elements were assigned 0 in the absence of an initializer (or NULL for pointers, or 0.0 for floating point values, recursively for structs).
Note also, that if you use less initializers than the array dimension specifies, the remaining elements are assigned zeros. So
int arr[5] = {42, 0xdead};
is equivalent to
int arr[5] = {42, 0xdead, 0, 0, 0};
and using a single 0 is just a special case of this rule.
Not ignoring the logical error of the code (re initialization at each iteration) I will recommend using memcpy or memset whenever you want to assign all the elements of an array.. This is the tried and tested way, which fortunately works as a charm in almost all the compiler implementations.
Memset Example
MemCpy Example
So, Using Memset your code will become;;
int a[5];
memset(a,0,<number of bytes to be set to> sizeof(int)*5);
Please read the documentation to find out why it is fast, you will enjoy...
EDIT
Sorry and Thanks for all the down voters / commentors... I corrected the answer...

Array Allocation causing terminal to hang

I came across this code accidentally:
#include<stdio.h>
int main()
{
int i;
int array[3];
for(i=0;i<=3;i++)
array[i]=0;
return 0;
}
On running this code my terminal gets hanged - the code is not terminating.
When I replace 3 by 2 code runs successfully and terminates without a problem.
In C there is no bound checking on arrays, so what's the problem with the above code that is causing it to not terminate?
Platform - Ubuntu 10.04
Compiler - gcc
Just because there's no bound checking doesn't mean that there are no consequences to writing out of bounds. Doing so invokes Undefined Behavior, so there's no telling what may happen.
This time, on this compiler, on this architecture, it happens that when you write to array[3], you actually set i to zero, because i was positioned right after array on the stack.
Your code is reading beyond the bound of array and causing an Undefined Behavior.
When you declare an array of size 3. The valid index range is from 0 to 2.
While your loop runs from 0 to 3.
If you access anything beyond the valid range of an array then it is Undefined Behavior and your program may hang or crash or show any behavior. The c standard does not mandate any specific behavior in such cases.
When you say C does not do bounds checking it actually means that it is programmers responsibility to ensure that their programs do not access beyond the beyonds of the allocated array and failing to do so results in all safe bets being off and any behavior.
int array[3];
This declares an array of 3 ints, having indices 0, 1, and 2.
for(i=0;i<=3;i++)
array[i]=0;
This writes four ints into the array, at indices 0, 1, 2, and 3. That's a problem.
Nobody here can tell exactly what you're seeing -- you haven't even specified what platform you're working on. All we can say is that the code is broken, and that leads to whatever result you're seeing. One possibility is that i is stored right after array, so you end up setting i back to 0 when you do array[3]=0;. But that's just a guess.
The highest valid index for array is 2. Writing past that index invokes undefined behaviour.
What you're seeing is a manifestation of the undefined behaviour.
Contrast this with the following two snippets, both of which are correct:
/* 1 */
int array[3];
for(i=0;i<3;i++) { array[i] = 0; }
/* 2 */
int array[4];
for(i=0;i<4;i++) { array[i] = 0; }
You declared array of size 3 which means (0,1,2 are the valid indexes)
if you try to set 0 to some memory location which is not for us unexpected (generally called UB undefined behavior) things can happen
The elements in an array are numbered 0 to (n-1). Your array has 3 spots, but is initializing 4 location (0, 1, 2, 3). Typically, you'd have you for loop say i < 3 so that your numbers match, but you don't go over the upper bound of the array.

Resources