パソコン活用研究シリコンバレー(C、C++、の活用研究)

値の入力
〜プログラミングコンテストに向けて〜 (準備中)

-----------------------------------------------------------------------------
いろいろなプログラミングコンテストでの、入力値の与えられ方は様々ですよね。
肝心のアルゴリズムを考える前に、まずどうやって値を入力するかに悩んでしまっては
お話になりませんので、まずは値の入力について
-----------------------------------------------------------------------------

入力値が改行区切りで入力される場合

例題1 正の整数の掛け算

入力
文字列は標準入力から以下のフォーマットで与えられ、入力値最終行の末尾に改行が1つ入る。

a
b

出力
aとbを掛け算した数値を出力
最後は改行(余計な文字、空行を含めないこと)

条件
0 ≦ a ≦ 100
0 ≦ b ≦ 100

入力例1
5
7

出力例
35

入力例2
0
100

出力例2
0


プログラム例1
文字列は標準入力から渡されるので、オーソドックスにscanfで値を読み込む。
一つの値が渡されるたびに改行で区切られるので、scanfを2回使って読み込む。

/* mul1.c */
#include <stdio.h>
int main(void){
int a,b,x;
scanf("%d", &a);
scanf("%d", &b);
x=a*b;
printf("%d\n", x);
return 0;
}

実行例
c:\bcc55\shortp>mul1
3
7
21
c:\bcc55\shortp>


※scanfについては
画面に出力(printf)・キーボードから入力(scanf)・変数
標準入力 scanfの使用上注意点


プログラム例2
出力のprintf文のなかで、掛け算の計算をしてしまう書き方。プログラム1よりソースコードは短い。
(コンパイルされた実行ファイルは同じサイズ。Borland C++でコンパイル)

mul2.c

#include <stdio.h>
int main(void){
int a,b;
scanf("%d", &a);
scanf("%d", &b);
printf("%d", a*b);
return 0;
}

c:\bcc55\Bin>mul2
6
9
54
c:\bcc55\Bin>


プログラム例3
ファイルからの値の読み込みにも対応できる汎用パターンでの記述。
fgets, sscanfを使う。fgetsとsscanfについては後述

mul3.c

#include <stdio.h>
int main(void){
int a,b;
char str[1000];
fgets(str, sizeof(str), stdin);
sscanf(str, "%d", &a);
fgets(str, sizeof(str), stdin);
sscanf(str, "%d", &b);
printf("%d", a*b);
return 0;
}

c:\bcc55\Bin>mul3
11
5
55


fgetsの使い方
char * fgets( char *row , int len , FILE *fp );
■戻り値:
ファイルポインタfpから1行、またはlenバイト読み込んでその先頭アドレスを返す。
全行を読み込んだ場合、又はエラー時にNULL(\0)を返す。
■説明
ファイルポインタfpから1行、またはlenバイトをrowに読み込みその先頭アドレスを返
す。
fgetsで読み込むファイルはテキストファイルを対象とする。(バイナリファイルではそも
そも改行(\n)と言う概念がない)
1行とは改行コード(\n)または読み込みバイトがファイルサイズに達するまでを指すが、
左記の状態にならなくともlenに達した時点で1回の読み込み(関数実行)は終了し、残りは
次回の読み込みで取得する。
1行読み込んだ領域の改行コードは削除されず、改行コードがあればそのまま読み込ま
れ、更に末尾にNULL(\0)が自動付与された状態になっている。従って、実際に読み込まれ
るのは自動付与されたNULLを除く(len-1)バイトになる。
通常、lenには「読み込み対象ファイルとしての仕様上の1行の最大バイト数」を少し超え
る値を指定するのが一般的である。
本関数fgetsは読み込みバイト数がファイルサイズに達するとNULLを返すが、エラー時も
NULLを返すので区別が付かない。このことから一般的にはエラー判定は行わずNULLの返却
を以って全行読み込んだものとしている。これは、もしファイルに障害があって読み込み
不能であった場合、ファイルオープン時にエラー検出可能であるからだと言われている

#include <stdio.h>
main() {
FILE * fp;
char str[100];
int i;
fp = fopen( "sample0.txt" , "r" );
if( fp == NULL ) {
printf( "ファイルオープンエラー\n" );
return -1;
}
while( fgets( str , sizeof( str ) , fp ) != NULL ) {
printf( "%s" , str ); /* strの末尾は\n\0 */
/* 1バイトずつ表示 */
/* for( i=0;i<strlen( row );i++ ) { */
/*printf( "row[%d]=0x%02x\n" , i , row[i] );*/
/*} */
}
fclose( fp );
return 0;
}

c:\bcc55\Bin>type sample0.txt
23
89

c:\bcc55\Bin>fgets1
23
89



これまでのプログラム例1〜2は以下の「2 空白を区切りとした入力値」の場合でも問題なく
動きます。プログラム例2の実行例

c:\bcc55\Bin>mul2
7 9
63

プログラム例3(mul3.c)は空白を区切りとした入力値の場合は正しく動作しません。
fgetsが1行を読み込む仕様のためです。
以下のテストでは、6は無視され、4×3 の結果12が出力されています。

c:\bcc55\shortp>mul3
4 6
3
12






2 空白を区切りとした入力値

入力
文字列は標準入力から以下のフォーマット(空白区切り)で与えられ、入力値最終行の末尾に改行が1つ入る。

a b

出力
aとbを掛け算した数値を出力
最後は改行(余計な文字、空行を含めないこと)

条件
0 ≦ a ≦ 100
0 ≦ b ≦ 100

入力例1
5 7

出力例
35

入力例2
0 100

出力例2
0


プログラム例4

空白区切りの入力値の読み込みについては標準入力 scanfの使用上注意点に説明をがありますので
ご参照下さい。

#include <stdio.h>
int main(void){
int a,b;
scanf("%d %d", &a,&b);
printf("%d", a*b);
return 0;
}


c:\bcc55\Bin>mul4
11 7
77
c:\bcc55\Bin>

プログラム例4は、以下のように1行づつ改行された入力でもちゃんと動作します。
c:\bcc55\Bin>mul4
10
2
20


fgetsを使用する場合は以下のようにします。


#include <stdio.h>
int main(void){
char str[1000];
int a,b;
fgets(str, sizeof(str), stdin);
sscanf(str,"%d %d", &a, &b);
printf("%d\n", a*b);
return 0;
}

TopPage