カテゴリー
C

独習C#第3版、P452 マルチキャストイベント

// マルチキャストイベントの例
 
using System;

// イベントのためのデリゲート宣言 
delegate void MyEventHandler();

// イベントの送信側のクラス
class MyEvent {
  public event MyEventHandler SomeEvent;

  //  イベント送信を実装したメソッド
  public void Fire() {
    if(SomeEvent != null)
      SomeEvent();
  }
}

class X {
  public void Xhandler() {
    Console.WriteLine("Event received by X object");
  }
}

class Y {
  public void Yhandler() {
    Console.WriteLine("Event received by Y object");
  }
}

class EventDemo {
  static void Handler() {
    Console.WriteLine("Event received by EventDemo");
  }

  static void Main() {  
    MyEvent evt = new MyEvent();
    X xOb = new X();
    Y yOb = new Y();

    // ハンドラをイベントリストに追加する
    evt.SomeEvent += Handler;
    evt.SomeEvent += xOb.Xhandler; //←マルチキャストのチェーンを作成する
    evt.SomeEvent += yOb.Yhandler;

    // イベントを発生させる
    evt.Fire();
    Console.WriteLine();

    // ハンドラを削除する
    evt.SomeEvent -= xOb.Xhandler;
    Console.WriteLine("After removing xOb.Xhandler");
    evt.Fire();
  }
}

 イベントは、マルチキャストにすることが出来ます。したがって、1つのイベント通知に対して複数のオブジェクトが応答することが出来る。この例には、クラスX,Yが追加されてますが、これらのクラス内で定義されるイベントハンドラーも、MyEventHandlerのデリゲート宣言文と同じ仮引数リストと戻り値を持っています。そのため、これらのハンドラーもイベントチェインに追加できます。と、解説されてます。

カテゴリー
C

独習C#第3版、P449 イベント

using System;

namespace Chapter01All
{
    // とても簡単なイベントの例
    // イベント用のデリゲートの宣言
    delegate void MyEventHandler(); //←イベントで使うデリゲートを宣言する

    // イベントの送信側のクラス
    class MyEvent
    {
        public event MyEventHandler SomeEvent; //←イベントを宣言する

        // イベント送信を実装したメソッド
        public void Fire()
        {
            if (SomeEvent != null)
                SomeEvent(); //←イベントを送信する
        }
    }
    class OtherEvent
    {
        public event MyEventHandler anOtherEvent;
        public void Water()
        {
            if (anOtherEvent != null)
                anOtherEvent();
        }
    }

    class EventDemo
    {
        static void Handler()
        {
            Console.WriteLine("Event fire occurred");
        }
        static void OtherHandler()
        {
            Console.WriteLine("Event water occurred");
        }


        static void Main()
        {
            MyEvent evt = new MyEvent(); //←イベントを送信する側のインスタンスを作成する
            // ハンドラをイベントリストに追加する
            evt.SomeEvent += Handler; //←イベントのチェーンにハンドラを追加する
            evt.SomeEvent += OtherHandler;
            // イベントを人為的に発生させる
            evt.Fire(); //←イベントを発生させる

            OtherEvent oevt = new OtherEvent();
            oevt.anOtherEvent += OtherHandler;
            oevt.Water();
        }
    }
}

 何回か見てはいましたが、どうもピンときません。この辺がC#を理解する上での肝かもしれません。例題と同じようにイベントを一個追加して見ました。上の例では、delegateが一個しかないので、同じように動作する場合は、問題なかったのですが、動作が違うとダメだったので、もう一つのdelegateを定義したのが、下です。

using System;

namespace Chapter01All
{
    // とても簡単なイベントの例
    // イベント用のデリゲートの宣言
    delegate void MyEventHandler(); //←イベントで使うデリゲートを宣言する
    delegate void OtherMyEventHandler(String s);

    // イベントの送信側のクラス
    class MyEvent
    {
        public event MyEventHandler SomeEvent; //←イベントを宣言する

