見出し画像

プログラム学習記録【17日目】/構造体

3.04.構造体

pair,tupleの他にも複数のデータを纏める方法がある。
構造体を利用するが、STLのpairやtupleも構造体を用いて実装されている。
以下のようにして実装する。

struct 構造体名
{1 メンバ変数名12 メンバ変数名2
   …
};  // セミコロンを忘れない

また、

auto 変数名 = 構造体名();

として構造体の値を生成することもできる。
構造体が持つ変数をメンバ変数と呼ぶ。
メンバ変数は通常の変数と同じ様に扱うことができる。

構造体には、オブジェクトに関連した処理を行う関数を定義することができる。
これをメンバ関数と呼ぶ。
メンバ関数は以下のように定義する。

struct 構造体名
{
   返り値の型 メンバ関数(引数の型1 引数名1, 引数の型2 引数名2, …)
    {
   // 関数の内容
   // メンバ変数に直接アクセスすることができる
    }
};  // セミコロンを忘れない

また、構造体が呼び出しされる際に独自の初期化処理などを行いたい場合、コンストラクタと呼ばれる処理を用いることができる。
コンストラクタは以下のように定義する。

struct 構造体
{ 
   // コンストラクタ
   構造体名()
   {
       // コンストラクタの内容
   }
}; // セミコロンを忘れない

コンストラクタは与える引数の型や引数の個数によって複数定義することができ、自動的に呼び分けることができる。

このほかにも、構造体には
・デストラクタ
・メンバアクセス
・継承
・静的メンバ変数/関数
・friend宣言
・union
・ビットフィールド
などが存在する。

EX24.時計の実装

構造体の練習として、24時間表記の時計を表す構造体を実装する。
入力された時刻と、与えられた秒数だけ時刻を変更したあとの時刻を出力する。
今回は雛形があるのでそれを見ていく。

   #include <bits/stdc++.h>
   using namespace std;
    
   // 以下に、24時間表記の時計構造体 Clock を定義する
    
   // Clock構造体のメンバ変数を書く
   //   int hour    時間を表す (0~23の値をとる)
   //   int minute  分を表す   (0~59の値をとる)
   //   int second  秒を表す   (0~59の値をとる)
    
   // メンバ関数 set の定義を書く
   //   関数名: set
   //   引数: int h, int m, int s (それぞれ時、分、秒を表す)
   //   返り値: なし
   //   関数の説明:
   //     時・分・秒を表す3つの引数を受け取り、
   //     それぞれ、メンバ変数 hour, minute, second に代入する
    
   // メンバ関数 to_str の定義を書く
   //   関数名: to_str
   //   引数: なし
   //   返り値: string型
   //   関数の仕様:
   //     メンバ変数が表す時刻の文字列を返す
   //     時刻の文字列は次のフォーマット
   //     "HH:MM:SS"
   //     HH、MM、SSはそれぞれ時間、分、秒を2桁で表した文字列
    
   // メンバ関数 shift の定義を書く
   //   関数名: shift
   //   引数: int diff_second
   //   返り値: なし
   //   関数の仕様:
   //     diff_second 秒だけメンバ変数が表す時刻を変更する(ただし、日付やうるう秒は考えない)
   //     diff_second の値が負の場合、時刻を戻す
   //     diff_second の値が正の場合、時刻を進める
   //     diff_second の値は -86400 ~ 86400 の範囲を取とりうる
    
    
   // -------------------
   // ここから先は変更しない
   // -------------------
    
   int main() {
     // 入力を受け取る
     int hour, minute, second;
     cin >> hour >> minute >> second;
     int diff_second;
     cin >> diff_second;
    
     // Clock構造体のオブジェクトを宣言
     Clock clock;
    
     // set関数を呼び出して時刻を設定する
     clock.set(hour, minute, second);
    
     // 時刻を出力
     cout << clock.to_str() << endl;
    
     // 時計を進める(戻す)
     clock.shift(diff_second);
    
     // 変更後の時刻を出力
     cout << clock.to_str() << endl;
   }

やることは、clock構造体のメンバ変数を書き、定義をそれぞれ決める。
まずは構造体のメンバ変数の設定。

struct Clock
{
 int hour;   //時間を表す (0~23の値をとる)
 int minute; //分を表す   (0~59の値をとる)
 int second; //秒を表す   (0~59の値をとる)

メンバ関数setの定義は、受け取った入力hour,minute,secondをh,m,sとして再設定する項目。

