Category Archives: C programming exercises 2

C exercises2 (14) Exam

FizzBuzz 問題

1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。

ちゃんとしたプログラマであれば、これを実行するプログラムを2分とかからずに紙に書き出せるはずだ。怖い事実を聞きたい? コンピュータサイエンス学科卒業生の過半数にはそれができないのだ。自称上級プログラマが答えを書くのに10-15分もかかっているのを見たこともある。

Problem

Print integers 1 to 100, but replace multiples of 3 with “Fizz” and multiples of 5 with “Buzz” and multiples of both with “FizzBuzz”
For longer description, see: http://tickletux.wordpress.com/2007/01/24/using-fizzbuzz-to-find-developers-who-grok-coding

http://golf.shinh.org/p.rb?FizzBuzz

C exercises2 (13) C言語2級検定問題演習

検定試験シミュレーション

サーティファイ検定試験シミュレーションSite

http://www.kenteisiken.com/

「模擬検」には、体験版とチャレンジ版の2つの受験形式があります。

C言語プログラミング能力認定試験 2級
チャレンジ版で行ってください。

参考(2級出題範囲)

出題内容
定数 浮動小数点定数 指数形式を許す
浮動小数点接尾語はf、l、F、Lのいずれか
整数定数 整数接尾語として長語接尾語(l、L)を含む
文字定数 拡張表記は8進拡張表記、16進拡張表記を含む
文字列リテラル 拡張表記は8進拡張表記、16進拡張表記を含む
列挙定数
演算子 ビット演算子、条件演算子、代入演算子、キャスト演算子、ポインタ/アドレス演算子、構造体演算子、sizeof演算子
宣言指定子 void、short、long、float、double、構造体共用体指定子(struct、union)、列挙型指定子(enum)、型修飾子(const)、typedef
変数 上記型指定子の単純変数、配列
外部定義
プリプロセッサ機能 ファイルの包含
ライブラリ関数
数学関数<math.h>
double cos(double x); double sin(double x);
double tan(double x); double exp(double x);
double log(double x); double log10(double x);
double pow(double x, double y);
double sqrt(double x); double ceil(double x);
double fabs(double x); double floor(double x);
入出力関数<stdio.h>
NULL、EOF、FILE、stderr、stdin、stdout、
FILE *fopen(const char *filename, const char *mode);
int fclose(FILE *stream);
int fscanf(FILE *stream, const char *format, …);
int fprintf(FILE *stream, const char *format, …);
int sscanf(const char *s, const char *stream, …);
int sprintf(char *s, const char *stream, …);
int fgetc(FILE *stream, …); int fputc(int c, FILE *stream);
char *fgets(char *s,int c, FILE *stream);
int fputs(const char *s, FILE *stream);
int getc(FILE *stream, …); int putc(int c, FILE *stream);
char *gets(char *s);int puts(const char *s);
int ungetc(int c, FILE *stream);
一般ユーティリティ関数<stdlib.h>
NULL  double atof(const char *nptr);
int atoi(const char *nptr);
long int atol(const char *nptr);
int rand(void);  void srand(unsigned int seed);
int abs(int i);  long int labs(long int j);
文字列操作関数<string.h>
NULL  size_t
char *strcpy(char *sl,const char *s2);
char *strncpy(char *sl,const char *s2, size_t n);
char *strcat(char *sl,const char *s2);
char *strncat(char *sl,const char *s2, size_t n);
int strcmp(const char *sl,const char *s2);
int strncmp(const char *sl,const char *s2, size_t n);
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
char *strstr(const char *sl, const char *s2);
size_t strlen(const char *s);
その他
  • main関数の引数、整数型以外の関数
  • 自己参照構造体
  • 変数の記憶クラスと通用範囲(auto、static、register、extern)

※3級出題範囲含む

注)各級とも日本工業規格 (JIS) X3010 で出題・解答する。

C exercises2 (12) C言語3級検定問題演習

C言語検定試験について