        // イベント送信を実装したメソッド
        public void Fire()
        {
            if (SomeEvent != null)
                SomeEvent(); //←イベントを送信する
        }
    }
    class OtherEvent
    {
        public event OtherMyEventHandler anOtherEvent;
        public void Water(String str)
        {
            if (anOtherEvent != null)
                anOtherEvent(str);
        }
    }

    class EventDemo
    {
        static void Handler()
        {
            Console.WriteLine("Event fire occurred");
        }
        static void OtherHandler(String s)
        {
            Console.WriteLine(s);
        }


        static void Main()
        {
            MyEvent evt = new MyEvent(); //←イベントを送信する側のインスタンスを作成する
            // ハンドラをイベントリストに追加する
            evt.SomeEvent += Handler; //←イベントのチェーンにハンドラを追加する
            // イベントを人為的に発生させる
            evt.Fire(); //←イベントを発生させる

            OtherEvent oevt = new OtherEvent();
            oevt.anOtherEvent += OtherHandler;
            oevt.Water("Water Event Occurred");
        }
    }
}

イベントに引数を持たせる場合もあるでしょうから、delegateを別に作って、試行錯誤しました。

カテゴリー
C

独習C#第3版、P448匿名メソッドは値を返せる

using System;

namespace Chapter01All
{
    class TokumeiMethod
    {
        //デリゲートの宣言
        delegate int CountIt(int limit);
        delegate int CountThat(int limit);
        delegate int CountThis(int limit);
        static void Main()
        {
            //単なるstatic methodの起動
            Console.WriteLine(Count(5));

            //delegateを使ったCountメソッドの起動
            CountIt Cnt = Count;
            Console.WriteLine(Cnt(10));

            //もう一度delegateを使ってCountメソッドの起動
            CountThat count = Count;
            Console.WriteLine(count(15));

            //匿名メソッドを使うと
            CountThis cnt = delegate (int l)
            {
                int wa = 0;
                for (int i = 0; i <= l; i++)
                {
                    Console.Write(i);
                    if (i != l)
                        Console.Write("+");
                    wa += i;
                }
                Console.Write(" = ");
                return wa;
            };
            Console.WriteLine(cnt(20));

        }
        static int Count(int Limit)
        {
            int w = 0;
            for (int i = 0; i <= Limit; i++)
            {
                Console.Write(i);
                if (i != Limit)
                    Console.Write("+");
                w += i;
            }
            Console.Write(" = ");
            return w;
        }
    }
}
カテゴリー
C

独習C#第3版、デリゲート 匿名メソッド

using System;

namespace Chapter01All
{
    class TokumeiMethod
    {
        delegate void CountIt();
        static void Main()
        {
            Count(5);
        }
        static void Count(int Limit)
        {
            for (int i = 0; i < Limit; i++)
                Console.Write(i + " ");
            Console.WriteLine();
        }
    }
}
using System;

namespace Chapter01All
{
    class TokumeiMethod
    {
        //デリゲートの宣言
    delegate void CountIt(int limit);
        static void Main()
        {
            //delegateを使ったCountメソッドの起動
            CountIt Cnt = Count;
            Cnt(10);

            //単なるstatic methodの起動
            Count(5);
        }
        static void Count(int Limit)
        {
            for (int i = 0; i < Limit; i++)
                Console.Write(i + " ");
            Console.WriteLine();
        }
    }
}
using System;

namespace Chapter01All
{
    class TokumeiMethod
    {
        //デリゲートの宣言
        delegate void CountIt(int limit);
        delegate void CountThat(int limit);
        delegate void CountThis(int limit);
        static void Main()
        {
            //単なるstatic methodの起動
            Count(5);

            //delegateを使ったCountメソッドの起動
            CountIt Cnt = Count;
            Cnt(10);

            //もう一度delegateを使ってCountメソッドの起動
            CountThat count = Count;
            count(15);

            //匿名メソッドを使うと
            CountThis cnt = delegate (int l)
            {
                for (int i = 0; i < l; i++)
                    Console.Write(i + " ");
                Console.WriteLine();
            };
            cnt(20);

        }
        static void Count(int Limit)
        {
            for (int i = 0; i < Limit; i++)
                Console.Write(i + " ");
            Console.WriteLine();
        }
    }
}

