写経 『計算物理のためのC/C++言語入門』

// sample01.cc
#include <stdio.h>

main(void)
{
  printf("Computer in Physics\n");
}
gcc sample01.cc -o sample01
./sample01
// sample02.cc
#include <stdio.h>

main(void)
{
  int a, b, c;

  a=1;
  b=2;
  c=a+b;

  printf(" %d + %d = %d \n", a, b, c );
}
gcc sample02.cc -o sample02
./sample02
// sample03.cc
#include <stdio.h>
#include <math.h>

main(void)
{
  double a, b, c;
  double xp, xm;

  a =  1.0;
  b = -4.0;
  c =  2.0;

  xp = (-b + sqrt(b*b-4.0*a*c))/(2.0*a);
  xm = (-b - sqrt(b*b-4.0*a*c))/(2.0*a);

  printf("The solutions are %lf and %lf\n", xp, xm );
}
  • 数学関数ライブラリ をリンクすることを指定 -lm
  • %d, $lfなどについては「フォーマット指定子」参照
gcc sample03.cc -o sample03 -lm
./sample03

3. ループ、分岐

// sample04.cc
#include <stdio.h>

main(void)
{
  int n;  // 変数の宣言
  int sum = 0; // 変数の宣言と初期化
    
    // for ループ
  for( n=1 ; n<=10 ; n++ ){
      sum += n;  // 足し上げる
  }
    
  printf("The sum is %d\n", sum );
}
gcc sample04.cc -o sample04
./sample04
// sample05.cc
#include <stdio.h>

// 与えた x に対する y = sqrt(x) を計算する。
main(void)
{
  double x, y;
  double a, da;
    
  printf("Input a positive number =");
  scanf("%lf", &x );  // 正の実数をキーから読み込む。
    
  a = x;     // aの値をまずこうする
    
    // do while ループ
  do{
    da = 0.5*(a - x/a);      // a の減少分 da を計算する
    a -= da;                 // a を da だけ減らす
  }while( da > 0.000001 ); // 減少分がこの程度大きい間ループを続ける

  y = a; // これが答えの値
  if(y >3){
    printf("more than 3\n");
  }else{
    printf("equal or less than 3\n");
  }
  printf("The root of %lf is %lf.\n", x, y );
}
gcc sample05.cpp -o sample05
./sample05

4. 配列、データ型の自動変換

// sample06.cc
#include <stdio.h>

main(void)
{
  int score1, score2;
  double mean;
    
  printf("Input the score of No.1 = ");
  scanf("%d", &score1 );
  printf("Input the score of No.2 = ");
  scanf("%d", &score2 );
    
  mean = (double)( score1 + score2 )/2.0;
    
  printf("The mean score is %lf \n", mean );
}
#include <stdio.h>
#define N 10

main(void)
{
  int score[N];                        // 配列の宣言
  int n, sum;
  double mean;
    
  for( n=0 ; n<N ; n++ ){           // 配列の各要素に値を入力
    printf("Input the score of No.%d = ", n );
    scanf("%d", &score[n] );
  }

  sum = 0;
  for( n=0 ; n<N ; n++ ){           // 合計点の計算
    sum += score[n];
  }
  mean = (double)sum/N;                // 平均点の計算

  printf("The mean score is %lf\n", mean );
}
  • 5. 関数
// sample08.cc
#include <stdio.h>

main( void )
{
  double r, term=1.0, sum=0.0;
  
  printf("Input a number below 1.0 =");
  scanf("%lf", &r );   // 比例乗数 r の入力受け付け

  while( term > 0.0 ){ // 足し上げる項が0より大きい間繰り返す
    sum  += term;      // 項の足し上げ
    term *= r;         // 乗数をかけて次の項の値とする
  }
  
  printf("The total of this series is %lf\n", sum );
}
    • 関数の本体を後に書くならプロトタイプ宣言を予めする必要がある。同じファイルの上部に書く、というのがその一つのやり方。それを更に突き詰めると、別ファイルに書いておく、ということになる。以下では、関数のプロトタイプ宣言を上部で、本体を末尾で書いている
// sample10.cc
#include <stdio.h>

double CalcSeries( double );  // 関数CalcSeries() のprototype宣言
    
