Pera
Pera

Reputation: 173

Unexpected output in C++

This is not a problem with programming contest but with the language C++.

There is an old programming problem on codeforces. The solution is with C++. I already solved in Python but I don't understand this behavior of C++. In my computer and on onlinegdb's C++ compiler, I get expected output but on codeforces judge, I get a different output.

If interested in the problem : http://codeforces.com/contest/8/problem/A It's very simple and a small read. Though Reading it is not required for the question.

Task in Short:

Print("forward") if string a is found in string s and string b is also found in s

Print("backward") if string a is found in reverse of string s and string b is also found in reverse of s

Print("both") if both of above are true

Print("fantasy") if both of above are false

#include<bits/stdc++.h>
using namespace std;
#define int long long

//initializing all vars because blogs said uninitialized vars sometimes give unexpected result
string s="", a="", b="";
bool fw = false;
bool bw = false;
string now="";
string won="";
int pa=-1, pb=-1, ra=-1, rb=-1;

signed main()
{
    //following 2 lines can be ignored
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    //taking main input string s and then two strings we need to find in s are a & b
    cin >> s >> a >> b;
    //need reverse string of s to solve the problem
    string r = s;
    reverse(r.begin(), r.end());
    //pa is index of a if a is found in s else pa = -1 if not found
    pa = s.find(a);

    //if a was a substring of s
    if (pa != -1) {
        //now is substring of s from the next letter where string a was found i.e. we remove the prefix of string till last letter of a
        now = s.substr(pa + a.size(), s.size() - (pa + a.size()));
        //pb stores index of b in remaining part s i.e. now
        pb = now.find(b);

        //if b is also in now then fw is true
        if (pb != -1) {
            fw = true;
        }
    }
    //same thing done for the reverse of string s i.e. finding if a and b exist in reverse of s
    ra = r.find(a);
    if (ra != -1) {
        won = r.substr(ra + a.size(), r.size() - (ra + a.size()));
        rb = won.find(b);
        if (rb != -1) {
            bw = true;
        }
    }
    if (fw && bw) {
        cout << "both" << endl;
    }
    else if (fw && !bw) {
        cout << "forward" << endl;
    }
    else if (!fw && bw) {
        cout << "backward" << endl;
    }
    else {
        cout << "fantasy" << endl;
    }
    return 0;
}

For input

atob
a
b

s="atob", a="a", b="b"

Here reverse of atob is bota.

a is in atob.

So, string now = tob.

b is in tob so fw is true.

Now a is in bota.

So, string won = "" (empty because nothing after a). So, b is not in won.

So, rw is false.

Here answer is to print forward and in C++14 on my PC and onlinegdb, the output is forward but on codeforces judge, it's both.

I did many variations of the code but no result.

Finally I observed that if I run my program on PC and don't give any input and terminate the program in terminal with Ctrl-C, it prints both which is strange as both should only be printed when both fw and rw are true.

What is this behavior of C++?

Upvotes: 0

Views: 183

Answers (2)

The Long Nguyen
The Long Nguyen

Reputation: 92

The above answer and comments are way more enough information for your question. I cannot comment yet so I would like to add a simplified answer here, as I'm also learning myself.

From the different outputs on different compilers you can trackback the logic and found the flow of code is differ in this line:

if (rb != -1) {

Simply adding a log before that line, or using a debugger:

cout << "rb:" << rb << endl;

You can see that on your PC: rb:-1

But on codeforces: rb:4294967295

won.find(b) return npos, which mean you have an assignment: rb = npos;

This is my speculation, but a possible scenario is:

On your PC, rb is compiled as int (keyword), which cannot hold 4294967295, and assigned to -1.

But on codeforces, rb is compiled as long long, follow the definition, and 4294967295 was assigned instead.

Because you redefine the keyword int, which is advised again by standard of C++ programming language, different compiler will treat this line of code differently.

Upvotes: 1

Useless
Useless

Reputation: 67733

Let's dissect this code and see what problems we can find. It kind of tips over into a code review, but there are multiple problems in addition to the proximate cause of failure.

#include<bits/stdc++.h>

Never do this. If you see it in an example, you know it's a bad example to follow.

using namespace std;

Fine, we're not in a header and brevity in sample code is a reasonable goal.

#define int long long

Oh no, why would anyone ever do this? The first issue is that preprocessor replacement is anyway prohibited from replacing keywords (like int).

Even without that prohibition, this later line

int pa=-1, pb=-1, ra=-1, rb=-1;

is now a deliberate lie, as if you're obfuscating the code. It would have cost nothing to just write long long pa ... if that's what you meant, and it wouldn't be deceptive.

//initializing all vars because blogs said uninitialized vars sometimes give unexpected result
string s="", a="", b="";

But std::string is a class type with a default constructor, so it can't be uninitialized (it will be default-initialized, which is fine, and writing ="" is just extra noise).

The blogs are warning you about default initialization of non-class types (which leaves them with indeterminate values), so

bool fw = false;

is still sensible.

NB. these are globals, which are anyway zero-initialized (cf).

signed main()

Here are the acceptable faces of main - you should never type anything else, on pain of Undefined Behaviour

int main() { ... }
int main(int argc, char *argv[]) { ... }

Next, these string positions are both (potentially) the wrong type, and compared to the wrong value:

ra = r.find(a);
if (ra != -1) {

could just be

auto ra = r.find(a);
if (ra != std::string::npos) {

(you could write std::string::size_type instead of auto, but I don't see much benefit here - either way, the interface, return type and return values of std::string::find are well-documented).

The only remaining objection is that none of now, won or the trailing substring searches correspond to anything in your problem statement.

Upvotes: 4

Related Questions