Category Archives: 明解C言語入門

8.1 マクロ

Published by:

オブジェクト形式マクロ

オブジェクト形式マクロとしての #define は、次のような形式で記述します。

#define マクロ名 置換後の文字の並び

強制されているわけではありませんが、一般的にマクロ名は大文字で表記することが多いです。また、置換後の文字の並びは空にしても構いません

コンパイルを行う直前で、ソースコード上の文字を置換し、その結果をコンパイルするのです。そうすることで、ソースコードの見た目を読みやすいまま保ちつつ、高度な処理を実現できます。

関数形式マクロ

関数形式マクロは、使用時の記述が関数を呼び出しているように見えるため、このように呼ばれます。関数形式マクロの定義は、次のように行います。

#define マクロ名(仮引数のリスト) 置換後の文字の並び

マクロ名の直後に ( ) で仮引数を指定する点が、オブジェクト形式マクロとの違いです。ただし、仮引数に型の指定はありません。仮引数がない場合は void とは書かず、単に ( ) の中を空にします。

通常の関数と異なり、マクロの場合はプリプロセスの段階で置換済みであることを忘れないようにしましょう。関数を呼び出すという行為そのものにも処理時間がかかるのですが、マクロの場合はこの呼び出し自体が発生しませんから、処理効率は向上します。

一方で、マクロを使っている箇所が個別に置換されるため、使用箇所が多いと、プログラムの大きさは増大しやすくなります。

なお、関数のように使うため、置換後の結果を複数行に渡って記述できた方が、見た目の上でも分かりやすくなることがあります。しかし、マクロの置換結果の中で普通に改行を行うことはできません。マクロの置換結果の中で改行を行うには、行末に \ を置きます。

#define INITIALIZE(a,b,c)  \
    (a) = 0; \
    (b) = 0; \
    (c) = 0;

特に、\ の後ろには改行しかあってはならないことに注意してください。

演習

演習 8-1

二つの値xとyの差を求める関数形式マクロを定義せよ。
diff (x, y)

演習 8-2

二つの値xとyの大きいほうの値を求める関数形式マクロは次のように定義できる。
#define max (x, y) (((x) > (y)) ? (x) : (y))
このマクロを利用して、四つの値a, b c d の最大値を求める、 次に示す各式がどのように展開さ
れるかを示し、考察を加えよ。
max (max (a, b), max(c,d))
max (max (max (a, b), c), d)

演習 8-3

type 型の二つの値を交換する、 関数形式マクロを次の形式で定義せよ。
swap (type, a, b)
たとえば、 int 型の変数xとyの値が5と10であるときに、 swap (int, x, y) を呼び出した後は、
xとyには10と5が格納されていなければならない。

7.4 演算子の優先順位

Published by:

表の上に位置するほど、優先順位が高くなります。

優先順位 演算子 名称 使い方
1(高) ()
[]
.
->
++(後置)
ーー(後置)
関数呼び出し
添字演算子
ドット演算子
アロー演算子
インクリメント(後置)
デクリメント(後置)
func()
num[0]
pos.x
pPos->x
num++
num–
2 +

&
*
sizeof
!
~
++
ーー
正符号
負符号
アドレス演算子
間接参照演算子
サイズオブ演算子
論理否定
ビットの論理否定
インクリメント(前置)
デクリメント(前置)
+num
-num
&data
*pdata
sizeof(num)
!num
~num
++num
–num
3 (型名) キャスト (long)num
4 *
/
%
乗算
徐算
剰余
num1 * num2
num1 / num2
num1 % num2
5 +
加算
減算
num1 + num2
num1 – num2
6 <<
>>
左シフト
右シフト
num << 5
num >> 5
7 <
<=
>
>=
小なり
小なりイコール
大なり
大なりイコール
num < 5
num <= 5
num > 5
num >= 5
8 ==
!=
イコール
ノットイコール
num == 5
num != 5
9 & AND演算子 num & 0x7F
10 ^ XOR演算子(排他的論理和) num ^ 0x80
11 | OR演算子 num | 0x80
12 && 論理積 num1 == 0 && num2 == 0
13 || 論理和 num1 == 0 || num2 == 0
14 ?: 三項演算子 num % 2 ? 1 : 0
15 =
+=など
代入
自己代入形式の代入
num = 1
num += 1
16(低) , カンマ num1, num2
スクロールできます

 