試験名

C言語プログラミング能力認定試験
(C-Language Programming Skills Qualification Test)

http://www.sikaku.gr.jp/ 

試験目的

C言語を駆使して応用プログラム(言語処理系、ユーティリティなど)を作成する能力を認定します。

認定基準

一級 C言語を駆使し、応用プログラム(言語処理系、ユーティリティなど)が作成できる能力を有する。また使用しているOSについて理解をしている。
二級 小規模のプログラム(500行程度)が適切に(理路整然、簡潔、正しく、速く)書ける。また各種基本アルゴリズムを理解している。
三級 C言語の概念を理解し、簡単なプログラムが書ける。

 

参考(3級出題範囲)

 

出題内容
定数 整数定数 10進定数、8進定数、16進定数
整数接尾語は符号無し接尾語(u、U)のみ
文字定数 ワイド文字定数(L’c文字の列’)を除く
拡張表記は単純拡張表記のみ
文字列リテラル ワイド文字列リテラル(L”s文字の列”)を除く
拡張表記は単純拡張表記のみ
演算子 算術演算子、インクリメント演算子、デクリメント演算子、(算術の)代入演算子、関係演算子、等値演算子、論理関係演算子、括弧演算子、コンマ演算子
型指定子 char、int、unsigned、signed
変数
  • 上記型指定子の単純変数、配列
  • 初期化の構文
基本制御文 break、continue、do、for、if、return、switch、while
プリプロセッサ機能 #define、#include
ライブラリ関数
入出力関数<stdio.h>
EOF  NULL
int printf(const char *format, …);
int scanf(const char *format, …);
int getchar(void);  int putchar(int c);
文字操作関数<ctype.h>
int isalnum(int c);  int isalpha(int c);
int iscntrl(int c);  int isdigit(int c);
int isgraph(int c);  int islower(int c);
int isprint(int c);  int ispunct(int c);
int isspace(int c);  int isupper(int c);
int isxdigit(int c);  int tolower(int c);
int toupper(int c);
その他 Cの歴史と特徴

注)各級とも日本工業規格 (JIS) X3010 で出題・解答する。

LinkedIn(リンクトイン)

世界最大級のビジネスSNSLinkedIn(リンクトイン)」。2016年6月13日、MicrosoftがLinkedInを262億ドル(約2兆7770万円)買収することで合意した、と発表しました。

そんなLinkedInは、世界で4億人が使う、採用やネットワーク構築に活かせるビジネスSNSです。しかしまだまだ日本では「ハードルが高い」と思われている方も多いかもしれません。

しかしこのLinkedIn、きちんと使えばとっても役に立つと思います!

日本語にも対応していますし、要はSNSなので、難しいサービスでもありません。要はFacebookのビジネス版のようなものです。うまく使いこなせれば、色々なメリットがあります。

  • 履歴書・レジュメ代わり。ビジネスのための「自己紹介ツール」
    • 取得資格一覧
  • ビジネスに特化した、自分のつながり(要はコネ)を整理できる
  • 仕事に役立つ、リアルな情報を日々収集できる

C言語3級検定問題演習(1月10日)

Google Classroomを利用

https://classroom.google.com/

C exercises2 (11) Binary File

テキストとバイナリのファイル

バイナリファイルには、

ファイルの種類
拡張子
説明
JPEG画像ファイル .jpg JPEG圧縮された画像ファイル
GIF画像ファイル .gif GIF圧縮された画像ファイル
WAV音声ファイル .wav WINDOWS標準音声ファイル
MPEGファイル .mpg MPEG圧縮された動画ファイル

などがあります。

バイナリ・アクセスを行う関数

書き込みには次の関数を使用します。

size_t fwrite( const void * ptr, size_t size, size_t n, FILE * stream );

  • ptr は書き込むデータの先頭アドレスを示すポインターです。
  • size は書き込むデータ一つ分のデータのバイト数です。
  • n は size バイトのデータを幾つ書き込むか、即ち書き込むデータの個数です。
  • stream は FILE 型へのポインターです。

