読者です 読者をやめる 読者になる 読者になる

プロコンと標準入出力

c++

プロコンをかじってみたら,標準入出力で躓いた...ということで,使い方を整理しておく.

scanf

  • 空白文字または改行文字を区切りとして,フォーマットに従って変換して変数に取り込む.2つ以上フォーマット指定子を指定すれば一度にその分だけ読み進む.注意として,最後の空白や改行自体は変換後にバッファに残っている.よって,連続して読み込む場合に前回の改行や空白文字が残ることになるので,2回目以降使う場合はfflush(stdin)する.
  • 整数はd, 浮動小数点数はlf, 文字はc, 文字列はsで受け取る.但し,sは空白は含まないので注意.
  • 戻り値は,成功のときは変換した変数の数,ミスの場合はEOF.
// 0 * 入力で終了.
#include <stdio.h>
int main()
{
  int a, b;
  scanf("%d %d", &a, &b);
  while (a != 0) {
    printf("a:%d, b:%d\n", a, b);
    fflush(stdin);
    scanf("%d %d", &a, &b);
  }
}

fgets/sscanf

  • バッファサイズが指定できないことや,フォーマットを無視した入力の取扱が面倒なので,普通はscanfは使わずにfgetとsscanfを組合せて使う.これも合わせて覚えておく.
  • sscanfの戻り値は,フォーマットに従って入力された変数の数.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
{
    FILE    *fp;
    char    buf[256]; // バッファサイズを指定する
    double  d1, d2;

    if( (fp = fopen( "hoge.dat", "r" )) == NULL ) {
        printf( "ERROR: file can't be opened." );
        exit(1);
    }
    while( fgets( buf, sizeof(buf), fp ) ) {
        if( strncmp(buf,"//",2) == 0 || strcmp(buf,"\n") == 0 ) // skip comment line
            continue;
        if( sscanf( buf, "%lf %lf", &d1, &d2 ) != 2 ) {
            printf( "WARNING: format does not match.\n" );
            break;
        }
        printf( "d1=%.1f, d2=%.1f\n", d1, d2);
    }
    fclose( fp );
}

cin

  • 空白区切りで文字列をパースしていく,改行文字は取り込まれないなどscanfとほぼおなじ動きをする.
  • 関数じゃなくて(オーバーロードされた)演算子
#include <iostream>
int main() {
  int a, b;
  cin >> a >> b; // "1 2" のようなラインを読み取る書き方
}

n個の数列を入力する例

// n
// 1 2 3 4 5
int n;
cin >> n;
vector<int> v(n); // (当然)コンストラクタは変数でも良い
for(int i = 0; i < v.size(); ++i) cin >> v[i];

文字列として連続して受け取る

  • cin >> がEOFを読み込んだ時にfalseとなることを利用する.
string str;
while (cin >> str) { // EOF(Ctrl-D)入力時に抜ける
 ...
}
//同じことの別の書き方
while (1) {
  cin >> str;
  if (cin.eof()) break;
  ...
}