7.2 整数型と実数型

Published by:

10進数、2進数、16進数

2進数 10進数 16進数 2進数 10進数 16進数
0 0 0 10001 17 11
1 1 1 10010 18 12
10 2 2 10011 19 13
11 3 3 10100 20 14
100 4 4 10101 21 15
101 5 5 10110 22 16
110 6 6 10111 23 17
111 7 7 11000 24 18
1000 8 8 11001 25 19
1001 9 9 11010 26 1A
1010 10 A 11011 27 1B
1011 11 B 11100 28 1C
1100 12 C 11101 29 1D
1101 13 D 11110 30 1E
1110 14 E 11111 31 1F
1111 15 F 100000 32 20
10000 16 10 100001 33 21

10進数

0~9の10個の数を使い、繰り上がりは、10のべき乗になります。1は100、10は101、100は102、1000は103

2進数

0と1の2個の数を使い、繰り上がりは、2のべき乗になります。1は20、10(10進数では2)は21、100(10進数では4)は22、1000(10進数では8)は23

16進数

0~9の10個の数とアルファベットのA~Fの6個の文字を使い、計16個の英数字を使います。繰り上がりは、16のべき乗になります。1は160、10(10進数では16)は161、100(10進数では256)は162、1000(10進数では4096)は163

整数型と文字型

データの型には次のようなものがあります。

種類 型名 サイズ 値の範囲
文字型 char 1バイト -128 ~ 127
整数型 short int
int
long int
2バイト
4バイト
4バイト
-32768 ~ 32767
-2147483648 ~ 2147483647
-2147483648 ~ 2147483647
浮動小数点型 float
double
long double
4バイト
8バイト
8バイト
3.4E-38 ~ 3.4E+38
1.7E-308 ~ 1.7E+308
1.7E-308 ~ 1.7E+308

符号ありデータの型

種類 型名 サイズ 値の範囲
文字型 unsigned char 1バイト 0 ~ 255
整数型 unsigned short int
unsigned int
unsigned long int
2バイト
4バイト
4バイト
0 ~ 65535
0 ~ 4294967295
0 ~ 4294967295

 

12.1 構造体

Published by:

演習

1)任意二つのunsigned int型数値の論理AND, OR, XORを求めなさい(P324)

/* a9-4-1.c */
#include <stdio.h>
#include <limits.h>

int main(void)
{
  unsigned a, b;

  printf("0 〜 %u の整数を2つ入力してください。¥n", UINT_MAX);
  printf("> ");
  scanf("%u", &a);
  printf("> ");
  scanf("%u", &b);

  printf("%u(%#x) AND %u(%#x) = %#x¥n",__,__,__,__,__);
  printf("%u(%#x) OR  %u(%#x) = %#x¥n",__,__,__,__,__);
  printf("%u(%#x) XOR %u(%#x) = %#x¥n",__,__,__,__,__);

  return 0;
}

 

2)任意unsigned int型数値のビットパターンを表示(P328)

/* a9-4-2.c */
#include <stdio.h>
#include <limits.h>

void show_bit(unsigned dt);

int main(void)
{
  unsigned a;

  printf("0 〜 %#x の16進数を入力してください。> ", UINT_MAX);
  scanf("%x", &a);

  show_bit(a);

  return 0;
}

/*** ビット表示関数 ***/
/*(仮引数)dt:表示データ */
void show_bit(unsigned dt)
{
    int i, len;

    len = sizeof(dt) * CHAR_BIT;
        
    printf("%#x ---> ", dt);
    for (i = len - 1; i >= 0; i--){
        putchar(( __ >> __ & 1U) ? '1' : '0' );
    }
    putchar('¥n');
}

 