int main( void )
{
  double r, sum;

  printf("Input a number below 1.0 =");
  scanf("%lf", &r );            // 比例乗数 r の入力受け付け その1
  sum = CalcSeries(r);          // 関数CalcSeries() の実行 その1
  printf("The total of this series is %lf\n", sum );

  printf("Input a number below 1.0 =");
  scanf("%lf", &r );            // 比例乗数 r の入力受け付け その2
  sum = CalcSeries(r);          // 関数CalcSeries() の実行 その2
  printf("The total of this series is %lf\n", sum );

  return(0);
}



double CalcSeries( double r )  // 関数CalcSeries() の定義の開始
{
  double term=1.0, sum=0.0; // 局所変数の宣言と定義
  
  while( term > 0.0 ){   // 足し上げる項が0より大きい間繰り返す
    sum  += term;        // 項の足し上げ
    term *= r;           // 乗数をかけて次の項の値とする
  }

  return( sum );         // 合計の値を呼び出し元へ戻す
}                        // 関数の定義の終了
    • main()の特別な引数の渡し方
// sample11.cc
#include <stdio.h>

int main( int argc, char* argv[] )
{
  for( int n=0 ; n<argc ; n++ ){
    printf("%d %s\n", n, argv[n] );
  }

  return(0);
}
    • 「参照渡し」を使うと、与えた変数の値を変換した上でその結果を得ることができる。結果として、「複数の値」を関数の処理の結果として入手できる。これが「一つの変数しか返り値を取れない仕様になっているC++での、複数の値返却」のやり方の一つ
// sample12.cc
#include <stdio.h>

void swap( int& x, int& y )
{
  int tmp;
  tmp = x;
  x   = y;
  y   = tmp;
}

int main( void )
{
  int a=1, b=2;

  swap( a, b );

  printf("a=%d, b=%d\n", a, b );
}
    • 返り値変数として配列を使えば、いくつもの値を返すことができる
// sample12_2.cc
#include <stdio.h>

void Print1DArray( int [] );

int main( void )
{
  int a[10]={0,1,2,3,4,5,6,7,8,9};     // 配列の宣言と初期化

  Print1DArray( a );       // 配列を関数の引数として渡す

  return(0);
}

// 配列の要素を表示する関数
void Print1DArray( int x[] )
{
  int n;
  for( n=0 ; n<10 ; n++ ){
    printf("%d ", x[n] );
  }
}
    • 参照渡しと配列とを両方使うと、たくさんの値の受け渡しが可能になる
// sample13.cc
#include <stdio.h>

void Copy1DArray( int [] , int [] );
void Print1DArray( int [] );

int main(void)
{
     // 配列の宣言、一方は初期化する。
  int a[10], b[10]={0,1,2,3,4,5,6,7,8,9};

  Copy1DArray( a, b );     // 配列ごとのコピー
  Print1DArray( a );       // 配列ごとの表示

  return(0);
}

// 配列をコピーする関数
void Copy1DArray( int x[] , int y[] )
{
  int n;
  for( n=0 ; n<10 ; n++ ){
    x[n] = y[n];
  }
}

// 配列の要素を表示する関数
void Print1DArray( int x[] )
{
  int n;
  for( n=0 ; n<10 ; n++ ){
    printf("%d ", x[n] );
  }
}
    • 二次元アレイ…このあたりが面倒なのでSTlとかができてきているのだと思う。この方法は少し姑息的とのこと
// sample14.cc
#include <stdio.h>

void Set2DArray( int [][10] );  // 配列の低次の次元の要素数を明記する

int main( void )
{
  int a[10][10];     // 配列の宣言

  Set2DArray( a );   // 配列を関数の引数として渡す

  return(0);
}

// 2次元配列に値を設定する関数
void Set2DArray( int x[][10] )  // 配列の低次の次元の要素数を明記する
{
  int n, m;
  for( n=0 ; n<10 ; n++ ){
    for( m=0 ; m<10 ; m++ ){
      x[n][m] = n*m;     // 配列の要素に適当な値を代入する
    }
  }
}
  • 6. 文字、文字列
  • 7. ファイル操作
    • FILE クラスにお任せ
// sampleFile.cc

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