最終は匿名メソッドを使ったデリゲートまで行くのですが、単純にstaticな関数から、delegateを使って、最後は匿名メソッドを使った、delegateまで行ってみました。

カテゴリー
C

独習C#第3版P443、デリゲート(マルチキャスト)

using System;

namespace Chapter01All
{
    delegate void Calcs(ref int a, ref int b);
    class DeleGateSample
    {
        void Kasan(ref int a, ref int b)
        {
            a += b;
        }
        void Genzan(ref int a, ref int b)
        {
             a -= b;
        }
        void Kakezan(ref int a, ref int b)
        {
            a *= b;
        }
        void Warizan(ref int a, refint b)
        {
            a /= b;
        }

        static void Main()
        {
            Calcs = Op;
            Calcs kasan = Kasan;
            Calcs genzan = Genzan;
            Calcs kakezan = Kakezan;

            int a = 10; int b = 20;
            Op = kasan;
            Op += genzan;
            Op(ref a, ref b);       //a+b=>30, 30-b=>10
            Console.WriteLine(a);

            int c = 100; int d = 200;
            Op = genzan;
            Op += kakezan;
            Op(ref c, ref d);       //c-d=>-100, -100*200=>-20000
            Console.WriteLine(c);

        }
    }
}

デリゲートを使う理由。その1)デリゲートはイベントをサポートするから。その2)コンパイル時に実行するメソッドが決まっていなくても、実行時に特定できる。

カテゴリー
C

独習C#第3版P442、インスタンスメソッドにデリゲートを設定する

using System;

namespace Chapter01All
{
    delegate int Calcs(int a, int b);
    class DeleGateSample
    {
        int Kasan(int a, int b)
        {
            return a + b;
        }
        int Genzan(int a, int b)
        {
            return a - b;
        }
        int Kakezan(int a, int b)
        {
            return a * b;
        }
        int Warizan(int a, int b)
        {
            return a / b;
        }

        static void Main()
        {
            DeleGateSample sobj = new DeleGateSample();
            
            Calcs Op = sobj.Kasan;
            Console.WriteLine(Op(10, 20));

            Op = sobj.Genzan;
            Console.WriteLine(Op(10, 20));

            Op = sobj.Kakezan;
            Console.WriteLine(Op(10, 20));

            Op = sobj.Warizan;
            Console.WriteLine(Op(10, 20));

            Calcs[] Ope = new Calcs[] {sobj.Kasan, sobj.Genzan, sobj.Kakezan, sobj.Warizan };
            for(int i=0; i<Ope.Length; i++)
            {
                Console.WriteLine(Ope[i](10, 20));
            }

        }
    }
}

デリゲートを個別に書く場合と、配列に書く場合の比較。

カテゴリー
C

独習C#第3版P438、デリゲート

using System;

namespace Chapter01All
{
    delegate int Calcs(int a, int b);
    class DeleGateSample
    {
        static int Kasan(int a, int b)
        {
            return a + b;
        }
        static int Genzan(int a, int b)
        {
            return a - b;
        }
        static int Kakezan(int a, int b)
        {
            return a * b;
        }
        static int Warizan(int a, int b)
        {
            return a / b;
        }

        static void Main()
        {
            Calcs Op = new Calcs(Kasan);
            Console.WriteLine(Op(10, 20));

            Op = Genzan;
            Console.WriteLine(Op(10, 20));

            Op = Kakezan;
            Console.WriteLine(Op(10, 20));

            Op = Warizan;
            Console.WriteLine(Op(10, 20));
        }
    }
}

 例としてやって見ましたが、これだとあまりやる意味がないようにも思います。例えば、Opを配列にしてしまうと少しは意味があるようにも思えますが。