戻り値は成功すれば n の値がそのまま、失敗すれば n より小さい値です。
成功すると書き込んだバイト数の分だけファイルの読み書き位置が進みます。失敗するとファイルの読み書き位置は不定です。
続いて読み込み関数です。

size_t fread( void * ptr, size_t size, size_t n, FILE * stream );

引数の意味するところは fwrite の引数が読み込みになっただけです。

  • ptr は読み込んだデータを格納する領域へのポインターです。
  • size は読み込むデータ一つ分のバイト数です。
  • n は size バイトのデータを幾つ読み込むか、即ち読み込むデータの個数です。
  • stream は FILE 型へのポインターです。

戻り値は成功すれば n の値がそのまま、失敗すれば n より小さい値です。但し n より小さくても途中でファイルの終端になった場合もあり、エラーとは限りません。
成功すると読み込んだバイト数分ファイルの読み書き位置が進みます。失敗するとファイルの読み書き位置は不定です。

サンプルプログラム

/* バイナリデータの読み書き */

#include <stdio.h>
#include <stdlib.h>
 
void main() {
    FILE* file;
    int i;
    //  書き込むデータ
    char wdata[] = { 0x10 , 0x1a , 0x1e , 0x1f };
    char rdata[4];
    //バイナリデータの書き込み
    file = fopen( "C:¥¥test¥¥test.bin", "wb" );
    if( file == NULL ){
        printf( "ファイルオープンに失敗しました。\n" );
        exit( 1 );
    }
    fwrite( wdata, sizeof(char), sizeof(wdata), file );
    fclose(file);          // ファイルをクローズ(閉じる)
    //バイナリデータの書き込み
    file = fopen( "C:¥¥test¥¥test.bin", "rb" );
    if( file == NULL ){
        printf( "ファイルオープンに失敗しました。\n" );
        exit( 1 );
    }
    fread( rdata, sizeof(char), sizeof(rdata), file );
    fclose(file);          // ファイルをクローズ(閉じる)
    //  結果を表示
    for(i = 0; i < sizeof(rdata) ; i++){
        printf("%x ",rdata[i]);
    }
    printf("¥n");
}

実行結果

10 1a 1e 1f

処理の流れ

10行目から17行目は、ファイルへデータを書き込んでいます。fopen()でファイルを開くのは同じですが、モードを”wb”に指定していることから、 バイナリモードでの書き込みとなります。ここでは、fwrite()でデータを書き込みます。ファイル名は、cドライブ直下のtestフォルダー内にあるtest.binに書き込まれます。

データは、char型の配列wdataのデータを書き込んでいます。最後は、fclose()でファイルを閉じて、書き込みが終了します。

次に、18行目から25行目でデータを読み込みます。fopen()でファイルを開きますが、今度はバイナリファイルの読み込みなので、モードに”rb”を指定します。バイナリモードでの読み込みは、fread()関数を用います。ここでは、char型の配列rdataに値を読み込んでいます。最後はclose()でファイルを閉じて終了です。

/* ファイルダンププログラム */

/* ファイルダンププログラム */
#include <stdio.h>
#include <ctype.h>

#define W 16	/* 16桁ずつ表示する */ 

int main(int argc, char *argv[])
{
  FILE *fp;
  int n, i;
  long offset = 0;
  unsigned char buf[W];

  if (argc < 2) {
    printf("ファイル名を指定してください。\n");
    return 0;
  }
  if ((fp = fopen(argv[1], "rb")) == NULL) {
    printf("ファイルオープンエラーです。\n");
    return 1;
  }
  while ((n = fread(buf, 1, W, fp)) > 0) {
    printf("%08lX: ", offset);
    for (i = 0; i < n; i++) {
      printf("%02X ", buf[i]);
    }
    if (n < W) {
      for (i = n; i < W; i++) {
        printf("   ");
      }
    }
    for (i = 0; i < n; i++) {
      if (isprint(buf[i])) {
        putchar(buf[i]);
      }
      else {
        putchar('.');
      }
    }
    putchar('\n');
    offset += W;
  }
  putchar('\n');

  fclose(fp);

  return 0;
}

 