int main( int argc, char* argv[] )
{
  FILE* fptr_r;
  FILE* fptr_w;
  char buf[128];
  double d1,d2,d3;

  if( argc != 3 ){
    printf("Give two file names.\n");
    exit(1);
  }

  fptr_r = fopen( argv[1], "r" );
  fptr_w = fopen( argv[2], "w" );

  if( fptr_r == NULL || fptr_w == NULL ){
    perror("failed at fopen");
    exit(1);
  }
  
  while( fgets( buf, 128, fptr_r ) != NULL ){
    d1 = atof(&buf[13]);
    d2 = atof(&buf[22]);
    d3 = atof(&buf[31]);

    fprintf( fptr_w, "%+07.2lf %+07.2lf %+07.2lf\n", d1, d2, d3 );
  }

  fclose( fptr_r );
  fclose( fptr_w );

  return(0);
}
  • 8. グラフィクス…省略
  • 描画コマンドを操る
  • 2. ウィンドウを開く
    • この写経サイトが書かれたのは2000年で、その頃は、いろいろする必要があるようだったようだが、今は、X11は標準装備らしいのでコンパイルも楽
#include <X11/Xlib.h>             //Xlibに必要なインクルード
#include <X11/Xutil.h>
#include <stdio.h>

int main( void )
{
  Display* dis;                       //Display pointer
  Window   win;                       //Window  ID
  XSetWindowAttributes att;           //窓属性の変数
  XEvent ev;                          //イベント取り込み変数

  dis = XOpenDisplay( NULL );         //Xserverとの接続
  win = XCreateSimpleWindow( dis, RootWindow(dis,0), 100, 100,
     256, 256, 3, WhitePixel(dis,0), BlackPixel(dis,0) );  //窓の生成

  att.backing_store = WhenMapped;     //絵を保存する設定をする
  XChangeWindowAttributes( dis, win, CWBackingStore, &att );
  

  XMapWindow( dis, win );             //窓の表示
  XFlush( dis );                      //リクエストの強制送信
	
  XSelectInput( dis, win, ExposureMask );
  do{                                 //窓が開くの待つループ
    XNextEvent( dis, &ev);
  }while( ev.type != Expose ); // Exposeイベントが届くまでここを繰り返す

  // ここまで来たら真っ黒な窓が登場しているはず。

  getchar();  // リターンキーが押されるまで待つ。

  XDestroyWindow( dis, win );         //窓の消去
  XCloseDisplay( dis );               //Xserverと断線

  return(0);
}
gcc -o gratest gratest.cc -O2 -lX11 -lm
./gratest
/* diamond.cc */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <math.h>

#define N 16


unsigned long GetColor( Display* dis, char* color_name )
{
    Colormap cmap;
    XColor near_color, true_color;

    cmap = DefaultColormap( dis, 0 );
    XAllocNamedColor( dis, cmap, color_name, &near_color, &true_color );
    return( near_color.pixel );
}


int main( void )
{
    Display* dis;
    Window win;
    XSetWindowAttributes att;
    GC gc;
    XEvent ev;

    int x[N],y[N];
    int i,j;

    dis = XOpenDisplay( NULL );
    win = XCreateSimpleWindow( dis, RootWindow(dis,0), 100, 100,
      256, 256, 5, WhitePixel(dis,0), BlackPixel(dis,0) );

    att.backing_store = WhenMapped;
    XChangeWindowAttributes( dis, win, CWBackingStore, &att );

    XSelectInput( dis, win, ExposureMask );
    XMapWindow( dis, win );

    do{
        XNextEvent( dis, &ev);
    }while( ev.type != Expose );

    gc = XCreateGC( dis, DefaultRootWindow(dis), 0, 0 );
    XSetForeground( dis, gc, GetColor( dis, "green")  );


    for( i=0 ; i<N ; i++ ){
        x[i] = (int)(128*cos(2*M_PI*i/N))+128;
        y[i] = (int)(128*sin(2*M_PI*i/N))+128;
    }

    for( i=0 ; i<N ; i++ ){
        for( j=i+1 ; j<N ; j++ ){
            XDrawLine( dis, win, gc, x[i], y[i], x[j], y[j] );
        }
    }

    XFlush( dis );

    printf("Push return key.");
    getchar();
    XDestroyWindow( dis , win );
    XCloseDisplay( dis );

    return(0);
}
gcc -o diamond diamond..cc -O2 -lX11 -lm
./diamond