using System;

namespace Chapter01All
{
    delegate int Calcs(int a, int b);
    class DeleGateSample
    {
        static int Kasan(int a, int b)
        {
            return a + b;
        }
        static int Genzan(int a, int b)
        {
            return a - b;
        }
        static int Kakezan(int a, int b)
        {
            return a * b;
        }
        static int Warizan(int a, int b)
        {
            return a / b;
        }

        static void Main()
        {
            Calcs[] Ope = new Calcs[] {Kasan, Genzan, Kakezan, Warizan };
            for(int i=0; i<Ope.Length; i++)
            {
                Console.WriteLine(Ope[i](10, 20));
            }
        }
    }
}
カテゴリー
C

C言語による実用アルゴリズム入門、リスト処理の写経

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct person {
	char name[40];
	int age;
	struct person* next;
}Person;

void ls_addFirst(const char* nm, int ag);
void ls_add(Person* pos, const char* nm, int ag);
void ls_addLast(const char* nm, int ag);
void ls_removeFirst(void);
void ls_remove(Person* pos);
void ls_removeLast(void);
Person* ls_end(void);
Person* psn_malloc(const char* nm, int ag);
Person* ls_find(const char* ss);
void disp_all(void);

Person head;

int main(void) {
	Person* p;
	head.next = NULL;
	printf("----------ls_addFirst,ls_addLAst\n");
	ls_addFirst("山田次郎", 22);
	ls_addFirst("山田一郎", 11);
	ls_addLast("山田三郎", 33);
	ls_addLast("山田四郎", 44);
	disp_all();

	printf("----------ls_find,ls_add\n");
	p = ls_find("山田次郎");
	if (p != NULL) ls_add(p, "追加五郎", 55);
	disp_all();

	printf("-----------ls_remove,ls_removeFirst,ls_removeLast\n");
	p = ls_find("山田次郎");
	if (p != NULL) ls_remove(p);
	ls_removeFirst();
	ls_removeLast();
	disp_all();

	return 0;
}

void ls_addFirst(const char* nm, int ag) {
	ls_add(&head, nm, ag);
}

void ls_add(Person* pos, const char* nm, int ag) {
	Person* dt;
	if (pos == NULL) return;
	dt = psn_malloc(nm, ag);
	dt->next = pos->next;
	pos->next = dt;
}

void ls_addLast(const char* nm, int ag) {
	if (head.next == NULL) ls_addFirst(nm, ag);
	else
		ls_add(ls_end(), nm, ag);
}

void ls_removeFirst(void) {
	ls_remove(&head);
}

void ls_remove(Person* pos) {
	Person* tmp;
	if (pos == NULL) return;
	if (pos->next == NULL)return;
	tmp = pos->next;
	pos->next = pos->next->next;
	free(tmp);
}

void ls_removeLast(void) {
	Person* p;
	if (head.next == NULL) return;
	for (p = &head; p->next->next != NULL; p = p->next) 
		;
	free(p->next);
	p->next = NULL;
}

Person* ls_end(void) {
	Person* p;
	if (head.next == NULL) return NULL;
	for (p = head.next; p->next != NULL; p = p->next) 
		;
	return p;
}

Person* psn_malloc(const char* nm, int ag) {
	Person* p;
	if ((p = (Person*)malloc(sizeof(Person))) == NULL) {
		printf("メモリを確保できません。\n"); exit(1);
	}
	strcpy_s(p->name, nm);
	p->age = ag;
	p->next = NULL;
	return p;
}

Person* ls_find(const char* ss) {
	Person* p;
	for (p = head.next; p != NULL; p = p->next) {
		if (strcpy_s(p->name, ss) == 0) return p;
	}
	return NULL;
}