 void set(int h, int m, int s)
 {
   hour = h;
   minute = m;
   second = s;
 }

メンバ関数to_strでは、それぞれの変数を正規の時間の範囲に収め、2桁の整数として表示できる様にし、それをstring型型として返り値に設定する項目。

void to_str() //   関数名: to_str 引数: なし
 {
   string ret; //   返り値: string型
   if (!(0 <= hour && hour <= 23 && 0 <= minute && minute <= 59 && 0 <= second && second <= 59)
   {
     return "error";
   }
   if(hour < 10) ret += "0";
   ret += to_string(hour);
   ret+= ":";
   if(minute < 10) ret += "0";
   ret += to_string(minute);
   ret+= ":";
   if(second < 10) ret += "0";
   ret += to_string(second);
   return ret;
 }

最後に、メンバ関数のshiftについて考える。
この関数では、秒から分、分から時間、それぞれの逆について、繰り上がり、繰り下がりを考慮する。
秒、分は60進数である点に注意。
また、時間については24の進数である点に注意する。
今回は日付に関して考慮する必要はないので、単純に0~24の範囲に収まるように24を増減させることでこれに対処する。

void shift(int diff_second)
 {
   int diff_hour = diff_second / 3600;
   diff_second %= 3600;
   int diff_minute = diff_second / 60;
   diff_second %= 60;
   second += diff_second;
   if (second >= 60) // 60秒以上なら分に繰り上げ
   {
     minute += 1;
     second -= 60;
   }
   if (second < 60) // 60秒以下なら分から繰り下げ
   {
     minute -= 1;
     second += 60;
   }
   minute += diff_minute;
   if (minute >= 60) // 60秒以上なら分に繰り上げ
   {
     hour += 1;
     minute -= 60;
   }
   if (minute < 60) // 60秒以下なら分から繰り下げ
   {
     hour -= 1;
     minute += 60;
   }
   hour += diff_hour; // 時間は24進数だが今回は日付に関して考慮しないので、0~24の範囲に時間が収まるようにすれば良い。
   // 時間が0~24の範囲になるように、24を増減させることで対処していく。
   if (hour >= 24)
   {
     hour -= 24;
   }
   else if (hour < 0)
   {
     hour += 24;
   }
 }

全文は以下の通り。

#include <bits/stdc++.h>
using namespace std;
// 以下に、24時間表記の時計構造体 Clock を定義する
// Clock構造体のメンバ変数を書く
struct Clock
{
 int hour;   //時間を表す (0~23の値をとる)
 int minute; //分を表す   (0~59の値をとる)
 int second; //秒を表す   (0~59の値をとる)
 // メンバ関数 set の定義を書く
 void set(int h, int m, int s)
 {
   hour = h;
   minute = m;
   second = s;
 }
 // メンバ関数 to_str の定義を書く
 void to_str() //   関数名: to_str 引数: なし
 {
   string ret; //   返り値: string型
   if (!(0 <= hour && hour <= 23 && 0 <= minute && minute <= 59 && 0 <= second && second <= 59)
   {
     return "error";
   }
   if(hour < 10) ret += "0";
   ret += to_string(hour);
   ret+= ":";
   if(minute < 10) ret += "0";
   ret += to_string(minute);
   ret+= ":";
   if(second < 10) ret += "0";
   ret += to_string(second);
   return ret;
 }
 // メンバ関数 shift の定義を書く
 void shift(int diff_second)
 {
   int diff_hour = diff_second / 3600;
   diff_second %= 3600;
   int diff_minute = diff_second / 60;
   diff_second %= 60;
   second += diff_second;
   if (second >= 60) // 60秒以上なら分に繰り上げ
   {
     minute += 1;
     second -= 60;
   }
   if (second < 60) // 60秒以下なら分から繰り下げ
   {
     minute -= 1;
     second += 60;
   }
   minute += diff_minute;
   if (minute >= 60) // 60秒以上なら分に繰り上げ
   {
     hour += 1;
     minute -= 60;
   }
   if (minute < 60) // 60秒以下なら分から繰り下げ
   {
     hour -= 1;
     minute += 60;
   }
   hour += diff_hour; // 時間は24進数だが今回は日付に関して考慮しないので、0~24の範囲に時間が収まるようにすれば良い。
   // 時間が0~24の範囲になるように、24を増減させることで対処していく。
   if (hour >= 24)
   {
     hour -= 24;
   }
   else if (hour < 0)
   {
     hour += 24;
   }
 }
};
// -------------------
// ここから先は変更しない
// -------------------
int main()
{
 // 入力を受け取る
 int hour, minute, second;
 cin >> hour >> minute >> second;
 int diff_second;
 cin >> diff_second;
 // Clock構造体のオブジェクトを宣言
 Clock clock;
 // set関数を呼び出して時刻を設定する
 clock.set(hour, minute, second);
 // 時刻を出力
 cout << clock.to_str() << endl;
 // 時計を進める(戻す)
 clock.shift(diff_second);
 // 変更後の時刻を出力
 cout << clock.to_str() << endl;
}

これを提出。

画像1

気がつけば12月が始まってしまっていた。
年々、月日を短く思うようになっている。
一日一日を後悔が残ることがないよう、誠実に生きていきたいものだ。

この記事が気に入ったらサポートをしてみませんか?