I am having an issue with an integer wrapping around to its minimum value unexpectedly.
The value of the integer is 15 before it wraps to -858993460.
Here is the code that is causing this issue:
while(ArrayLocation2 < EmpArray2Size)
{
GivenEmployees[(*EmployeeSize++)] = curr2;
prev2 = curr2;
if(ArrayLocation2 < EmpArray2Size)
{
curr1 = EmpArray2[ArrayLocation2];
}
ArrayLocation2++;
if((ArrayLocation2 >= EmpArray2Size) || (prev2.HourlyRate > curr2.HourlyRate))
{
subFiles++;
}
}
If I manually change the values that it needs (16, 17, 18, etc) it works as expected.
Size is declared as int Size = 21; and passed into its current method as &Size if it makes a difference.
Why is this exactly happening?
The problem is that you are incrementing the pointer - and it ends up pointing into random territory.
You probably intended to write:
GivenEmployees[(*EmployeeSize)++] = cur2;
The parentheses are necessary here; they are unnecessary in the original.
From the comments:
The integer that is wrapping is "EmployeeSize" and is declared as I've described in the OP.
(Except that it is called 'Size' in the original OP.) However, it appears to be:
void this_function(..., int *EmployeeSize, ...)
{
...code...
}
The expression *EmployeeSize++ returns the value pointed to by EmployeeSize and then increments the pointer, not the pointed-to item. Try (*EmployeeSize)++.
GivenEmployees[(*EmployeeSize++)]
Smells like trouble. It is parsed as
GivenEmployees[(*(EmployeeSize++))]
Postfix incrementation has higher precedence than dereferencing.
So, you increment a pointer and then dereference it. Is 'EmployeeSize' a pointer to an array?
Related
I tried to write the following code in C++ to reverse a string. For some reason, when the string is of odd-length it gives a wrong output.
#include <iostream>
using namespace std;
void swapWithOutThirdVar(char &a, char &b) {
a = a + b;
b = a - b;
a = a - b;
}
void reverse(char string[]) {
int length = 0;
while (string[length] != '\0') {
length++;
}
int left = 0, right = length - 1;
while (left <= right) {
swapWithOutThirdVar(string[left], string[right]);
left++;
right--;
}
}
int main() {
char string[25];
cin>>string;
reverse(string);
cout<<string<<endl;
}
For example if I enter lappy to the console, the subsequent output is yp. I am new to programming, so please be kind to me no matter how stupid the underlying mistake is.
There are many ways to resolve the error in your code, but the backbone error in your code lies in the swap function that you have defined on your own.
void swapWithOutThirdVar(char &a, char &b) {
a = a + b;
b = a - b;
a = a - b;
}
I know that this is a very well-known function used to swap two variables without using a third variable. But it has two issues:
For certain values of a and b, the operation a + b can result in an overflow.
(This is the case here) If you run into passing the exact same variables to the function, the swap would end up being erratic. Here's why:
Let's say that you're passing the variable char c to both the arguments of the function. Since in your function the parameters are being passed by reference, the dummy variables a and b are actually the same variables, that is, they're aliases to the same c. In a nutshell, a and b denote the same variable c.
So, now when you do a = a + b, the operation actually results in c = c + c, which means that c's (ASCII) value has been doubled by the end of execution of this statement.
The fun hits when the second statement comes into play. b = a - b results in c = c - c, which assigns 0 to c. That's where you went wrong, kiddo.
The third statement doesn't do anything good to the process. a = a - b results in c = c - c, which still makes c hold 0.
So, your variable gets assigned the value 0, instead of getting swapped with (itself?).
Now, you might be wondering where are you exactly ending up swapping the same variable, right?
When you're having an odd-length string, note that in the last iteration of the second while loop, the values of left and right are the same. In that case, left and right have the same indices for string and hence string[left] and string[right] are the same variables. The same variables are being passed to the swap function in that iteration.
Now, as I had stated earlier: passing the same variables to the swap function will end up handing a 0 to the variable that has been passed to it. For your example case, this is what string looks like at the end of the last iteration:
['y', 'p' '\0', 'a', 'l']
In C/C++, a null (0) marks the end of a string. Therefore, the weird output (yp) is justified.
In even-length strings, left will never be equal to right in any of the iterations of the second while loop. That's why, a same variable is never passed to the swap function, and that's why the reverse function works just as fine as the same variable is never passed to it.
Therefore, firstly you need to take care of the same-variable case. In case a and b are the same variable, you simply return from the function as swapping a variable with itself is techically pointless. Utilise the fact that if two variables are basically references to the same variable, they must be having the same address.
void swapWithOutThirdVar(char &a, char &b) {
if (&a == &b)
return;
a = a + b;
b = a - b;
a = a - b;
}
But this doesn't resolve the overflow issue. So, you need to do something else.
Assuming that this is a programming assignment problem in which you need to implement everything on your own, you can go for the XOR-swap which uses bitwise XOR to swap two variables. Going by the name of your swap function, I think you're aware of the vintage three-variable swapping technique and that using a third variable for swapping is also a restriction in your assignment.
Operating XOR on two numbers doesn't result in overflow, so that problem is fixed. The XOR method although, doesn't independently resolve the same-variable case and ends up handing the variable a 0 in the first statement itself, so you need to retain the address equality checking part:
void swapWithOutThirdVar(char &a, char &b) {
if (&a == &b)
return;
a ^= b;
b ^= a;
a ^= b;
}
Also, you can leave the swap function as it is and slightly modify the second while loop's condition to resolve the error:
For an odd-length string, the middle character's position is left unchanged when reversed. Come to think of it: the left-equals-right case arises when left and right (both) are pointing to the middle character of the string. So, the loop needs to run only as long as left < right holds true. For an even-length string, left never becomes equal to right. The while loop ends right when left and right are indices of the two adjacent middle elements of the string. Therefore, the left < right modification doesn't hurt the even-length case. So, the corresponding fix would be:
void reverse(char string[]) {
int length = 0;
while (string[length] != '\0') {
length++;
}
int left = 0, right = length - 1;
while (left < right) {
swapWithOutThirdVar(string[left], string[right]);
left++;
right--;
}
}
This concludes the bug explanation and rectification part. But in case this isn't for a programming assignment in which you have to implement everything on your own, that is, you don't have restrictions, you should consider the following instead:
Judging by the using namespace std; in your code, it appears that it was meant for C++0x or beyond. So, you should be considering the following things:
From C++0x onwards, you already have a predefined swap function (std :: swap). You can use that instead. Overflows and same-variables being passed to it aren't an issue here. See here.
You're using a C-style string in your program. C-style strings are not recommended anymore. Moreover, you're using C++0x or beyond. So, you should be using std :: string instead. See here.
You can use the reverse function from the algorithm header. See here.
Your swap implementation is incorrect if a and b point to the same memory location.
So you shall fix your loop:
while (left < right) {
swapWithOutThirdVar(string[left], string[right]);
left++;
right--;
}
This is a peculiarity of C++'s call-by-reference semantics. Your swap function will give unexpected (and incorrect) results when both &a and &b are the same memory address. This occurs when left == right.
Consider the following substitution, where I've changed a and b to both be the same variable, middleLetter:
middleLetter = middleLetter + middleLetter;
middleLetter = middleLetter - middleLetter;
middleLetter = middleLetter - middleLetter;
The second line sets middleLetter to zero, and the third line leaves it as zero.
The simple fix is to change your loop condition to while(left < right). There is no need to swap the middle letter with itself anyway.
I am getting started with C++. I wanted to understand the different
outputs while playing around with this snippet of code.
int main()
{
int i = 3;
int *ptr = &i; //stores address of the i
while(*(ptr)--) //the same as i--
{
cout << *ptr << endl;
}
}
When I run this code I understand that the deferenced value
of ptr, which is "i", gets 1 subtracted from it and the loop exits
when "i" equals 0. But when I use while(*ptr--) instead of while(*(ptr)--) I get a list of random integers which eventually go down to 0 and the loop breaks.
To my understanding when I use *ptr-- I am subtracting a byte(size of one int) from the initial address of &i(*ptr) with each loop. But why does the program terminate eventually? No matter what the value of "i" is, the program prints 23 random numbers with the last one being 0 and the loop exits. Should I not get an overflow error since the program runs out of memory?
However, when I use while(ptr--) the program does go into an infinite loop.
What exactly is happening?
Thank you very much.
(ptr) is the same as ptr, thus (ptr)-- is the same as ptr--.
*ptr-- IS NOT the same as i-- !
You are applying operator-- to the right side of the pointer. The suffix/postfix operator-- has a higher precedence than operator*. So, *ptr-- is the same as *(ptr--), not (*ptr)-- like you are expecting.
IOW, ptr-- gets evaluated first, which returns a copy of the current pointer and then decrements the pointer, and then you are dereferencing the copied pointer to retrieve the value that was previously being pointing at.
That is why you are seeing garbage - you are decrementing the pointer into memory that does not belong to you.
To simply decrement the int and not the pointer, use (*ptr)-- instead. IOW, dereference the pointer first, then decrement the value being pointed at, eg:
int main()
{
int i = 3;
int *ptr = &i; //stores address of the i
while((*ptr)--) //the same as i--
{
cout << *ptr << endl;
}
}
Live demo
Parenthesis and operator precedence matter!
I was hoping someone could explain how the condition statement of return (i % 2) ? &odd : &even; is able to determine if i is even or odd.
I am confused because &odd and &even are references to int odd[] and int even[]. It is my understanding the a condition statement does not "iterate" through the array and check all values in the array in order to check the condition of (i % 2) for a match. below is the code. I hope I was clear enough.
#include <iostream>
int odd[] = { 1, 3, 5, 7, 9 };
int even[] = { 0, 2, 4, 6, 8 };
decltype(odd)* arrptr(int i) { // equivalent to int (*arrPtr(int))[5] or
// auto arrPtr(int i) -> int(*)[5]
return (i % 2) ? &odd : &even;
}
int main()
{
arrptr(3);
system("pause");
return 0;
}
This is to explain the confusion you've as I see in the comments you posted to the other answer.
How does the conditional statement know the difference between what is a even number or an odd number?
It doesn't. It simply evaluates the first expression and checks the truth value. Like an if, you insert the logic on deciding if i is even or odd. Usually this is done with the interger reminder operator i % 2.
The expressions in the conditional statement are nothing more than references to an array named &odd[] and &even[]. There is nothing in the program that tells the program what even or odd number means.
No, the second and the third arguments are what &odd[] and &even[] are. You missed the first; it is a conditional expression which will be evaluated for a truth value.
i % 2 will return 0 if i is even, else 1 if i is odd. This integer value will be implicitly converted into a boolean value since the expression is evaluated in a boolean context. In C and C++ any non-zero value is true else false. Hence if i is even it'll return false, else true.
I think what is confusing you is the name of operands 2 and 3; mentally rename them into evenArray and oddArray. What the operator does is, it returns an array. Which array? That it decides based on the first operand, which in turn decides it with parity (even/odd) of the argument i.
That is the C conditional operator ?:. The part before the question mark is a Boolean expression. If it evaluates to true then the part between the questions mark and the colon is executed otherwise the other part is executed. It's equivalent to:
if(boolean expr) { expression1 }
else { expression2 }
In your example, you could write:
decltype(odd)* arrptr(int i)
{ if(i % 2) return &odd;
else return &even;
}
You might be confused by how the arrays are named. The function returns a pointer to an array depending on the value of i (the function knows nothing about the numbers stored in the arrays). That is, if i is an odd number we return a pointer to the array named odd and if it i is even we return a pointer to the array named even. The i % 2 part tells you if i is even or odd. Hope this helps.
int main()
{
int* nir = new int; // creating dynamic memory
*nir = 7; // assigning value
cout << *nir << endl;
delete nir; // deleting
nir = 0; // **is this line for assigning the address nir=0? 0 is also part of memory right? Why didn't we put NULL?
*nir = 8; // **can i do like this and change the value, so that the output can be 8 now?
cout << *nir << endl;
delete nir;
nir = 0;
return 0;
}
This is the code that I created to understand new. But, even though it was compiled fine by Code::Blocks, during the runtime, it crashes. I have two questions, which I have already mentioned in comment part.
nir = 0;
is this line for assigning the address nir = 0? 0 is also part of memory right? Why didn't we put nir = NULL?
*nir = 8;
can I do like this and change the value, so that the output can be 8 now? After all, I have already deleted the *nir value.
nir=0;
This sets the pointer to NULL. 0 and NULL are the same in this context.
*nir=8
This is wrong as nir in not a valid pointer. It's no suprise that it crashes!
cout<<*nir<<endl;
This is also wrong as nir is invalid pointer. You cannot read or write.
delete nir;
This is harmless, as deleting a NULL pointer is safe (it does nothing).
This code snippet is wrong
nir=0; //**is this line for assigning the address nir=0? 0 is also part of memory right? Why didn't we put NULL?
*nir=8; //**can i do like this and change the value, so that the output can be 8 now?
cout<<*nir<<endl;
delete nir;
nir=0;
You did not allocate memory and are trying to write to address 0.
*nir=8; //**can i do like this and change the value, so that the output can be 8 now?
Usually the program will crash.
As for the line
nir = 0;
then it is equivalent to
nir = NULL;
In C++ NULL usualy defined as 0 or ( long )0 and so on.
According to the C++ Standard
1 A null pointer constant is an integer literal (2.14.2) with value
zero or a prvalue of type std::nullptr_t. A null pointer constant can
be converted to a pointer type; the result is the null pointer value
of that type and is distinguishable from every other value of object
pointer or function pointer type.
You tagged c++ so I recommend using nullptr instead of 0/NULL
nir = nullptr;
The problem
The literal 0 (which is essentially of type int) also serves as a null pointer literal in C++. This kludge results in ambiguity and bugs.
Solution
Use the nullptr keyword instead of 0 to indicate a null pointer value
source
A short breakdown of errors you purposely committed:
int main()
{
int* nir = new int; // allocating dynamic memory
*nir = 7; // assigning value
cout << *nir << endl;
delete nir; // deleting
nir = 0; // **is this line for assigning the address nir=0?
// 0 is also part of memory right? Why didn't we put NULL?
The previous comment is wrong. For historical reasons, assigning a literal 0 to a pointer variable means setting it to a null pointer constant. This is not guaranteed to be 0 [!!!]. NULL and nullptr_t are more modern...
*nir = 8; // **can i do like this and change the value,
// so that the output can be 8 now?
cout << *nir << endl;
On some systems you can do that. But your computing platform is now irretrievably corrupted. Modern systems catch the culprit and raise General Protection Fault, which only kills your program.
delete nir;
Because programmers are keen to avoid useless work, the above (delete NULL) is defined as a no-op
nir = 0;
return 0;
The previous two lines are useless, as nir is never used again and main per standard returns 0 unless it explicitly doesn't, quite in contrast to any other function.
}
I am from C background, and now I am learning OOP using C++
Below is a program that calculates factorial.
#include <iostream>
using namespace std;
void main ()
{
char dummy;
_int16 numb;
cout << "Enter a number: ";
cin >> numb;
double facto(_int16);
cout << "factorial = " <<facto(numb);
cin >> dummy;
}
double facto( _int16 n )
{
if ( n>1 )
return ( n*facto(n-1) );
else
return 1;
}
The above code works fine.
But if I replace the return statement
return ( n*facto(n-1) );
with this
return ( n*facto(n--) );
then it doesn't work. The n-- won't decrement n by 1. Why?
I am using Visual Studio 2012
Edit:Got it! thanks :)
*also, I would like to add to the answers below: using --n will cause the n to decrement before the statement is executed. So, due to pre-decrement, the expression will become (n-1)*facto(n-1) . That is why it is better not to use pre-decrement in this case *
Currently, by using n-- you are passing the original and therefore unmodified value of n into facto which is causing a loop.
You need to use n - 1 instead. It would, on the face of it, be tempting to use --n since that would decrement n and evaluate to the new (lower) value. But --n will give you undefined behaviour since you are pre-multiplying the function return value by n and since * is not a sequence point, the value of n is not well-defined.
(By the way, the behaviour in C would have been identical).
[Edit: acknowledge Mike Seymour on the undefined behaviour point].
EDIT:: The explanation below is only to shed light on the usage of Post and Pre-Decrement for OP's better understanding of them. The correct answer for OP's code is, n*facto(n - 1). #OP: You should not do any pre-drecrement in that part of your code because it will invoke Undefined Behavior due to unsequenced modification of variable n.
Pre And Post-Decrement::
You have to use pre-decrement (wiki-link) if you want to decrement the variable before the value is passed. On the other hand, a post-decrement evaluates the expression before the variable is decremented:
int n = 10, x;
x = --n; // both are 9
and
int n = 10, x;
x = n--; // x = 10, i = 9
Why not to use pre-decrement in your case?:: n*facto(n--) causes UB.
Why?
The Standard in ยง5/4 says
Between the previous and next sequence point a scalar object shall
have its stored value modified at most once by the evaluation of an
expression.
and
The prior value shall be accessed only to determine the value to be
stored.
It means, that between two sequence points a variable must not be modified more than once and, if an object is written to within a full expression, any and all accesses to it within the same expression must be directly involved in the computation of the value to be written.
return ( n*facto(n--) );
You are using the post decrement operator.
What happens is, You pass the value of n to the function and then decrement it. That doesn't affect the value that is already passed to the function