演習

  1. P344演習+社員情報構造体データをバイナリファイルに出力する。
  2. 1)のバイナリファイルを構造体変数に読み込む。

C exercises2 (10) Text File

テキストファイル

 

ファイルの種類
拡張子
説明
C言語ソースファイル .c C言語のプログラムを記述したファイル
C言語ヘッダーファイル .h C言語のヘッダーを記述したファイル
C++ソースファイル .cpp C++のプログラムを記述したファイル
HTML文章 .html インターネットで使われているマークアップ文章
データファイル .dat 様々なデータを保存するファイル

 

文字の入出力

fgetc()関数

fgetc()関数

fgetc()関数はファイルポインタで指定したファイルから1文字入力します。
fgetc()関数はgetchar()関数と使い方が似ているところがあります。

例題3 この例題のソースファイルを出力する
#include <stdio.h>

int main(){
  //ファイル構造体へのポインタを宣言
  FILE *fp;
  char str;

  //読み込みモードでファイルを開く
  fp = fopen("01.cpp","r");

  //ファイルが開けなかったとき
  if(fp==NULL){
    //失敗を表示して終了
    printf("ファイルオープンエラーn");
    return -1;
  }

  //ファイルの終端(EOF)になるまで続ける
  //ファイルから一文字読込strに格納
  while((str = fgetc(fp))!=EOF){
    //strを出力
    printf("%c",str);
  }

  //ファイルを閉じる
  fclose(fp);
  return 0;
}

 

fputc()関数

fputc()関数

fputc()関数はファイルポインタで指定したファイルに1文字を書き込みます。
fputc()関数はputchar()関数と使い方が似ているところがあります。

例題5 この例題のソースファイルを違うファイルへ出力する
#include <stdio.h>

int main(){
  //ファイル構造体へのポインタを宣言
  //読込み用、書き込み用それぞれ宣言する
  FILE *lf,*sf;
  int c;

  //読み込み、書込みそれぞれでオープン
  //短縮して書いていますが、
  //if(lf=fopen("01.cpp","r")==NULL){}
  //if(sf=fopen("test.txt","w")==NULL){}
  //の場合と同じです。
  if(!(lf=fopen("01.cpp","r")) || (!(sf=fopen("test.txt","w")))){
    printf(" ファイルオープンエラーn");
    return -1;
  }

  //ファイルの中身がEOFになるまで続ける
  //ファイルから一文字読み込みcへ格納
  while((c=fgetc(lf))!=EOF){
    //画面に出力
    putchar(c);
    //ファイルに出力
    fputc(c,sf);
  }

  //書込みクローズ
  fclose(sf);
  //読み込みクローズ
  fclose(lf);

  return 0;
}

 

書式付入出力

 

fscanf()関数

fscanf()関数

fscanf()関数はファイルポインタで指定したファイルから文字や数値を入力します。
fscanf()関数はscanf()関数のファイル版にあたります。
(1)は指定文字列、(2)は入力データを格納する変数のアドレスを表します。

fprintf()関数

fprintf()関数

fprintf()関数はファイルポインタで指定したファイルに文字や数値を出力します。
fprintf()関数はprintf()関数のファイル版にあたります。
(1)は書式指定文字列、(2)は変数を表します。

エラー処理

fopen()関数を使ってファイルを開くことが出来ますが、必ずしもファイルを開くことができるとは限りません。
ファイルを開くことが出来ないままファイルを操作する処理を実行するのはとても危ないです。
そこで、エラーを起こした時はそのままプログラムを実行させるのではなく、エラー処理をさせ、プログラムを正しく動かします。
fopen()関数で正しくファイルを開くことが出来ない場合はNULLを返しますが、それを使うことでエラー処理を行うことが出来ます。
エラー処理の方法は以下の通りです。

