I am trying to assign values within an array within the condition of a for loop:
#include <iostream>
using namespace std;
int* c;
int n;
int main()
{
scanf("%d", &n);
c = new int[n];
for (int i = 0; i < n; c[i] = i++ )
{
printf("%d \n", c[i]);
}
return 0;
}
However, I am not obtaining the desired output, for n = 5, 0 1 2 3 4. Instead, if I am using the instruction, c[i] = ++i, I am obtaining the output -842150451 1 2 3 4. Could you please explain me we does my code behave like this and how can I correct it?
The value of the expression ++i is the value after i has been incremented. So if it started at 0, you assign value 1 the first time and so on. You can see where the value got assigned, but asking why it got assigned there opens a can of worms.
Using i in an expression where i is modified via i++ or ++i is undefined behavior unless there is a so-called "sequence point" in between the two. In this case, there isn't. See Undefined behavior and sequence points for this rather complicated part of the language.
Although the behaviour is undefined by the standard, and may not be consistent from one run to another, clearly your program has done something. Apparently it didn't assign to index 0 at all (at least, not before the first print, which is understandable considering that the loop body happens before the last part of the "for"), so you got whatever just so happened to be in that raw memory when it was allocated to you. It assigned 1 to index 1 and so on.
This means that it may also have attempted to assign the value 5 to c[5], which is a class of bug known as a "buffer overrun", and more undefined behavior on top of what you've already got. Attempting to assign to it probably overwrites other memory, which on any given day may or may not contain something important.
The fix is to assign some value to c[0], and don't try to assign to c[5], which doesn't exist anyway, and don't try to invalidly use i "at the same time as" incrementing it. Normally you'd write this:
for (int i = 0; i < n; ++i) {
c[i] = i;
printf("%d \n", c[i];
}
If you're desperate for some reason to assign in the third clause of a for loop, you could use the comma operator to introduce a sequence point:
for (int i = 0; i < n; c[i] = i, ++i) {
}
But of course if you do that then you can't print the value of c[i] in the loop body. It hasn't been assigned yet, because the third clause isn't evaluated until the end of each loop.
You could also try c[i] = i+1, ++i, but not ++i, c[i] = i because then we're back to trying to assign to c[5], on the last iteration.
First you need to understand that the last part of the for loop is executed at the end of each iteration, so the reason you see this:
-842150451 1 2 3 4
Is because you print c[0] before it is assigned, so the value could be anything. The rest falls into line as expected.
Lesson; don't be sneaky and stuff things into the last part of the for loop like that. Make your code clear and simple:
for (int i = 0; i < n; ++i )
{
c[i] = i;
printf("%d \n", c[i]);
}
Firstly, you are claiming that you want to assign the values "within the condition of the loop". In for loop the condition is the second part of the header (i < n in your case). You are performing the assignment in the third part, which is not a condition. So, why are you saying that you want to assign the values within the condition, and yet not doing that?
Secondly, expressions like c[i] = i++ or c[i] = ++i do not have any defined behavior in C++ language. In C++ it is illegal to modify a variable and at the same time read it for any other purpose without an intervening sequence point. Yet, you are doing exactly that. There's no meaningful explanation for the behavior of your code. The behavior of your code is undefined. It can do anything for any random reason.
Thirdly, initializing anything in the for condition is generally not a good idea. Could you explain in more detail what you are trying to do and why? Without it it is hard to come up with anything meaningful.
Your fundamental problem is how the statements in the for(;;) structure get broken down and executed. The for(st1; st2; st3) structure is intended to be identical to:
st1;
while (st2) {
<body>
st3;
}
Therefore, your 3rd statement, c[i] = i++, gets executed after the printf statement and you're printing uninitialized data.
The pre-increment vs. post-increment issue is obscuring this.
The reason why c[i] = ++i produces undefined behavior. It's undefined to both ++ a value (pre or post) and use it again within the same expression. In this case it appears that ++i is being evaluated before anything else and causing the execution to essentially be
c[1] = 1;
c[2] = 2;
...
This means c[0] is never initialized and instead has essentially a garbage value. It seems like the order you want is
c[0] = 0;
c[1] = 1;
To get this ordering you'll need to separate the initialization and increment into separate statements.
c[i] = i;
i++;
Related
This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 3 years ago.
I have two arrays in my code each one of them have 7 elements, I used a for loop:
for (int i = 0; i < 7; i++)
{
distance = x[++i] - x[i];
area = trapezoidArea(distance, y[++i],y[i]);
sum += area;
}
I wanted to calculate the area of a trapezoid. The difference of x[1]-x[0] will give me the height and y[1] is the first side, and y[0] is the second side.
This for loop doesn't work, and I want to know why.
You can't use ++ as post or pre-increment operator in this case.
This will change the value of your i variable, and therefore your for loop won't have the behaviour you want.
The proper way would be :
for (int i = 0; i < 6; i++)
{
distance = x[i+1] - x[i];
area = trapezoidArea(distance, y[i+1],y[i]);
sum += area;
}
Be careful you have to loop until i<6 because if you let 7, you'll try to access x[7+1] = x[8], and you'll have undefined behaviour or segmentation fault.
++i increases i. So you increase i thrice in one run through the loop, and on top of that, it might also be undefined behavior because of sequencing. What's the i in x[i] supposed to be? The i before the ++i in x[++i] increased it, or after it was increased?
If you want one more than i without increasing it, do i+1 instead. Replacing x[++i] with x[i+1] and likewise with y[++i] should fix this issue. But without seeing all of your code, it's impossible to say if that's the only issue.
When you do ++i in the square brackets, you actually increment the value of i by one. What you should do is i + 1 and leave ++i only in the loop declaration.
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
int n;
n++;
printf("n : %d\n", n)'
}
}
The output of the code is 1 2 3 4 5 6 7 8 9. I'm wondering why the variable n in the for loop isn't initialized when the variable declaration is executed.
You're never initializing n to a specific value. C++ will not do this by default when you call int n. Instead, it just reserves an integer sized block of memory. So when you call n++, the program is just grabbing whatever value happens to be in that memory and incrementing it. Since you're doing this in quick succession and not creating new variables in between, it happens to be grabbing the same memory over and over. As #NicolasBuquet points out, compiler optimization may also be responsible for the consistency with which the same chunk of memory is picked.
If you were to assign a value to n, (i.e. int n = 1;) this behavior would go away because a specific value will be written to the chunk of memory assigned to n.
In C++, no variable is initialized with a default value; you must specify one explicitly should you find the need to do so.
The result of your code is really undefined; it is just pure luck that you are getting the numbers 1 through 9 in sequence. On some other machine or implementation of C++, you might get different results.
My interest is in the difference between for and while loops. I know that the post-increment value is used and then incremented and the operation returns a constant pre-increment.
while (true) {
//...
i++;
int j = i;
}
Here, will j contain the old i or the post-incremented i at the end of the loop?
Since the statement i++ ends at the ; in your example, it makes no difference whether you use pre- or post-increment.
The difference arises when you utilize the result:
int j = i++; // i will contain i_old + 1, j will contain the i_old.
Vs:
int j = ++i; // i and j will both contain i_old + 1.
Depends on how you use them.
i++ makes a copy, increases i, and returns the copy (old value).
++i increases i, and returns i.
In your example it is all about speed. ++i will be the faster than i++ since it doesn't make a copy.
However a compiler will probably optimize it away since you are not storing the returned value from the increment operator in your example, but this is only possible for fundamental types like a int.
Basic answer for understanding.
The incrementation operator works like this:
// ++i
function pre_increment(i) {
i += 1;
return i;
}
// i++
function post_increment(i) {
copy = i;
i += 1;
return copy;
}
A good compiler will automatically replace i++ with ++i when it detect that the returned value will not be used.
In pre-increment the initial value is first incremented and then used inside the expression.
a = ++i;
In this example suppose the value of variable i is 5. Then value of variable a will be 6 because the value of i gets modified before using it in a expression.
In post-increment value is first used in a expression and then incremented.
a = i++;
In this example suppose the value of variable i is 5. Then value of variable a will be 5 because value of i gets incremented only after assigning the value 5 to a .
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argp)
{
int x = 5;
printf("x=%d\n", ++x);
printf("x=%d\n", x++);
printf("x=%d\n", x);
return EXIT_SUCCESS;
}
Program Output:
x=6
x=6
x=7
In the first printf statement x is incremented before being passed to printf so the value 6 is output, in the second x is passed to printf (so 6 is output) and then incremented and the 3rd printf statement just shows that post increment following the previous statement by outputting x again which now has the value 7.
i++ uses i's value then increments it but ++i increments i's value before using it.
The difference between post- and pre-increment is really, in many cases subtle. post incremenet, aka num++, first creates a copy of num, returns it, and after that, increments it. Pre-increment, on the other hand, aka ++num, first evaluates, then returns the value. Most modern compilers, when seeing this in a loop, will generally optimize, mostly when post increment is used, and the returned initial value is not used. The most major difference between the 2 increments, where it is really common to make subtle bugs, is when declaring variables, with incremented values: Example below:
int num = 5;
int num2 = ++num; //Here, first num is incremented,
//then made 6, and that value is stored in num2;
Another example:
int num = 5;
int num2 = num++; //Here, num is first returned, (unfortunately?), and then
//incremented. This is useful for some cases.
The last thing here I want to say is BE CAREFUL WITH INCREMENTS. When declaring variables, make sure you use the right increment, or just write the whole thing out (num2 = num + 1, which doesn't always work, and is the equivalent of pre-increment). A lot of trouble will be saved, if you use the right increment.
it does not matter if you use pre or post increment in an independent statement, except for the pre-increment the effect is immediate
//an example will make it more clear:
int n=1;
printf("%d",n);
printf("%d",++n);// try changing it to n++(you'll get to know what's going on)
n++;
printf("%d",n);
output:
123
I'm writing a C++ application that has a user enter a 0 (zero) or a one (1) as input, then stores the numbers as an array and sorts them so that the zeros come first and the ones come last.
However, I think I'm getting a memory address in my array that's messing up the sorting operation.
The function that accepts input looks like this:
cout << "Please enter number " << i+1 << ":\n";
cin >> ar[i];
Then there's a function that's called that sorts the input and displays the sorted list:
sort_elements(ar, number);
... and that function looks like this:
void sort_elements(int ar[], long int num_elements) {
int temp_num;
num_elements -= 1; //since the array starts at 0
cout << "num_elements is " << num_elements << "\n";
for (int i=0; i < (num_elements/2); i++ ) {
if (ar[i] > ar[num_elements-i]) {
temp_num = ar[i];
ar[i] = ar[num_elements-i];
ar[num_elements-i] = temp_num;
}
}
cout << "Here's your neatly sorted list of numbers: \n";
for (int j=0; j <= num_elements; j++) {
cout << ar[j] << ", ";
}
cout << "\n";
}
For a five number input, starting with three "1"s, and ending with two "0"s, this results in an output that looks like this:
1, 0, 1, 1, 1892218304,
I'm assuming the 1892218304 is a memory address, that's messing up the input. Though I don't really know.
Can anyone figure out why my sort operation is getting messed up?
Thanks in advance.
Suggestion
Use vector and sort in standard library
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>
int main()
{
std::vector<int> v;
for(int i=0; i < 10; i++)
{
v.push_back(i);
}
std::sort(v.begin(), v.end());
return 0;
}
The number you are seeing is not a memory address, but the value of the 4 bytes either immediately before or immediately after your array, interpreted as an int. Your code has an off-by-one error that causes an access to just outside the array. That much I suspect even though I don't have proof.
However, I can't find anything wrong with the code you posted that would cause it to access outside the array bounds.
Are you sure that num_elements has the correct value when this function is called?
Update to address the pastebin code
Things are going wrong already from the start:
int number;
int ar[number]
This is called a variable-length array and it's not legal in C90 or any flavor of C++. That your program compiles is probably "thanks to" a compiler extension... which helpfully raises a bug: the value of number is not initialized before the array is allocated.
You need to do one of the following:
declare ar as an array of constant size (a hard limit on the number of inputs you can accept)
dynamically allocate ar with new[] after number is entered from the user
(by far preferable) use an std::vector instead of an array
It looks to me like you're just getting an uninitialized value in your output.
Under the circumstances, the simplest "sorting" method is probably a counting sort -- i.e., count the number of 0's and the number of 1's the user enters, and then print out the appropriate number of 0's followed by the appropriate number of 1's.
As Tony said, your sorting algorithm is incorrect.
If we assume the following values:
ar[0] = 0
ar[1] = 1
ar[2] = 0
ar[3] = 1
ar[4] = 0
that gives us num_elements equal to 5.
Running this through your function as written, we get the following sorting behavior:
First pass, i = 0
ar[0] > ar[4] -> not true, so no switch
Secon pass, i = 1
ar[1] > ar[3] -> not true, so no switch
There is no third pass, as your for loop condition is met
i = 2
num_elements/2 = 2
2 is not less than 2
So based on your code, you didn't sort anything. This is the first issue.
Your print problem is interesting, based on what you have shown num_elements has been decremented by 1 at the top of your code snippet in your function - therefore the <= condition is correct and you should not be outside the bounds of your 'ar' array. Are you sure this is the exact code, or perhaps you did not copy it properly here and you are actually having a scoping issue?
(EDIT: Although the other answers suggesting using a built in sorting method via vectors, I'd suggest you still work your current implementation out to figure out WHY this is wrong, and what you need to do to fix it. You will not always have an available type that has built in sorting, so understanding the fundamentals is important for any young programmer.)
EDIT2: Based on the link you provided, you aren't properly defining your integer array. You are defining the array based on an uninitialized integer (int ar[number]) when number has not yet been initialized. You then read a value from the standard input to set number, and assume your array has been dynamically adjusted to be of the size read from cin. It does not work this way. Your entire loop is reading/writing outside the bounds of your array which is a big no-no. You want to read the number first, and then define your array based on the size read. - Looks like Jon beat me again.. BAH! :P
The last element being read and printed to the screen has never been written to. I think it's likely your function which accepts input has a fault, like maybe you have a line like you have here
num_elements -= 1; //since the array starts at 0
at the input function so that the first element you write to is at address 1. Then when you're reading them you read from address zero.
I kind of agree with Jim's point: Use the facilities in the C++ standard library to finish your task as much as possible.
Besides, I suggest you go through the algorithm all by yourself, manually, instead of letting the computer run it for you. Ever heard of the "Rubber Duck Debugging Method"? :-) Have a try.
for (int i = 0 ; i < stlVector.size() ; i++)
{
if (i == 10)
{
stlVector.erase(stlVector.begin() + 5 )
}
}
Does the termination condition part "stlVector.size()" take "stlVector.erase(...)"
into consideration? In other word does stlVector.size() refresh for every loop iteration?
I can't test it right now, so i posted a question here.
Thx in advance!
Best regards,
zhengtonic
Just to be clear, don't think of it in terms of the loop refreshing anything. Every time the condition is checked (at the start of each time through the loop), the size() method is called on the stlVector variable, and the current size of the vector is returned.
The erase() method reduces the size of the vector, so the next time size() is called, the returned value will be smaller.
Yes it does!
stlVector.size () // is called for evey iteration
Thus for every loop you'll have the test "i < stlVector.size ()" re-evaluate!
Yes, the test is performed, with side effects, for each loop.
A for loop is merely a nice convention - a for loop is easily decomposed as a while loop:
for (int i = 0 ; i < stlVector.size() ; i++)
{
if (i == 10)
{
stlVector.erase(stlVector.begin() + 5 )
}
}
Becomes:
int i = 0 ;
while(i < stlVector.size())
{
if (i == 10)
{
stlVector.erase(stlVector.begin() + 5 )
}
i++;
}
-Adam
Yes, it does, but don't do this! If you want to remove elements from a vector, do it inside another loop. You are deleting elements after the i index in this case: nothing guarantees that the stlVector[i+5] element exists. If you remove the i-th element from the vector, your count is broken because you can jump elements without checking them.
The most safe way of doing this is storing references for the elements on the stlVector you want to delete on another vector, and then iterate on this auxiliar vector doing stlVector.erase(auxVector[i]).
I expect the code you provided is just "fantasy code" (as one commenter put it) to give a concrete example of the type of thing you're trying to do.
However just in case it's not: the loop you gave will skip over the 12th element (i.e. the element originally in stlVector[11]) because when examining stlVector[10] you delete an earlier element, causing all later elements to shunt forward one position, but you still increment i at the end of the loop. So the next iteration will look at stlVector[11] which is actually the element that was originally in stlVector[12]. To remedy this, you need to --i after the call to erase().
Always reevaluate sure!
Also, to clarify a bit, since you asked if it's done this way "in VC++ 6".
The "continue condition" is re-evaluate on every loop in EVERY version of C, C++, C# and Java.
If any complier does not generate code which does that, it is broken, and must be avoided.
As others have said, yes the condition is re-evaluated each time through the loop. That's why a common performance optimization is:
int saveSize = someExpensiveComputation();
for (int i = 0 ; i < saveSize ; i++)
{
foo(i);
}
where the loop conditional is at all expensive to compute, instead of
for (int i = 0 ; i < someExpensiveComputation(); i++)
{
foo(i);
}
Where the expensive computation is needlessly done each iteration through the loop.
Yes it reduces the size. More information is here