Undefined behaviour

To those programmers who use the header <bits/stdc++.h> , I strongly recommend them to stop using this header.I know its convenient to use the header as you don’t need to include any other header but it isn’t any standard header of C++ and you’ve no idea what it will do to the program.

More information: More info

As an example I’m providing 2 of my codes. The only difference between them is that one uses <bits/stdc++.h> (and gives Wrong Answer for one of the test cases) and another does not use <bits/stdc++.h> (and gives Correct Answer for the same test case)

The one with <bits/stdc++.h> : Solution 1
The one without <bits/stdc++.h> : Solution 2

The problem is GMEDIAN, from November Long Challenge. I’ve written an editorial on the question as well.
In case you need : Editorial

PS: Yes. I had a tough time debugging this :stuck_out_tongue:

3 Likes

Thanks for the post. I will now switch from

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

to this

#include <algorithm>
#include <iostream>
#include <cstring>
#include <complex>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <vector>  
#include <string>
#include <cmath>
#include <ctime>
#include <queue>
#include <list>
#include <map>
#include <set>
using namespace std;

Can anyone explain why this is happening? What would be the test case that causes this issue?

The same thing happens if you include instead of <stdio.h>.

https://www.codechef.com/viewsolution/21642809

1 Like

#1)Here is wrong answer solution with iostream (standard i/o library)
#2)Here is accepted solution with bits/stdc++.h (just used cout instead of printf)

Now should I stop using iostream too ? XD

It’s because of printf,scanf.
Though thanks for sharing.

Switching from scanf to cin for n only fixes the problem.

CodeChef: Practical coding for everyone

1 Like

May be a subtle bug in compiler.
In my solution is with iostream.

In the two solutions I have provided, I am pre-calculating the factorials at the starting of main() function.
If I calculate the factorials by calling a function, I’m again getting correct answer.
Here, I’m pre-calculating factorials by using a function fill() : CodeChef: Practical coding for everyone

There is too much of undefined behaviour of this code, it would be nice if someone answers this question.

1 Like

The issue is somehow related to the usage of the printf call in the presence of the <iostream> header (part of the bits/stdc++.h include).

For example, if you add fflush(stdout); at the end of you main program, you will get a correct solution regardless of whether you include bits/stdc++.h, <iostream>, or <stdio.h>.

The overall recommendation would be to use cin and cout in C++ programs since cin and cout have type-safe checks as compared with scanf and printf. scanf and printf (along with stdio.h) are remnants of the early days of C programming. Unless you are into embedded programming as your career, it makes sense to deal with C++ paradigms. Furthermore, if you consider competitive programming as a preparation for job hunting and interviews, the cin/cout approach definitely beats scanf/printf. Just compare:

scanf("%lld", &a[i]);

printf("%lld\n", ans);

vs

cin >> a[i];

cout << ans << “\n”;

If you need faster IO with cin and cout, you can add

ios_base::sync_with_stdio(false);
std::cin.tie(NULL);

at the beginning of your main program. The relative performance of data reading is the following (the measurements are done on HackerRank servers but CodeChef servers are similar)

Reading 4,000,000 positive integer values, each less than 10^7:

  • 1.55 sec - simple cin
  • 0.51 sec - scanf
  • 0.41 sec - cin with sync_with_stdio(false) and cin.tie(NULL)

There are ways to reduce it even further (to sub 0.1 sec levels) but it becomes somewhat esoteric in implementation.

1 Like

I think I know what went wrong! I think your problem is simply undefined behavior. On line 157,

if (j < n)
   while(a[i]==a[j]) {    // LINE 157
      ...
      j++;
   }

you are sometimes reading outside of the array as j could become n. If you change it to

while(j < n && a[i]==a[j]) {
  ...
  j++;
}

everything passes without any problems (apart from timeout on the big test cases).

9 Likes

Considering people are talking about undefined behavior I might as well add my 2 cents.

It’s worth noting that even though something is undefined behavior, the result need not be random at all. It can be perfectly consistent, but you can’t assume anything about the behavior.

One really interesting fact is that compilers can (ab)use undefined behavior to optimize code. One simple example (not my code, stolen from a youtube comment)

#include<iostream>

using namespace std;

int main()
{
    for (int i = 0; i < 10; ++i)
        cout << i*1000000000 << endl;
}

How many lines do you expect this to print?

  • With no optimization it’s as you expect, 10 lines.

  • With optimization (at least for my compiler) the loop runs forever.

I can recommend you to stop reading after this sentence try to reason about why this is, and look at the helpful warning the compiler gives you.


The compiler very helpfully warns you if you compile with optimization:

ub.cpp: In function ‘int main()’:
ub.cpp:7:19: warning: iteration 3 invokes undefined behavior [-Waggressive-loop-optimizations]
         cout << i*1000000000 << endl;
                   ^~~~~~~~~~
ub.cpp:6:23: note: within this loop
     for (int i = 0; i < 10; ++i) {

So what’s going on? The problem is signed integer overflow, which is undefined behavior. But why does that produce an infinite loop?

The compiler knows that signed integers are not allowed to overflow. This puts a constraint on i, namely that i < 3. But in that case the loop condition i < 10 is always true, so why check that? The compiler happily optimizes that check away, and we end up with an infinite loop.

4 Likes

Is this for real?

really weird :open_mouth:

1 Like

@harrypotter0 yes. It is :stuck_out_tongue:

1 Like

@divik544 I agree :confused:

I still feel its not the header but some undefined behavior in code which fortunately decided to behave correctly on changing header.

1 Like

It does seem iostream is the culprit, cstdio seems to work. However I don’t understand why iostream exposes printf and scanf at all… the reference pages definitely do not document this.

1 Like

I was unable to replicate this on my machine with random test cases. Please share such a test case if you find one.

@meoow exactly!
I’m confused what to use from now on :confused:

Can it be because of using %lld in scanf? I am not sure but if that is an issue in first place, but I used %lld for long long int and not long long.