エラー処理

“エラー処理”とコメントアウトしている部分に処理を記述すると、ファイルオープンに失敗した場合にエラー処理を実行することになります。
慣れてくればこのように書いても大丈夫です。

エラー処理

fopen()関数とifを1行にまとめました。
()のくくり方が若干複雑なので、書き方に慣れていない人は使わないほうが無難でしょう。
次に、エラー処理の内容について説明します。
エラー処理は基本的に「エラーしましたよ」というのを表示してからプログラムを強制終了させます。
表示する部分はprintf()関数を使って表示させます。
強制終了はreturn文を使っても構わないですが、自作関数内でreturn文を使うことになると、呼び出し元へ戻ってしまいます。
そこで使うのがexit()関数と呼ばれるものです。
exit()関数はプログラムを終了させる関数で、exit()関数を使うには「#include<stdlib.h>」を追加する必要があります。
exit()関数の使い方は以下のようになります。

exit()関数

ステータスはexitによる終了が正常終了なのか異常終了なのかを調べます。
ステータスの値は基本的に決められた数値はありませんが、正常終了が0、異常終了が1というのが暗黙の了解で決まっています。
さらに0はEXIT_SUCCESS、1はEXIT_FAILUREと書きかえることができます。
どちらを使うかはお好みで。

演習

  1. P344演習+社員情報構造体データをテキストファイルに出力する。
  2. 1)のテキストファイルを構造体変数に読み込む。

 

C exercises2 (9) File Access

ファイル入出力の基本

ファイル入出力の流れを見ていきましょう。

ファイル入出力は以下の手順を踏みます。

(1)ファイル構造体のポインタ作成

(2)ファイルオープン

(3)ファイルの読み書き

(4)ファイルクローズ

上から順を追って説明していきましょう。

(1)ファイル構造体のポインタを作成

ファイル入出力を行うためには、まずファイル構造体のポインタを作成する必要があります。
ポインタの作成方法は以下の通りです。

構造体ポインタ

この一文を書くだけで、ファイル構造体のポインタが作成されます(変数名は各自お好みで)。
そう言えば、ファイル構造体を作っていないのに宣言が可能なのでしょうか?
実は既にファイル構造体は出来上がっているのです。
ソースコードの最初におまじないとして書いている「#include <stdio.h>」を入れることによって自動的にファイル構造体が作られています。
興味のある人は、” C:Program FilesMicrosoft Visual Studio 8VCincludestdio.h”(インストール場所によって” C:Program Files”の場所は違う)の59~69行目を見てみよう。
59~69行目に記述されているのが実はファイル構造体なのです。
「#include <stdio.h>」を入れることによって59~69行目の構造体が使えるのかは次回で確認してください。

(2)ファイルオープン

ファイルを開くにはfopen()関数を使います。
fopen()関数の使い方は以下の通りです。

ファイルオープン

ファイル名は開きたいファイル名を記述します。
オープンモードはファイルをどのように開くかを決めます。
オープンモードの種類は以下の通りです。

モード 動作 ファイルがある場合 ファイルがない場合
“r” 読み出し専用 変化なし 失敗
“w” 書き込み専用 ファイル上書き 新規作成
“a” 追加書き込み専用 ファイルの最後に追加 新規作成
“r+” 読み込みと書き込み 変化なし 失敗
“w+” 書き込みと読み込み ファイル上書き 新規作成
“a+” 読み込みと追加書き込み ファイルの最後に追加 新規作成

fopen()関数はファイルを開く時にファイルを正しく開くことが出来ると様々なファイル情報を持つFILE型のポインタ変数を返します。
このFILE型のポインタ変数の事をファイルポインタといいます。
正しく開くことが出来なかった場合は失敗とみなされNULLを返します。

(4)ファイルクローズ

