C言語編 第27章 簡略記法

先頭へ戻る

このエントリーをはてなブックマークに追加

この章の概要

この章の概要です。

複合代入演算子

既に使っていますが、「+=」のように、演算と代入を合体させた演算子を複合代入演算子と呼びます。 「+=」のほかに「-=」「*=」「/=」「%=」が使えます。

まだ登場していませんが、「&=」「|=」「^=」「<<=」「>>=」もあります。 これらは第49章で説明します。

複合代入演算子を使わなくても、「a = a + b;」のように書くことはできるので、そういう意味では、こんな演算子は不要であるとも言えます。 これらの演算子は、短く簡潔に記述できるようにするために存在しており、 こういった目的で用意された構文を、構文糖(シンタックスシュガー)と呼びます。

なお、ソースコードを短く書いたからといって、実行速度も向上するというものではありません。 ソースコードの長さと、実行効率の間には、明確な比例関係は存在しません。

代入の連結

同じ値を、複数の変数に代入したい場合があります。今までは次のようにしてきました。

a = 100;
b = 100;
c = 100;

このように、同じ値を複数の変数に代入するときには、次のように書くことができます。

a = b = c = 100;

この式は、次のように分解して考えることができます。

a = (b = (c = 100));

同じ型の変数をまとめて宣言する

幾つかの変数を宣言するとき、今までは次のようにしてきました。

int i;
int j;
int k;

変数の型が同じであれば、次のようにまとめて宣言することができます。

int i, j, k;

初期値がある場合には、次のように書くことができます。

int i = 0, j = 10, k = 20;

一部の変数にだけ初期値を与えることもできます。

int i, j = 10, k;

カンマ演算子

カンマ演算子を使うと、複数の式を連結できます。 よくあるのは、for文で 2つ以上のループ制御変数を使うというものです。

#include <stdio.h>

int main(void)
{
	int i, j;

	for( i = 0, j = 20; i < j; ++i, --j ){
		printf( "%d %d\n", i, j );
	}
	
	return 0;
}

実行結果:

0 20
1 19
2 18
3 17
4 16
5 15
6 14
7 13
8 12
9 11

カンマ演算子(,) で区切られた 2つの式は、左側から処理されます

条件演算子

条件演算子は、if文の変形のようなもので、演算子を使って分岐構造が実現できます。 正確な名前とは言い難いのですが、一般に三項演算子と呼ばれることもあります。

この演算子は、? と : という 2つの記号を使って、3つの部分に分けて書きます。 構文は次の通りです。

条件式 ? 真のときの式 : 偽のときの式

例えば、絶対値を返す関数を次のように書けます。

int abs(int num)
{
	return (num < 0) ? (-num) : (num);
}

ソースを短く書ける魅力はありますが、あまり多用すると見づらくなりがちです。 例えば、ネストして使用した次のコードは、読みやすいものとは言えません。

res = (a > 0) ? ( (b > 100) ? ('A') : ( (b > 50) ? ('B') : ('C') ) ) : ('D');

if文と違い、条件演算子の場合、関数の実引数のところに埋め込めるという利点があります。

printf( "入力は100ですか?  %s\n", (in == 100) ? ("YES") : ("NO") );

文字列定数の連結

文字列定数を続けて記述すると、それぞれが連結して書かれたことになります。

#include <stdio.h>

int main(void)
{
	char str[] = "abcde"
	             "fghij";

	puts( str );
	
	return 0;
}

実行結果:

abcdefghij

このルールは、うっかり意図せずに連結してしまう可能性を持っています。 この機能を使わないとしても、連結されてしまうのだということは覚えておくべきです。

なお、次のような記述も許可されます。

#include <stdio.h>

#define STR1 "abcde"
#define STR2 "fghij"

int main(void)
{
	char str[] = STR1 STR2;

	puts( str );
	
	return 0;
}

実行結果:

abcdefghij

通常の文字列定数と、ワイド文字列定数(第47章参照)との連結については、 C95規格の時点では未定義となっています。

C99 (通常の文字列定数と、ワイド文字列定数との連結)

C99 では、通常の文字列定数と、ワイド文字列の定数(第47章参照)との連結結果は、 両者を合体させたワイド文字列定数になることが規定されました。

VisualC++ 2013/2015/2017 では、この規定には対応していません。 Xcode 8.3.3 は対応しています。

#include <stdio.h>
#include <wchar.h>

int main(void)
{
	const wchar_t* const str = "abc" L"あいうえお";

	wprintf( L"%ls\n", str );
	
	return 0;
}

実行結果:

abcあいうえお


練習問題

問題@ 次のプログラムを、できるだけ短く書き直して下さい。

#include <stdio.h>

int main(void)
{
	int num1 = 10;
	int num2 = 20;
	int num3 = 30;
	
	printf( "%d %d %d\n", num1, num2, num3 );

	num1 = num3;
	num2 = num3;
	
	printf( "%d %d %d\n", num1, num2, num3 );

	return 0;
}

問題A 次のプログラムを、条件演算子を使って書き直して下さい。

#include <stdio.h>

int main(void)
{
	int num = 90;

	if( num < 100 ){
		printf( "100未満\n" );
	}
	else{
		printf( "100以上\n" );
	}
	
	return 0;
}

問題B 次のプログラムを、複合代入演算子を使って書き直して下さい。

#include <stdio.h>

int main(void)
{
	int num = 15;
	int num2 = 5;
	int num3 = 30;

	num = num - 10;
	num2 = num2 + (num * 4);
	num3 = num3 % (num2 - 5);
	
	printf( "%d %d %d\n", num, num2, num3 );
	
	return 0;
}

問題C 10文字の文字列 "abcdefghij" があり、先頭と末尾の両方から 1文字ずつを取り出して出力するプログラムを書いて下さい。 ただし、カンマ演算子をうまく使って下さい。
例として、"abcde" と入力された場合、次のように出力されるようにして下さい。

a e
b d
c c
d b
e a


解答ページはこちら

参考リンク

更新履歴

'2017/7/30 clang 3.7 (Xcode 7.3) を、Xcode 8.3.3 に置き換え。

'2017/3/25 VisualC++ 2017 に対応。

'2016/10/15 clang の対応バージョンを 3.7 に更新。

'2015/10/12 clang の対応バージョンを 3.4 に更新。

'2015/9/5 VisualC++ 2012 の対応終了。

'2015/8/18 VisualC++ 2010 の対応終了。

'2015/8/15 VisualC++ 2015 に対応。

'2014/10/18 clang 3.2 に対応。

'2014/2/1 VisualC++ 2013 に対応。

'2014/1/25 「C99 (通常の文字列定数と、ワイド文字列定数との連結)」の項のサンプルプログラムを修正。

'2014/1/14 VisualC++ 2008 の対応終了。

'2014/1/11 clang 3.0 に対応。

'2013/4/20 「C99 (通常の文字列定数と、ワイド文字列定数との連結)」の項を追加。

'2010/9/3 問題Cの表示例が、問題の解答そのものになってしまっていたのを修正。

'2010/4/25 「カンマ演算子」のサンプルプログラムの誤りを修正。

'2009/9/2 新規作成。



前の章へ

次の章へ

C言語編のトップページへ

Programming Place Plus のトップページへ