I've done a search and I’ve found nothing relevant to my query.
I am currently debugging a C optimizer and the code in question looks like this:
while( x-- )
array[x] = NULL;
What should happen in this instance? And should the result of this logic be consistent across all compilers?
Lets say that the initial value of x in this case is 5.
The problem is that the program crashes, my understanding is that it is caused by a negative array element reference.
Any help would be appreciated.
This cycle will end with x equal to -1 (assuming x is signed), but its body will not produce access to array[-1] at the last step. The last array access is to array[0]. The behavior is consistent across all implementations.
In other words, there's no problem with negative index array access in the code you quoted. But if you attempt to access array[x] immediately after the cycle, then you'll indeed access array[-1].
The code you quoted is a variation of a fairly well-known implementational pattern used when one needs to iterate backwards over an array using an unsigned variable as an index. For example
unsigned x;
int a[5];
for (x = 5; x-- > 0; )
a[x] = 0;
Sometimes less-experienced programmers have trouble using unsigned indices when iterating backwards over an array. (Since unsigned variables never have negative values, a naive implementation of the cycle termination condition as x >= 0 does not work.) This approach - i.e. post-increment in the cycle termination condition - is what works in such cases. (Of course, it works with signed indices as well).
If the initial value of x is 5, it will execute:
array[4] = NULL;
array[3] = NULL;
array[2] = NULL;
array[1] = NULL;
array[0] = NULL;
If x is a signed type, then the final value of x will be -1; otherwise, it will be the maximum value of the type.
Make sure x is non negative before processing the while loop(precondition).
Also x value will be -1 when the process leaves the while loop(post condition). Therefore, after leaving while loop, you should not access the array using x as index.
Related
Just to be clear, I understand how for loops work. However, the different syntax causes me problems... Let me give you an example:
I was looking up a recursive sorting algorithm (insertion sort). The code went like this:
void insertion_recursive(int array[],int size){
int i;
if (size<=1) return;
insertion_recursive(array,size-1);
for(i=size-1;i;i--)
if(array[i]<array[i-1])
swap(&array[i],&array[i-1]);
else
break;
}
I understand how the code works, but the condition for the loop is confusing me:
for(i=size-1 ; i ; i--)
What does it mean? Just leaving 'i' without specifying a condition?
An expression represents a single data item--usually a number. The expression may consist of a single entity, such as a constant or variable, or it may consist of some combination of such entities, interconnected by one or more operators. Expressions can also represent logical conditions which are either true or false. However, in C, the conditions true and false are represented by the non-zero integer values and zero integer value, respectively. Several simple expressions are given below:
a + b
x = y
t = u + v
x <= y
++j
In your example, i is an expression whose value is expression's l-value which is in this case, it is the value of variable i.
The expression will evaluate to true for non-zero i values and false if value of i is zero.
So, for(i=(size-1); i ; i--) is equivalent to for(i=(size-1); i != 0; i--).
In C when trying to evaluate a condition, everything that is 0 is false, and everything else is true.
Even pointers are treated the same way. The constant NULL is actually defined as 0. In C++11 we finally have the null_ptr for type safety.
In C there is no bool type, and in C++ if you cast true to integer you get 1, and false casts to 0.
i by itself is converted to a boolean, similar to if (i) {...} or if (! i) {...}; integers are considered true when nonzero and false when zero.
So, for(i=size-1 ; i ; i--) is equivalent to for(i=size-1 ; i != 0; i--).
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Can anyone tell me how does this code work?
int Calc(int *arr, int m)
int result;
for (result &= 0; m; (arr[--m] & (0x1 << 0x1F)) ? result += arr[m]: Void());
return result;
I can't understand for loop:/
Where did you find this code so I can hunt that person down and beat him with a copy of Schildt?
It's no surprise you don't understand the loop; it wasn't written to be understandable. The only place this kind of code is acceptable is the IOCCC, except it's not obfuscated enough for that competition.
Taking each bit in turn:
result &= 0;
is a really funky way of initializing result to 0; it's shorthand for result = result & 0, which performs a bitwise-AND of result against 0 (giving 0) and assigns the result back to result. It's also unsafe, since an uninitialized object may contain a trap representation. That should have been written as simply result = 0.
m;
just checks the current value of m; the loop will run until it is 0. The loop basically starts at the last element and works its way down to the first.
(arr[--m] & (0x1 << 0x1F)) ? result += arr[m]: Void()
Ugh. So, the first thing it does is take the value of the array at index m-1 and does a bitwise and against 0x1 << 0x1F (1 shifted left 31 postitions, or essentially 0x80000000); if the result of this operation is non-zero, then we add the value of that array element to result, otherwise we execute some incredibly inappropriately named function that hopefully returns a 01. Given that we're dealing with signed integers, and that on most platforms an int is 32 bits wide, this code is obviously adding up negative values in result.
A slightly saner way of writing that would be
result = 0;
while ( m ) // or m != 0, or m > 0, whatever you prefer
{
if ( arr[--m] < 0 )
result += arr[m];
}
1. The conditional operator ?: isn't meant to be used as a control structure like this. The syntax is expr1 ? expr2 : expr3. First, expr1 is evaluated and all side effects applied; if it results in a non-zero value, then the result of the expression is expr2; otherwise, the result is expr3.
Part 1
Firstrly result &= 0 is used for setting 0 to result variable using bitwise AND operation. Bitwise with 0 will ever return 0.
You can write it simply this way: result = 0
The better (much optimal) way of doing this is: result ^= result. (Bitwise XOR)
Part 2
This loop will iterate while m is greater (or less) than 0. Because m expression will return true if m != 0.
Much secure way of doing it is m > 0.
Also you can use this expression, which is not making programm much optimal, but it will be cleaner to another programmer to understand your code: !!m (casting m variable to bool), which is equal to m != 0;
Part 3
In this part ternary operator (logical_expression ? expression_1 : expression_2) is used.
If logical_expression is true, then expression_1 will be executed, expression_2 will be executed otherwise.
So in your code, if this expression (arr[--m] & (0x1 << 0x1F)) returns true then we add arr[m] to result variable. And do nothing in another case.
Also m variable is decremented in ternary logical expression (arr[--m]).
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I'm studying C in school and I had this question, and I'm having trouble solving it.
What does the following code do?
#define N (100)
int main(void)
{
unsigned short i = 0;
unsigned long arr[2*N + 1];
unsigned long a = 0;
for (i = 0 ; i < N ; ++i) {
a ^= arr[i];
}
printf("%lu", a);
return 0;
}
It would be really helpful if you could explain it to me!
Thanks!
It's usually a good idea to explain what you understand, so we don't have to treat you as though you know nothing. Important note: This code behaves erratically. I'll discuss that later.
The exclusive or operator (^) produces its result by applying the following pattern to the binary representation of the numbers in question:
Where both operands (sides of the operator) contain different bits, the result will contain a 1 bit. For example, if the left hand side contains a right-most bit of 0 and the right hand side contains a right-most bit of 1, then the result will contain a right-most bit of 1.
Where both operands (sides of the operator) contain the same bit, the result will contain a 0.
So as an example, the operands of 15 ^ 1 have the following binary notation:
1111 ^
0001
... and the result of this exclusive or operation will be:
1110
Converted back to decimal, that's 14. Xor it with 1 again and you'll end up back at 15 (which is the property the silly xor swap takes advantage of).
The array[index] operator obtains the element within array at the position indicated by index.
The ^= operator is a compound operator. It combines the exclusive or and assignment operators. a ^= arr[i]; is roughly equivalent to a = a ^ arr[i];. That means: Calculate the exclusive or of a and arr[i], and assign it back into a.
for (i = 0 ; i < N ; ++i) /*
* XXX: Insert statement or block of code
*/
This denotes a loop, which will start by assigning the value 0 to i, will repeatedly execute the statement or block of code while i is less than N (100), incrementing i each time.
In summary, this code produces the exclusive or of the first 100 elements of the array arr. This is a form of crude checksum algorithm; the idea is to take a group of values and reduce them to a single value so that you can perform some form of integrity check on them later on, perhaps after they've been trasmited via the internet or an unreliable filesystem.
However, this code invokes undefined behaviour because it uses unspecified values. In order to avoid erratic behaviour such as unpredictable values or segfaults (or worse yet, situations like the heartbleed OpenSSL vulnerability) you need to make sure you give your variables values before you try to use those values.
The following declaration would explicitly initialise the first element to 42, and implicitly initialise all of the others to 0:
unsigned long arr[2*N + 1] = { 42 };
It is important to realise that the initialisation part of the declaration = { ... } is necessary if you want any elements not explicitly initialised to be zeroed.
this function will print unpredictable value.
because of unsigned long arr[2*N + 1]; arr is not initialized and it will have random content based on data on you memory.
a ^= arr[i]; is equal to a = a^arr[i]; so it will do this for multiple times (because of loop) and then it will print it.
I know that negative length arrays have undefined behaviours, but with the standard of E1[E2] being identical to (*((E1)+(E2))) I expected something to work.
So in this instance what I do is I create an array that spans in direction -32, so the accessible indexes I expected to gain are -31 up to 0.
I am using 8bit unsigned chars of 0 to 255 and signed chars of -128 to +127, but this happens with 32bit integers and 64bit integers too.
I use C99's ability to declare arrays of variable length to construct the negative spanning array, specifically I am compiling to the GNU99 C standards.
I assign these values to the indexes and print them out as I go, all seems to work fine.
It goes strange when I make a pointer to the value at array index [-31] and then loop through that, 0 to 31, printing the values.
const signed char length = 32;
const signed char negativeLength = -length;
signed char array[negativeLength];
for ( signed char ii = 0; ii > negativeLength; ii-- ) {
array[ii] = ii;
printf( "array %d\n", array[ii] ); /* Prints out expected values */
}
printf( "==========\n" );
signed char * const pointer = &array[negativeLength + 1];
for ( unsigned char ii = 0; ii < length; ii++ ) {
printf( "pointer %d\n", pointer[ii] ); /* Begins printing expected values then goes funky */
}
I get different results every time, but with 32 it generally starts out okay for the first 3 values, it then goes funky and starts printing out -93 up to +47 and then at index pointer[8], array[-23] it goes fine again.
I am running this on an iPad 2.
What exactly is going on here? Is the iPad messing with the pointer or the array when it detects the negative spanning array length?
I sometimes advocate understanding the behavior observed in some C implementations in situations where the C standard does not define the behavior, because it can be illuminating about how certain implementing work or how computers work. In this case, however: Do not do that.
To access an array with arbitrary integer indices, from X (inclusive) to Y (exclusive), do this:
ElementType ArrayMemory[Y-X], *Array = ArrayMemory - X;
If X <= 0 <= Y and X < Y, the behavior of this is defined by the C standard.
Why would you expect something to work when you've done something with undefined behaviour?
While E1[E2] being equivalent to *(E1 + E2) is well defined, the data you're accessing is not well defined so all bets are off.
I had this question after reading the Stack Overflow quesion Print an int in binary representation using C.
In a user's comment, they posted this for loop, which assigns either a 1 or a 0 to the bit position in order to convert from an int decimal to char * binary.
for(; bits--; u >>= 1)
str[bits] = u & 1 ? '1' : '0';
I understand why there doesn't need to be an initialized value. This is the syntax for a for loop that I've always known:
for ( variable initialization; condition; variable update )
I don't understand how 'bit--' can be an exit condition. Please help me understand how this code works (I tested it, and it is valid).
In C, a value of zero evaluates to "false" in a Boolean context. So when bits-- evaluates to 0, in the context of the loop it evaluates to "false" and terminates the loop.
If you say, for example:
int x = 1;
if (--x)
{
printf("True!\n");
}
else
{
printf("False!\n");
}
It will output "False", because --x evaluates to 0, which is "false" in a Boolean context.
All conditions basically boil down to checking whether something is 0 or not. 0 means false, everything else means true. So that loop will break when bits is 0.
You will sometimes see while or if conditions written
if (variable) // or while(variable)
That is just shorthand for
if (variable != 0) // or while (variable != 0)
So
for (; bits--; u >>= 1)
is short for
for (; bits-- != 0; u >>= 1)
bits-- is an assignment expression of type int (since it will return the value of b, which is int). To match the for loop syntax, it gets converted to a Boolean expression, which means it is true if bits != 0.
In fact, the condition is identical to bits!=0, but by using bits--, it changes the value of bits at the same time, making the code more compact. That's all.
As others said, in C, you can use integers as a condition - 0 or false, and anything else for true. (Actually, you almost always do it - even an expression like a<b is an int.)
So, the loop will end when bits-- will be 0.
When the -- operator comes after the variable, it decreases the variable, and gets the previous value of it. For example, if you have int a=3,b; b=a--;, then b will be 3, and a will be 2.
So, the loop will exit after that bits will been decreased from 0 to -1.
That means that, if in the beginning, bits==8 (for example), the loop will iterate 8 times, when in the first, bits will be 7 (because the condition had checked), and in the last, bits will be 0. It is a nice way to loop through an array (Since in C, an array of bits variables is being indexed from 0 to bits-1).