void disp_all() {
	Person* p;
	for (p = head.next; p != NULL; p = p->next)
		printf("%s: %d\n", p->name, p->age);
}

 ネタ本との実行画面が合わないので、(二番目のブロック、途中に追加するところ)どっか間違っていると思われます。また、ネタ本ではchar *nmのようになってますが、VS2019ではconstを付けないとコンパイル通りません。それ以外は、今のところC++と違いなく、コンパイル出来ているようです。もう一つ、strcpyがエラーになって、strcpy_sを使うようにとのエラーのように思えました。constはイメージ的には分かりますが、strcpy_sは、違いが何処にあるんでしょうか?

間違っていたところが分かりました。ls_findが違ってました。strcpy_sでなくて、strcmpでした。

カテゴリー
C C++

VS2019でC++とCの違いはどれ程あるんでしょうか?

ネタ本は、林晴比古さんの「C言語による実用アルゴリズム入門」です。

// ConsoleApplication2.cpp : このファイルには 'main' 関数が含まれています。プログラム実行の開始と終了がそこで行われます。
//

#include <iostream>

int gcd(int a, int b) {
    while (a != b) {
        if (a > b) a = a - b; else b = b - a;
    }
    return a;
}

int gcd2(int a, int b) {
    int w;
    while (b != 0) {
        w = a % b;
        a = b; b = w;
    }
    return a;
}

int main()
{
    int a = 128; int b = 72;
    printf("整数%d, 整数%d, の最大公約数=%d", a, b, gcd(a, b));
}

拡張子はcppになってますが、後はCのネタ本に出来るだけ近くしてます。

カテゴリー
C

独習C#第3版 P276 Setクラスを作成する

C#のこーどならシンタックスハイライターが効きますか?

/* 
   例7-1 
 
   char型データ用のSetクラス
*/ 
using System;  
  
class Set {     
  char[] members; // この配列がセットの値を保持する

  // 実質的に読み取り専用の、自動実装する Length プロパティ 
  public int Length { get; private set; }

  // ヌルのセット(配列の実体がないセット)を作る
  public Set() {  
    Length = 0; 
  }

  // 指定されたサイズの領域を持つ空のセットを作る
  public Set(int size) {     
    members = new char[size]; // セットのためにメモリを確保
    Length = 0; // 実質的な要素はない
  }     
   
  // セットから別のセットを作る
  public Set(Set s) {     
    members = new char[s.Length]; // セットのためにメモリ確保    
    for(int i=0; i < s.Length; i++) members[i] = s[i];
    Length = s.Length; // 実質的な要素の数 
  }     
 
  // 読み取り専用のインデクサ
  public char this[int idx]{  
    get {  
      if(idx >= 0 & idx < Length) return members[idx];
      else return (char)0; 
    }  
  }  
 
  /* 引数で指定されたデータがセットの中に
     存在するかチェックする
     あればそのインデックスを返し、なければ-1を返す */ 
  int find(char ch) {  
    int i; 
     
    for(i=0; i < Length; i++)
      if(members[i] == ch) return i; 
 
    return -1; 
  }

  // ユニークな要素をセットに追加する
  public static Set operator +(Set ob, char ch)
  {

    // もし、セットの中にchと同じものが既に存在していた場合は、
    // 元のセットのコピーを返す
    if (ob.find(ch) != -1)
    {

      // 元のセットのコピーを返す
      return new Set(ob);

    } else { // 新しい要素を含む新しいセットを返す

      // 元のセットよりも、要素1つ分だけ大きいセットを新規作成する
      Set newset = new Set(ob.Length + 1);

      // 新しいセットに要素をコピーする 
      for (int i = 0; i < ob.Length; i++)
        newset.members[i] = ob.members[i];

      // Length プロパティを設定する
      newset.Length = ob.Length + 1;

      // 新しいセットに新しい要素を追加する
      newset.members[newset.Length - 1] = ch;

      return newset; // 新しいセットを返す
    }
  } 
 
  // セットから要素を取り除く
  public static Set operator -(Set ob, char ch) {   
    Set newset = new Set();
    int i = ob.find(ch); // もし見つからなければ、変数iは-1になる
 
    // 残りの要素をコピーする
    for(int j=0; j < ob.Length; j++)
      if(j != i) newset = newset + ob.members[j]; 
 
    return newset; 
  }     
 
