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.
Related
I have a function which should modify an array (of floats) in the original parent function. I am using the following code:
void sortFunction(Word**words, int wordCount){ //to sure if two * are correct (pointer to an array..?)
int i = 0;
for(i=0;i<wordCount-1;i++){
Word first = *words[i]; //values fine
Word second = *words[i+1]; //weird values, causes segfault
if(first.data[0] > second.data[0]){
//do stuff
}
}
}
int main(int argc, char ** argv){
Word* words = NULL;
int wordsCount = ...
//filling the array in a loop and using realloc for memory allocation
//Here, the array is filled correctly (verified)
sortFunction(&words, wordsCount);
}
Where Word is a typedef struct and Word.data is the (dynamic) float array. When checking in the parent function, the array is allocated and the values set correctly.
I have tried with about 10 elements in the array, but always only the first ([0]) element is fine in the sortFunction(), second and all others are messed up. I also have an int propery in the struct, and when I try to print it for the second element, I get something over 1 billion.
I assume I am not passing the array correctly - I use the following code (just a sample) to pass regular variables, so I tried to modify it for an array, but apparently, not correctly. What is the right way to do this for an array?
void foo(int*var){
*var=8;
}
int main(){
int var = 5;
changeVar(&var);
}
Thanks in advance for any tips!
Postfix [] has higher precedence than unary *, so *words[i] is parsed as *(words[i]), which isn't what you want.
You need to dereference the words pointer before applying the subscript, so you need to explicitly group the * operator with words using parentheses:
Word first = (*words)[i];
Word second = (*words)[i + 1];
First, you do not need to pass **, just one is enough, because you will be passing the address of your array anyway:
void sortFunction(Word* words, int wordCount)
and call it as:
sortFunction(words, wordsCount);
Second, the Undefined behavior originates in the following statement:
Word first = *words[i]; Word second = *words[i+1];
It should have been (*words)[i] but still, you are copying structs, so your dynamic data array is not copied correctly. avoid this useless copy, and use this instead, AFTER changing the protoype of sortFunction:
Word* first = &words[i];
Word* second = &words[i+1];
if(first->data[0] > second->data[0])
p.s: This does not guarantee that the rest of your code is correct, just comments of the parts you showed of the code.
I am a beginner at c++ can anyone explain me this code:
#include <iostream>
void display(int b)
{
std::cout << b << std::endl;
}
int main()
{
int a;
display(a=10);//display 10
std::cout << a << std::endl;//also display 10
return 0;
}
I know we can use = operator to set default values for a function parameters, but here it's in the function call, apparently "disply(a=10)" pass the value 10 to the function and store it in the variable "a" at the sametime.
is this correct coding in c++ and can anyone explain the assignment part?
The line
display(a=10);//display 10
equals to:
a = 10;
display(a);
This is because the value of the clause a = 10; is a.
I think this answers your question.
You need to know about = operator more. Not only is it assign rhs (right hand side) value to lhs (left hand side), but also it refers to the lhs.
Suppose this code:
a = b = c;
is exactly equal to
a = (b = c);
because = is right-associative.
If c is 10, the code assign 10 into b, and assign the value of b into a. So now a == b == c == 10.
The built-in assignment operator =
is right-associative
which means it groups to right, e.g. a = b = c means a = (b = c),
is an lvalue expression that refers to the left hand side.
Note that in C an assignment produces a pure value, while in C++ it produces a reference (in the common language meaning of referring).
This means that you can assign a value to multiple variables:
a = b = c = 12345;
which is parsed as
a = (b = (c = 12345));
which first copies 12345 to c, then copies c to b, then copies b to a.
And it means that you can assign to the result of an assignment:
((a = b) = c) = 12345;
which first copies the b value to a, then copies the c value to a, then copies 12345 to a, leaving b and c unchanged…
In your case, the code
display(a=10);
is equivalent to
a = 10; display( a );
Since the display function takes an int by value, this is equivalent to
display( 10 )
but if display had a reference argument then it could not be rewritten this way.
A common pitfall is to write
if( x = 12345 )
when one means to do a comparison,
if( x == 12345 )
Many compilers will warn about the first if the warning level is upped, as it should be.
More guaranteed ways to detect it include
Using const everywhere it can be used.
x can’t be assigned to when it’s const. This is my preferred solution.
Writing if( 12345 == x ).
Some people prefer this, but I find it hard to read, and as opposed to const it only helps to avoid the mis-typing when the writer is already, at that very point, very aware of the problem.
Defining a custom if construct via a macro.
Technically this works, also for other constructs that use boolean conditions, but in order to be useful such a macro should be short, and this runs the risk of name collision. It's also hard on maintainers who are unfamiliar with the (effectively) custom language.
In C++03 the standard library required that any container element type should be assignable, and the assignable criterion required that a custom assignment operator T::operator= should return T& (C++03 §23.1/4) – which is also a requirement on the built-in assignment operator.
Until I learned that I used to define assignment operators with result type void, since I saw no point in supporting coding of expressions with side-effects (which is generally a bad practice) at the cost of both efficiency and verbosity.
Unfortunately this is a case where in C++ you pay for what you don’t use and generally should not use.
The assignment <variable> = <value> in C, C++ is and expression which means it have a value and this value is, of course, the <value> you've just assigned.
That's the reason why you can assign a value to multiple variables like this:
a = b = c = 1;
because internally it works something like this
a = value of (b = value of (c = 1));
and since the assignment does indeed have a value, the value of (c = 1) is
1, value of (b = (c = 1)) is 1 and therefore we get a = 1. And as a
If the assignment wouldn't be an expression and didn't have a value, we would
get an error, because value of (c = 1) would not exist and we would get a
syntax error.
So in your code, display(a=10); means: *set value a to 10 and pass the
resulting value (which would be 10) as an argument to the function display.
It is correct.
display(a=10); //It assigns 10 to a and 10 is passed as the parameter to function.
I tried the following:
if(int i=6+4==10)
cout << "works!" << i;
if(int i=6+4,i==10)
cout << "doesn't even compile" << i;
The first works fine while the second doesn't compile. Why is this?
EDIT: Now I know that the first one may not work as I intend it to. The value of i inside the if scope will be 1, not 10. (as pointed out by one of the comments on this question).
So is there a way to initialize and use a variable inside of an if statement at the same time similar to for(int i=0;i<10;i++)? So that you could produce something like if((int i=6+4)==10) (which will not compile) where the value of I inside the if scope would be 10?
I know you could declare and initialize I before the if statement but is there a way to do this within the statement itself?
To give you an idea why I think this would be usefull.
if(int v1=someObject1.getValue(), int v2=someObject2.getValue(), v1!=v2)
{
//v1 and v2 are visible in this scope
//and can be used for further calculation without the need to call
//someObject1.getValue() und someObject2.getValue() again.
}
//if v1==v2 there is nothing to be done which is why v1 und v2
//only need to be visible in the scope of the if.
The expression used as an initializer expression must be an assignment-expression so if you want to use a comma operator you must parenthesize the initializer.
E.g. (not that what you are attempting makes much sense as 6 + 4 has no side effects and the value is discarded and i == 10 uses the uninitialized value of i in its own initializer.)
if (int i = (6 + 4, i == 10)) // behaviour is undefined
Did you really mean something like this?
int i = 6 + 4;
if (i == 10)
When using the form of if that declares a new variable the condition checked is always the value of the initialized variable converted to bool. If you want the condition to be an expression involving the new variable you must declare the variable before the if statement and use the expression that you want to test as the condition.
E.g.
int i;
if ((i = 6 + 4) == 10)
I doubt seriously either example works to do anything useful. All that it does is evaluate to "true" in a complicated fashions.
But the reason the second one doesn't compile is that it's interpreted as two declarations: int i = 6+4; int i==10 and int i==10 isn't valid because that's an equality operator, not an assignment.
There are different alternatives, because what you want cannot be done (you cannot mix the comma operator with declarations). You could, for example, declare the variable outside of the if condition:
int i = 6+4;
if ( i == 10 ) ...
Or you can change the value of i to be 0 instead of 10 and recalculate i inside the else block:
if ( int i = (6+4)-10 ) ; else {
i += 10;
// ...
}
Much simpler, don't declare the variable at all, since you know the value inside the loop:
if ( (6+4)==10 ) {
int i = 10;
// ...
}
Unless of course you need the value of i in the case where it is not 10, in which case the second option is the most appropriate.
As of C++17 what you were trying to do is finally possible:
if (int i=6+4; i==10)
cout << "works, and i is " << i << endl;
Note the use of ; of instead of , to separate the declaration and the actual condition.
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?
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <iostream>
using namespace std;
char a[21]; // If this is put inside the function unter -> junk output
char* b="";
void unter()
{
char *new_str = "";
strcpy(a, new_str);
char str_temp[10]="";
int chnum =0, neighbor1=3, neighbor2=5, mynode=4;
sprintf(str_temp,"%d",chnum);
b = strcat(a, str_temp);
b = strcat(b, "_from");
sprintf(str_temp,"%d",mynode);
b = strcat(b, str_temp);
b = strcat(b, "to");
sprintf(str_temp,"%d",neighbor1);
b = strcat(b, str_temp);
}
int main()
{
unter();
cout << a;
cout << b;
std::cin.get();
}
This is my code in C++. I'm not sure how the character array 'a' also has the same values as 'b'. And moreover, when I declare 'a'
char a[21];
inside function unter(), I'm getting some junk value for 'b'(as output). Care to explain how?
a is a char array and b is a pointer that points to a, so when printing them, they always print the same thing. When you move the declaration for a into unter, it is destroyed when unter returns, leaving b a dnagling pointer, so you get garbage when you print it.
b = strcat(a, str_temp);
is probably what's causing your issue, since the return value from strcat() is the first parameter that was passed to it, hence why you're seeing a and b becoming equal, since b is getting set to a in that call.
strcat() returns the result of the concatenation operation, so
b = strcat(a, str_temp);
results in b pointing to the array a[]. The subsequent strcat() operations effectively do the same, so the end result is that b points to a[] as you observe. If you declare a[] inside unter() it will have local scope to that function, with the result that the global variable b will point to random/undefined memory contents after you exit the call to unter().
It's mildly worth noting that you're doing a lot of work that could be accomplished more easily with
sprintf(a, "%d_from%dto%d", chnum, mynode, neighbor1);
You can do the whole concatenation and sprintf's in a single line.
char* b="";
void unter()
{
int chnum =0, neighbor1=3, neighbor2=5, mynode=4;
char str_temp[21];
sprintf(str_temp,"%d_from%dto%d", chnum, mynode, neighbor1);
b = new char[strlen(str_temp)+1];
b = strcpy(b, str_temp);
}
Only funny thing is you must remember to delete b when you are done. The other option is using the a buffer and sprintf directly to it:
char a[21];
void unter()
{
int chnum =0, neighbor1=3, neighbor2=5, mynode=4;
char str_temp[21];
sprintf(a,"%d_from%dto%d", chnum, mynode, neighbor1);
}
When you define a inside the function, memory for the variable a is allocated on stack. This memory is destroyed when the function exits. Your pointer b is pointing to starting address of a. Now, if you try to access b outside the function, it is pointing to a memory location which is already destructed and contain garbage values. Basically, b becomes a dangling pointer.
If you declare a inside the unter() function, then it is only scoped inside that function. Attempt to print b from outside the function will print junk since it is pointing to a which is already destroyed.
This is a classic example of why you should always make sure to not to point to a local variable from a global one.
In addition to the other hints provided, you should take notice of the line
b = strcat(b, str_temp);
which seems rather inappropriate for b is merely defined as a char pointer to a single byte storage ("" defines an empty string, i.e. an array of chars with a single element containing '\0')
So when strcat appends to b, it creates a buffer overrun.
Edit:Actually I just noticed that b was assigned to point to a, (thanks to the line preceding the one mentionned) so that would then be ok, since a may have the room for this... It doesn't make sense however, to need the two variables.
Maybe what you do not understand, is that although strcat() returns a pointer, this return doesn't need to be "consumed", it is merely a convenience, for when we chain commands an such. In other words you can simply write:
strcat(a, str_temp);
Not requiring any char * b.