ハトネコエ Web がくしゅうちょう

プログラミングやサーバー・Web制作、チームマネジメントなど得た技術のまとめ

誰だよ! char に数値が入れられるとか言ったの!

信じてた……信じてたのに……!!

整数型 char の値域は -128~127 で、
小さな値であれば char型 や unsigned char型(0~255) を使えるから、
本によっては、メモリ節約のために使うことを考えよう、と推奨していることもあります。

環境にもよりますが、たいてい、
char : 1 Byte
short int : 2 Byte
int : 4 Byte
float : 4 Byte
double : 8 Byte
ですからね。
単純に考えればint型の4分の1です。

しかししかし、だめでした!
正常に動かないことがあるようです。

以下が書いたコードの全文です。

#include <iostream>
using namespace std ;

// (x, y) にいる人が 中心 (xc, yc) にある、半径 r_2 の台風の暴風域にいるか判定
// 内側の半径 r_1 は台風の目とする。
bool isThere(char xc, char yc, char r_1, char r_2, char x, char y){
  int term = (x - xc) * (x - xc) + (y -yc) * (y-yc) ;
  if( (r_1) * (r_1) <= term && term <= (r_2) * (r_2) ){
    return true ;
  }
  return false ;
}


int main(){
  char r_1, r_2 ;  // 内側の半径、外側の半径
  char n ; // 人数
    // 上記の値は 1~100 で与えられる
  char xc, yc ;  // 台風の中心座標
  char x[100], y[100] ; // 人物のいる座標
    // 上記の値は -100~100 で与えられる 

  cin >> xc >> yc >> r_1 >> r_2 ;
  cin >> n ;
 
  for(char i=0; i<n; ++i){
    cout << "test-i_" << i << "\t test-n_" << n << endl ;
    cin >> x[i] >> y[i] ;
  }

  for(char i=0; i<n; ++i){
    if( isThere(xc, yc, r_1, r_2, x[i], y[i]) ){
      cout << "yes" << endl ;
    }else{
      cout << "no" << endl ;
    }
  }
}

しかしこれを実行すると、以下のようになります。

実行結果1

0 0 1 2
3
test-i_  test-n_3
0 0
test-i_  test-n_3
1 2
test-i_  test-n_3
3 4
test-i_  test-n_3
1 1
test-i_  test-n_3
2 2
test-i_  test-n_3

ループが終わりません。
終わらない、素敵なループです。

i が表示されないことを不審に思い、for文のところを

  for(int i=0; i<n; ++i){

と直してみても……

実行結果2(for文中の i を int に)

0 0 1 2
3
test-i_0         test-n_3
0 0
test-i_1         test-n_3
1 2
test-i_2         test-n_3
3 4
test-i_3         test-n_3
1 1
test-i_4         test-n_3
2 2
test-i_5         test-n_3

やはりダメ。

実のところ、はじめの n の宣言を
short int n ;
とするだけで、このfor文は正しく動くようになります。

実行結果3( n の宣言を short int に)

0 0 1 2
3
test-i_  test-n_3
0 0
test-i_  test-n_3
1 1
test-i_  test-n_3
2 2
no
no
no

まあ、i の値が表示されないので、やはりfor文の i も short int で宣言するべきですが……。
それに、出力も間違っています。

では、もうあきらめてプログラム中の char はすべて short int に直してしまいましょう。

実行結果4( char ではなく全て short int に)

0 0 1 2
3
test-i_0         test-n_3
0 0
test-i_1         test-n_3
1 1
test-i_2         test-n_3
2 2
no
yes
no

正しく実行されました。

このように、char で宣言しても、コンソールアウトされなかったり
for文が正しく回らなかったり、正しい計算がされずあせることになります。

これはC++だけで起こることなのかなんなのかわかりませんが、
小さな値でも、せいぜい short int を使うくらいに留めた方がいいようですね。
誰だ char型に数値を代入できると言ったやつは!!

追記:コメントいただきました!

char型にcinで入力する場合、数値ではなく文字として扱われるのが問題ではないでしょうか。
たとえば 3 と入力すると整数値3ではなく文字'3'となるので整数値としては51です。
char型は8bit整数型として使えますよ。

なるほど!
たしかに char型 は通常文字が代入されるものですから、そのような処理になっていると思われます。

というわけで、以下のようにプログラムを書き換えました。

#include <iostream>
#include <stdio.h> // scanf を実行させるために必要
using namespace std ;

// (x, y) にいる人が 中心 (xc, yc) にある、半径 r_2 の台風の暴風域にいるか判定
// 内側の半径 r_1 は台風の目とする。
bool isThere(char xc, char yc, char r_1, char r_2, char x, char y){
  int term = (int)(x - xc) * (x - xc) + (int)(y -yc) * (y-yc) ;
  cout << term << ", " << (int)(r_1) * (r_1) << endl ; // debug
  if( (int)(r_1) * (r_1) <= term && term <= (int)(r_2) * (r_2) ){
    return true ;
  }
  return false ;
}


int main(){
  char r_1, r_2 ;  // 内側の半径、外側の半径
  char n ; // 人数
    // 上記の値は 1~100 で与えられる
  char xc, yc ;  // 台風の中心座標
  char x[100], y[100] ; // 人物のいる座標
    // 上記の値は -100~100 で与えられる 

  //  cin >> xc >> yc >> r_1 >> r_2 ;
  //  cin >> n ;
  scanf("%d %d %d %d", &xc, &yc, &r_1, &r_2) ;
  scanf("%d", &n) ;
  printf("r_1 = %d \n", r_1) ; // debug
 
  for(char i=0; i<n; ++i){
    cout << "test-i_" << i << "\t test-n_" << n << endl ;
    //    cin >> x[i] >> y[i] ;
    scanf("%d %d", &x[i], &y[i]) ;
  }

  for(char i=0; i<n; ++i){
    if( isThere(xc, yc, r_1, r_2, x[i], y[i]) ){
      cout << "yes" << endl ;
    }else{
      cout << "no" << endl ;
    }
  }
}

ところが残念なことに、
実行結果 a1

0 0 1 2
3
r_1 = 0
test-i_  test-n_
0 0
test-i_  test-n_
1 1
test-i_  test-n_
2 2
0, 0
yes
2, 0
no
8, 0
no

と、 r_1 の値が読み込まれず正しい実行結果となりません。
scanf("%d%d", &xc, &yc) ;
scanf("%d%d", &r_1, &r_2) ;
と、入力部分を直してみても同じ結果です。

うーん、なぜなんだ・・・。
今のところの結論としては、C++の手法で書けなくなり複雑になりますし、
インプットを求める場合は char を使わないのが無難ですね。