ファイルの読み書きの前にファイルの閉じ方を説明します。
ファイルを閉じるにはfclose()関数を使います。
fclose()関数の使い方は以下の通りです。

ファイルクローズ

fopen()関数によって開いたファイルをfclose()関数で閉じます。
こうすることで開いたファイルを閉じることが出来ます。
ここまでで簡単なファイル操作が出来ますので、例題で確かめてみましょう。
今回はtest.datをいう名前のファイルを開いて閉じるというのをやってみます。

例題1 ファイルを開いて閉じる結果

確認のため、出力しました

ファイルを書き込みモード”w”で開き、ファイルが存在していなかったのでソースコードがあるところにtest.datというファイルが作成されています。
テキストエディタなどで開いて中身を見てもらえば分かるとおり、プログラムは開いて閉じるだけの処理なので中身はカラッポです。

文字列の入出力

先ほど飛ばしたファイルの読み書きについて説明します。

fgets()関数

fgets()関数

fgets()関数はファイルポインタで指定したファイルから読み取る文字数だけ読み取り、文字配列に格納します。
読み取る文字数にはヌル文字も含まれるので読み取る文字数の最大値は指定した数値-1となります。
指定したファイルの途中で改行やファイルの終了を見つけた時は読み取りを終え、改行も配列に格納されます。
そして、最後に格納した配列の次の配列にヌル文字を入れて文字列の終了とします。

例題2 この例題のソースファイルを出力する
#include <stdio.h>

int main(){
  //ファイル構造体へのポインタを宣言
  FILE *fp;
  char str[1024];

  //01.cppを読み込みモードで開く
  //ファイル名は自分でつけたファイル名を書いてください
  fp = fopen("01.cpp","r");

  //ファイルオープンに失敗したとき
  if(fp==NULL){
    //失敗を表示し終了
    printf("ファイルオープン失敗n");
    return -1;
  }

  //fgetsの戻り値がnullになるまで続ける
  //strにファイルからバイト取得し格納
  while((fgets(str,256,fp))!=NULL){
    //格納された文字を出力
    printf("%s",str);
  }

  //ファイルを閉じる
  fclose(fp);
  return 0;
}

 

fputs()関数

fputs()関数

fputs()関数はファイルポインタに指定したファイルに文字配列に格納されている文字列を書き込みます。
fputs()関数はputs()関数のファイル版にあたります。

例題4 この例題のソースファイルを違うファイルへ出力する
#include <stdio.h>

int main(){
  //ファイル構造体へのポインタを宣言
  //読込みようファイルポインタ:lf
  //書き込み用ファイルポインタ:sf
  //をそれぞれ宣言する
  FILE *lf,*sf;
  char str[256];
  int c;

  //読み込みモードでファイルを開く
  lf = fopen("01.cpp","r");
  //エラー
  if(lf==NULL){
    printf("ファイルオープンエラーn");
    return -1;
  }

  //書き込みモードでファイルを開く
  sf = fopen("test.txt","w");
  //エラー
  if(sf==NULL){
    printf("ファイルオープンエラーn");
    return -1;
  }

  //fgetsがNULLになるまで繰り返す
  //fgets(str,256,lf)!=NULL
  //と同じです。このように短縮することも可能
  while(fgets(str,256,lf))
  {
    printf("%s", str);
    //str に格納されている文字列をsfに書き込む
    fputs(str,sf);
  }

  //sfクローズ
  fclose(sf);
  //lfクローズ
  fclose(lf);

  return 0;
}

画面出力され、ファイルにもちゃんと書き込まれていますね。

演習 (P371)

色の名前を格納してあるファイル[Color.txt]を読み込み、”green”が名前の中にあるもののみファイル”green.txt”に書き込むプログラムを作成せよ。

C exercises2 (7) Ch9 & Ch10 Summary

ビットと構造体のまとめ

  • 第9章 ビットを意識する
  • 第10章 構造体を使いこなす

Google Classroom

https://classroom.google.com/

