#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...
Related
I have a problem with predicting result of code linked below.
Why program is printing 2 0 6 0 10 0 16 0 20 0 ? I guess it is all about operators precedence, but after thinking a while I can't realize what's wrong with my interpretation. Can you explain it a little bit?
#include <stdio.h>
int main(void)
{
int tab[10] = {2,4,6,8,10,14,16,18,20};
int *pi, i;
for(pi = tab; ++pi < tab+9;)
{
*pi++ = 0;
*pi *= 2;
}
for(int i=0; i<10; i++)
printf("%d ", tab[i]);
return 0;
}
The first thing that the for loop does is point pi at tab, i.e. pi=&tab[0]
So pi is pointing at the number 2. The next piece of code to be executed is the for loop's "condition" statement ++pi < tab+9. This first increments pi (so it's now pointing at the number 4 in tab[1]) and checks whether it's still pointing at a member of tab earlier than the final 20.
In the body of the for loop, the line *pi++ = 0; first stores a 0 at the address pointed to by pi (which means that tab[1] is now 0 rather than 4) and then (post-) increments pi to point at tab[2], which is 6. Then the line *pi *= 2; doubles the value pointed to by pi, so tab[2] becomes 12.
The next thing that happens is a re-evaluation of the for loop's conditional statement (since its iteration statement is empty): pi is incremented and checked.
The rest of the iterations are fairly uneventful. The final state of tab is that the first member is unchanged, members with an odd index are zero, and other members are doubled from their initial value.
General advice regarding operators and precedence: one of two situations is almost always the case. The first is that you and the compiler don't agree on the order in which the operators in your code will be applied—in other words your code doesn't do what you expect. The second is that you understand perfectly what the compiler is going to do, but the programmer reading your code does not—in other words your code doesn't do what they expect. Fortunately, both situations can be mitigated by adding parentheses to remove any doubt.
The actual output is 2 0 12 0 20 0 32 0 40 0 (as shown in Blastfurnace comment https://ideone.com/UUy8QO)
pi is indeed initially on the first cell, but your stop condition increment the pointer. Therefore, inside the loop, for the first instruction, pi is in tab[1]. It first put this cell to 0, then increment with ++. On the second line, it double the value, therefore it double tab[2]. Then, the stop condition again increment the pointer, and so on.
Why does this code print out b[index]: 0 all the way up until 1011, than at 1012 starts producing garbage?
int b[10];
for(int i=0; i<1025; i++){
printf("b[%d]: %d\n", i, b[i]);
}
The output I get is:
b[0]: 0
b[1]: 0
...
b[1011]: 0
b[1012]: 1376789009
b[1013]: 0
b[1014]: 2036613137
Your array can only hold 10 element, but you attempt to access elements past that. C doesn't have any kind of bounds checking to ensure you don't do that. What you get instead is undefined behavior, which means you can't predicts how the program will behave. Note also that the value 0 is just as much garbage as any other value that might be printed.
Also, because b is not initialized, the 10 elements it does contain have indeterminate values. They could be 0 or they could be something else entirely. You could also trigger undefined behavior in this case if the values happen to have a trap representation, although you're unlikely to come across that on modern systems.
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.
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.
The code below is me trying to instantiate a 2d array, and it instantiating incorrectly:
THE CODE:
FILE* kernalFile = fopen(argv[1], "r");
int rKernalSize;
fscanf(kernalFile, "%d", &rKernalSize);
unsigned int rKernal[rKernalSize][rKernalSize];
Data froma break point right after that code is ran:
rKernalSize VALUES:
Name : rKernalSize
Details:3
Default:3
Decimal:3
Hex:0x3
Binary:11
Octal:03
rKernal VALUES:
Name : rKernal
Details:0x7ffffffe0cd0
Default:[0]
Decimal:[0]
Hex:[0]
Binary:[0]
Octal:[0]
or
rKernal[][0]
It should be rKernal[3][3] and here is the file so you can look at it. If wanted:
3 -1 1 0 1 0 -1 0 -1 1 3 -1 1 0 1 0 -1 0 -1 1 3 -1 1 0 1 0 -1 0 -1 1
TLDR: rKernalSize is correct (3) but when I create the 2d Array with rKernal[rKernalSize][rKernalSize] it does not instantiate correctly! It instatiates as rKernal[][0] maybe thats default but should be rKernal[3][3]
Forget what the debugger is telling you. In your code, immediately following:
unsigned int rKernal[rKernalSize][rKernalSize];
put the statement:
printf ("%d\n", sizeof(rKernal) / sizeof(unsigned int));
and see what it prints out (hopefully 9).
It's possible the debugging information, created at compile time, is not enough to properly determine the sizes of variable length arrays.
By way of example, even though gcc supports variable length arrays, gdb itself couldn't properly handle them as recently as late 2009 and there's still no mention of them in the documentation dated October 2010.
So I suspect that is the problem, especially since the test code I provided above output 9 as expected.
The basic problem here is that rKernalSize isn't known at compile time when that array is being allocated. At compile time, the value of int rKernalSize is compiler-dependent (unless the new C standard explicitly makes it 0; 0's the value I'd bet on anyway.) So when the code is loaded, there's a symbol rKernal that represents the address of a secrtion of memory containing no bytes.
But then you run the program, and read '3' with your scanf; when you dumpt the results, you see '3'.
This code, by the way, wouldn't work in straight C -- you must allocate before the first executable statement. This will compile in C++.
Now, if you want, using straight C, to do something like this, here's what you need:
Read your size as you have using scanf.
Allocate the memory for your array using malloc, which will look something like
x
int ** ary;
int rkSize; // what you scanf'd into
if((ary = malloc(rkSize*rkSize*sizeof(unsigned int)))==NULL){
// for some reason your malloc failed. You can't do much
fprintf(stderr,"Oops!\n");
exit(1);
}
// If you got here, then you have your array
Now, because of the pointer-array duality in C, you can treat this as your array
x
ary[1][1] = 42; // The answer