演習解説

構造体の変数

構造体とは

構造体とは,「いろいろな種類の互いに関連するデータをまとめて, 1つのかたまりにしたもの」である。 たとえば,「氏名,年齢,性別などのデータを一人分だけまとめたもの」 このようなものをいう。

構造体 構造体を構成する要素を,構造体のメンバと呼ぶ。上の例では, 「名前」「性別」「年齢」「身長」「体重」などが,メンバにあたる。

構造体の宣言

構造体は,一つのデータ型であり,その型枠をまず始めに宣言する必要がある。 そして,その型枠を型とする変数を宣言する形で構造体の実体(オブジェクト)を宣言し, それを使用することができる。

構造体の型枠の宣言と,その型枠をもつ構造体変数の宣言は次のようになされる.

struct 構造体タグ名 {メンバの並び};   /* 型枠の宣言 */

struct 構造体タグ名 構造体変数名;     /* 構造体変数の宣言 */

例えば,次図のような人のデータをまとめた構造体の定義は下のようになる。

person 構造体struct

 _person {           /* _person がタグ名 */
    char name[20];        /* 文字配列型のメンバ name */
    char sex;              /* 文字型メンバ sex */
    int age;               /* 整数型メンバ age */
    double height;         /* 倍精度実数型メンバ height */
    double weight;         /* 倍精度実数型メンバ weight */
};


struct

 _person p;      /* p という名前の struct _person 型変数を宣言 */

構造体の代入

一つの構造体変数の内容全部を 同じ型の別の構造体変数に, 通常の変数を代入するのと同じように,代入することができる.

    person_t p1 = {"Tom", 'M', 19, 175.2, 69.5};
    person_t p2;
    
    p2 = p1;

構造体の代入

構造体の配列

構造体を並べた配列も扱える.その宣言定義は通常のようにすればよい.

#define PERSON_NUM 5

typedef struct {   
    char name[20];
    char sex; 
    int age;
    double height; 
    double weight; 
} person_t;

person_t p[PERSON_NUM]

;

これで,要素数がPERSON_NUM個(5個)の person_t 構造体型配列 p ができる.

構造体配列たとえば,上の図で色のついてある p[3] の height メンバには, p[3].height でアクセスする.

サンプルプログラム2

#include <stdio.h>

#define PERSON_NUM 5

typedef struct {   
    char name[20];
    char sex; 
    int age;
    double height; 
    double weight; 
} person_t;

main()
{
    person_t p[PERSON_NUM] = {{"Bob",      'M', 19, 165.4, 72.5},
                              {"Alice",    'F', 19, 161.7, 44.2},
                              {"Tom",      'M', 20, 175.2, 66.3},
                              {"Stefany",  'F', 18, 159.3, 48.5},
                              {"Leonardo", 'M', 19, 172.8, 67.2}};
    int i;
    double height_sum, weight_sum, height_ave, weight_ave;                          
    
    height_sum = weight_sum = 0.0;
    for (i = 0; i < PERSON_NUM; i++) {
        height_sum += p[i].height;
        weight_sum += p[i].weight;
    }
    height_ave = height_sum / PERSON_NUM;
    weight_ave = weight_sum / PERSON_NUM;
    
    printf("average height = %fn", height_ave);
    printf("average weight = %fn", weight_ave);
    
    return 0;
}

構造体のいろいろな宣言の仕方

  1. 構造体の型枠と実体を同時に宣言する
  2. 初期化も同時に行う
  3. 構造体タグ名を記述しないこともできる
  4. typedefで別名をつけることができる

演習

「学籍番号、氏名、学年、クラス」を含める構造体の宣言、初期化、表示するプロフラムを作る。
演習
struct student
{
char no[10]; //番号
char name[20]; //名前
int s_year; //年
char s_class; //クラス
};