  // 和集合
  public static Set operator +(Set ob1, Set ob2) {
    Set newset = new Set(ob1); // 1番目のセットをコピーする
 
    // 2番目のセットの要素を追加する
    for(int i=0; i < ob2.Length; i++)
        newset = newset + ob2[i]; 
 
    return newset; // 更新されたセットを返す
  }  
 
  // 差集合
  public static Set operator -(Set ob1, Set ob2) {
    Set newset = new Set(ob1); // 1番目のセットをコピーする 
 
    // 2番目のセットの要素を1番目のセットから引く 
    for(int i=0; i < ob2.Length; i++)
        newset = newset - ob2[i]; 
 
    return newset; // 更新されたセットを返す
  }  
}     
  
// セットクラスの使用例
class SetDemo {     
  static void Main() {     
    // ヌルのセットを作成する
    Set s1 = new Set();    
    Set s2 = new Set(); 
    Set s3 = new Set(); 
  
    s1 = s1 + 'A'; 
    s1 = s1 + 'B'; 
    s1 = s1 + 'C'; 
 
    Console.Write("s1 after adding A B C: ");  
    for(int i=0; i<s1.Length; i++)
      Console.Write(s1[i] + " ");    
    Console.WriteLine(); 
 
    s1 = s1 - 'B'; 
    Console.Write("s1 after s1 = s1 - 'B': ");  
    for(int i=0; i<s1.Length; i++)
      Console.Write(s1[i] + " ");    
    Console.WriteLine(); 
 
    s1 = s1 - 'A'; 
    Console.Write("s1 after s1 = s1 - 'A': ");  
    for(int i=0; i<s1.Length; i++)
      Console.Write(s1[i] + " ");    
    Console.WriteLine(); 
 
    s1 = s1 - 'C'; 
    Console.Write("s1 after s1 = s1 - 'C': ");  
    for(int i=0; i<s1.Length; i++)   
      Console.Write(s1[i] + " ");    
    Console.WriteLine("\n"); 
 
    s1 = s1 + 'A'; 
    s1 = s1 + 'B'; 
    s1 = s1 + 'C'; 
    Console.Write("s1 after adding A B C: ");  
    for(int i=0; i<s1.Length; i++)   
      Console.Write(s1[i] + " ");    
    Console.WriteLine(); 
 
    s2 = s2 + 'A'; 
    s2 = s2 + 'X'; 
    s2 = s2 + 'W'; 
 
    Console.Write("s2 after adding A X W: ");  
    for(int i=0; i<s2.Length; i++)
      Console.Write(s2[i] + " ");    
    Console.WriteLine(); 
 
    s3 = s1 + s2; 
    Console.Write("s3 after s3 = s1 + s2: ");  
    for(int i=0; i<s3.Length; i++)
      Console.Write(s3[i] + " ");    
    Console.WriteLine(); 
 
    s3 = s3 - s1; 
    Console.Write("s3 after s3 - s1: ");  
    for(int i=0; i<s3.Length; i++)
      Console.Write(s3[i] + " ");    
    Console.WriteLine("\n"); 
 
    s2 = s2 - s2;  // s2のクリア
    s2 = s2 + 'C'; // 逆の順番にABCを加える
    s2 = s2 + 'B'; 
    s2 = s2 + 'A'; 
 
    Console.Write("s1 is now: ");  
    for(int i=0; i<s1.Length; i++)
      Console.Write(s1[i] + " ");    
    Console.WriteLine(); 
 
    Console.Write("s2 is now: ");  
    for(int i=0; i<s2.Length; i++)
      Console.Write(s2[i] + " ");    
    Console.WriteLine(); 
 
    Console.Write("s3 is now: ");  
    for(int i=0; i<s3.Length; i++)
      Console.Write(s3[i] + " ");    
    Console.WriteLine(); 
   }     
}
inserted by FC2 system