Googleクラスルームログイン方法

  • ID : 15TE123@daiichi-koudai.com
    PW : 15TE123@daiichi-koudai.com

(初期PWは、最初のログインで変更すること)

演習コードの提出する方法

ソースコード(.cファイル)を課題の詳細ページより、添付で提出する。

先週の演習コードの提出は間違いが多いから、問題点をリスト
1)添付ファイルなし
2)空白の添付ファイル
2)ソースコード(.cファイル)以外のものを提出

提出した演習コードの修正する方法
1)提出を取り消し
2)提出内容の確認、修正
3)再提出

 

C exercises2 (6) Structures and Functions

数学における複素数(ふくそすう、英: complex number)は、実数の対 a, b と 1 と線型独立な(実数ではない)要素 i の線型結合 a + bi の形に表される数(二元数: 実数体上の二次拡大環の元)で、基底元 i はその平方が −1 になるという特別な性質を持ち虚数単位と呼ばれる。

解説のためのサンプルとして,複素数を表す構造体を作っておく.

typedef struct {
    double re; /* 実数部分 */
    double im; /* 虚数部分 */
} complex_t;

 

構造体型の関数引数

関数の引数として,構造体全体の全体を(その値をコピーして)引き渡すことができる. (配列では,そのようなことはできなかったことに注意しよう)

次の関数 printComplex は complex_t 構造体型の引数をとり,それを表示する.

void printComplex(complex_t c)
{
    printf("%f + %f i\n", c.re, c.im);
}

main()
{
    complex_t c = {1.2, 3.4};
 
    printComplex(c);
}
1.200000 + 3.400000 i

構造体型の関数戻り値

構造体型を関数の戻り値の型とすることができる. (配列を関数の戻り値とすることはできなかったことに注意しよう)

次の関数 addComplex は complex_t 構造体型の引数を二つとり, その和を complex_t 構造体型として返す.

complex_t addComplex(complex_t a, complex_t b)
{
    complex_t c;
    
    c.re = a.re + b.re;
    c.im = a.im + b.im;
    
    return c;
}

main()
{
    complex_t a = {1.2, 3.4};
    complex_t b = {5.6, 7.8};
    complex_t c;
    
    c = addComplex(a, b);
    printComplex(c);
    
    return 0;
}
6.800000 + 11.200000 i

構造体ポインタ型の関数引数

関数の引数に,構造体へのポインタ値を与えることもある.

次の関数 addComplexPtr は,3個の complex_t ポインタ型を引数にとり, 最初の2つが指すところにある complex_t 型の値を加えたものを, 最後のものが指すところにある complex_t 型に代入する.

void addComplexPtr(complex_t *a, complex_t *b, complex_t *c)
{
    (*c).re = (*a).re + (*b).re;
    (*c).im = (*a).im + (*b).im;
}

main()
{
    complex_t x = {1.2, 3.4};
    complex_t y = {5.6, 7.8};
    complex_t z;
    
    addComplexPtr(&x, &y, &z);
    printComplex(z);
    
    return 0;
}
6.800000 + 11.200000 i

このように,構造体全体の値をコピーして引数に渡すのではなく, ポインタ値だけを渡す理由には,おおよそ2通りある.

一つは,構造体全体の値よりもポインタ値だけの方が引き渡す手間が少いということである. これは,メモリと実行時間の有効利用という点では大事である. この例の場合,最初の2個の引数 a と b とがポインタ値となっている理由がそうである.

もう一つは,関数外部の構造体の中身を関数内部で変更したいときである. この例の場合,最後の引数 c がポインタ値となっている理由がそうである.

次で説明する間接メンバ参照演算子 -> を用いて,次のようにも書くことができる.

void addComplexPtr(complex_t *a, complex_t *b, complex_t *c)
{
    c->re = a->re + b->re;
    c->im = a->im + b->im;
}

演習

  1. P360
    P353演習を関数化
  1. P360
    P346演習の関数化