Search code examples
c++mingw-w64

Problems of cin and scanf() on MinGW-w64


My MinGW-w64's version is: x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z

My System's version is: Windows 10 2004

When I tried to use MinGW-w64's g++ to compile and run this source file, I ran into troubles. this file's name is "temp.cpp"

#include <iostream>
using namespace std;
int main()
{
    char player1[8] = {0}, player2[8] = {0};
    cin >> player1 >> player2;
    cout << player1 << ' ' << player2;
    return 0;
}

I built and ran this file in PowerShell by entered this line of codes.

g++ -g .\temp.cpp -o .\temp.exe; .\temp.exe

Then I typed in the inputs.

Rock Scissors

After I pressed the enter key. I got this.

 Scissors

The first word didn't print out.

Then I use VS Code to debug the source file. I found after I entered the input, the data in player1[0] didn't get replaced by 'R'. Instead, it is still 0.

Then I copy the entire mingw64 folder to another computer to try again, same thing happened again.

Then I replaced cin by using scanf().

#include <iostream>
using namespace std;
int main()
{
    char player1[8] = {0}, player2[8] = {0};
    scanf("%s %s", player1, player2);
    printf("%s %s", player1, player2);
    return 0;
}

Same thing happened again.

Then I download the older version of MinGW-w64: x86_64-5.4.0-release-posix-seh-rt_v5-rev0.7z

By using the older version, It can print out properly now.

Why?


Solution

  • Oh... Your array is one-character too short for Scissors. You require 9-characters 8 + 1 for the nul-terminating character. So what happens on your stack is you have Player1 followed by Player2 (but since the stack grows down, Player1 is in the memory above Player2), e.g.

        |        Player2                |        Player1                |
        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
        | S | c | i | s | s | o | r | s | \0| o | c | k | \0|   |   |   |
        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    

    So when you are take input for "Scissors" and the nul-terminating character is written for end-of-string, you overwrite the first character for Player1 with '\0' causing it to appear to be an empty-string.

    Lesson Learned -- Don't Skimp on Buffer Size! (or better yet, use std::string)

    Declare:

    char player1[32] = {0}, player2[32] = {0};
    

    or

    #include <string>
    ...
    std::string player1 {}, player2 {};
    

    and try again.