C/C++

●特徴 ●基本的な文法
C言語は記述の方法から、関数の集まりで構成されていると表現されます。
型 関数名(引数){
  ステートメント;
}

void main() {
  //プログラムの開始
  printf("Hello World!");
}
最初に実行されるのはmain()関数になるため、必ずこの関数が必要です。
main()関数内にて、さらに様々な関数を呼び出したり、条件分岐や繰り返し制御をしながらプログラムが作られていきます。
ステートメントの後には「;」が必要です。
制御構文(if,for,whileなど)は、処理するブロックを「[」、「]」で区切ります。

●コメント
//、/* */の部分はコメントとして、コンパイラは読み飛ばし何も処理をしません。

//1 行コメント

/*複数行コメント1
  複数行コメント2*/

●定数と数値表現
170 10進数
0252 8進数(頭に0をつける)
0xAA 16進数(頭に0xをつける)
0b10101010 2進数(頭に0bをつける)
10U 符号なし(末尾にUをつける)
20L long(末尾にLをつける)
30UL 符号なしlong(末尾にULをつける)
10.0 浮動小数点
2.4e5 240000.0(指数表記)
true、false 論理値(真と偽)
NULL ヌル0

●変数
変数とはメモリ内に値や文字列を保存しておく場所を示すラベルです。
使用前に必ず宣言をする必要があります。
関数や変数の名前は英数字、アンダースコア( _ )を使用することができます。
型 変数名
int val;
char a,b,c;
◆型指定子には主に以下のようなものがあります。
bool 真trueか偽false
int8_t、char 8ビットの整数 -128~127
uint8_t、unsigned char 8ビットの非負整数 0~255
int16_t、short 16ビットの整数 -32768~32767
uint16_t、unsigned short 16ビットの非負整数 0~65535
int32_t、int 32ビットの整数 -2147483648~214748364
uint32_t、unsigned int 32ビットの非負整数 0~4294967295
int64_t、long 64ビットの整数 -9223372036854775808~9223372036854775807
uint64_t、unsigned long 64ビットの非負整数 0~18446744073709551615
float 32ビット浮動小数点 3.4028235E+38~-3.4028235E+38
double 64ビット浮動小数点 2.225074e-308~1.797693e+308

sizeof()関数を使うことで変数や配列で使用されている領域がバイト数で分かります。
◆型の修飾子
const float pi = 3.14;  #読み込み専用で値を変更できません。
volatile char buf;  #コンパイラによる最適化を抑制する。
static int result;  #静的領域を割り当てられ値が保持されます。
void  #関数を定義する際に呼び出した側に値を返さないことを示す。
◆型変換(Cast) 異なる型へ値を変換します。計算時には一番精度が高いものに合わせて結果が出力されます。
int a=3;
int b=2;
float f;
f = a/b; 1.0が代入される
f = (float)a/b; 1.5が代入される

●文字列
文字列には終端を意味するNULL(0)が追加されるため、バッファを確保する場合などには注意が必要。
"A" 文字列と見なすため、0x41 + 0x00(文字列終端) のデータとなる。
'A' 1バイトのキャラクターとして、0x41のみとなる。
char str[] = "hello"; #キャラクタ配列として文字列を定義します。この場合 6バイトの領域が使用される。
char str[] = {'a', 'b', 'c', 0}; #文字列として扱う場合は最後の要素を0にする。
char* str = "abc"; #文字列をポインタで指定。
◆特殊文字(エスケープシーケンス)
'\r'、'\n'、'¥¥'、'¥?'、'¥''、'¥"'、'\071'、'\x1a'、'\0'
'\x1b'  //ESC  ACII文字(16進)
◆文字列関数
printf("%s %u %d %x", c, a, b, c);  //フォーマット指定子を使って文字列出力
sprintf(str, "%s %u %d %x", c, a, b, c);  //フォーマット指定子を使ってstrへ文字列代入(戻り値は生成した文字列の文字数)
sscanf(str, "%s %s %s", c1, c2, c3);  //strの文字列をフォーマット指定子に従って各変数へ代入(戻り値は変換ができた個数)
sscanf(str, "%[^,],%[^,],%[^,]", c1, c2, c3);  //カンマ区切り
strcpy(str, "abcd"); strcpy(str1, str2);  //文字列コピー
strncpy(str1, str2, 4);  //str1へstr2の先頭から4バイト分コピー
strncmp(str1, str2, 3);  //str1とstr2の先頭から3バイト比較
strlen(str);  //文字列の長さ
strcat(str1, str2);  //str1にstr2の内容を連結
◆フォーマット指定子
%c char   1文字 "%c"
%s char*   文字列 "%8s", "%-10s"
%d int, short   10進数 "%-2d","%03d"
%u unsigned int, unsigned short  符号なし10進数を "%2u","%02u"
%o int, short,unsigned int, unsigned short 8進数 "%06o","%03o"
%x int, short,unsigned int, unsigned short 16進数 "%04x"
%f float   実数 "%5.2f"
%e float   実数指数表示 "%5.3e"
%g float   実数を最適な形式で "%g"
%ld long   倍精度整数を10進 "%-10ld"
%lu unsigned long   符号なし倍精度整数 10進 "%10lu"
%lo long, unsigned long   倍精度整数 8進 "%12lo"
%lx long, unsigned long   倍精度整数 16進 "%08lx"
%lf double   倍精度実数 "%8.3lf"
%hd short   単精度整数 10進
◆文字列→数値変換
atoi("123"); atol("123456789"); atof("0.123");  //10進数文字列を数値変換。変換できない場合は0
strtol("123" , NULL, 16);  //第二引数には変換できた位置のポインタが 第三引数には変換時の基数(0の場合文字列に合わせ変換)します。他にもstrtodがある
unsigned int val;
sscanf("12", "%u", &val);  //フォーマット指定子にて10進数に変換
sscanf("1a", "%x", &val);  //16進数に変換
sscanf("1A", "%hhx", &val);  //1バイト16進数に変換
int r = sscanf("12A", "%hx", &val);  //2バイト16進数に変換。正常に変換できた場合、戻り値は 1 になる。
◆応用
▼ Stringクラス
▼ 区切り文字での分割

●配列
int array[5];  要素を5個持つ配列
byte ary[2][3];  2次元配列
array[0] = 2;  ひとつめの要素に代入
int pins[] = {2, 4, 8, 6};  int型で配列を作成し2,4,8,6を代入
sizeof(pins);  要素のバイト数
sizeof(ary) / sizeof(int);  aruの要素数を計算
memcpy(ary1, ary2, size);  配列ary1へary2のsizeバイト分コピー
memcpy(ary1+2, ary2, size);  配列ary1の3バイト目からary2のsizeバイト分コピー
memmove(ary1, ary2, 3);  配列ary1へary2のsizeバイト分コピー。コピー先とコピー元のメモリ領域が重複している場合にも対応
memset(ary, 'a', size);  配列aryの4バイト目から'a'をsizeバイト分セット

●ポインタ
int *a;  ポインタ変数作成(頭に*をつける)
&a  変数名の前にアンパサンド(&)をつけるとその変数のポインタを示す
int *point , var;
var = 123456;
po = &var;  // varのポインタを代入
int a = *po;  // poポインタのアドレス内容を変数aに代入(valの内容を代入)
char *strP = "ABC";  //文字列リテラルの先頭アドレス。書き換えは文字数を超えないよう注意が必要

●構造体
複数の変数を1つにまとめたもので、配列とは違いそれぞれの変数はデータ型が異なっても構いません。
struct [tag] { member-list } [declarators];  // 構造体を定義します
	tag - 構造体のタグ名を指定します(省略可)
	member-list - メンバを定義します
	declarators - 構造体変数を宣言します(省略可)
[struct] tag declarators;  // 構造体変数を宣言

struct st_meibo {
	char *name;
	int age;
}person1, person2;

person1.name = "suzuki";
person1.age = 15;
person2.name = "sato";
person2.age = 20;
struct st_meibo person3;  // リストに追加
person3.name = yamada";
person3.age = 21;
person1 = person3;  //構造体はそのまま代入が可能

●演算子
・算術演算子 + - * / %(余り) =(代入)
・複合演算子 ++ -- += -= *= /= &= |=
 i++ 評価して加算  ++i 加算して評価  i-- 評価して減算  --i 減算して評価
 i += 3 ⇒ i = i + 3
・比較演算子 == != < > <= >=
・ブール演算子 && || !
・ビット演算子 & | ^ ~ << >>
x &= 0b11111100; マスク(AND)
x |= 0b00000011; セット(OR)
z = x ^ y; 排他的論理和(XOR)
y = ~x; 否定(NOT)
y = x<<2; 左シフト y = x>>2; 右シフト
a = !a; 内容を反転させる

●制御文
if(x > 8){...} else {...}
for(int i=0; i<8; i++){...}
while(x < 8){...}
do{...} while(x < 8);
continue; ループは止めず以降の処理をスキップ
break; 処理を中止して抜ける
return x; 関数から抜けて値xを返す

goto label; ラベル位置へジャンプ 
label: 

switch(x){
case 1:
  break;
case 2:
  break;
default:
}

●プリプロセッサ
#include:別のファイルに記述された内容を読み込んで挿入します。
#include <ヘッダファイル名>  //ヘッダファイルのディレクトリからファイルを検索し挿入
#include "ファイル名" //カレントとヘッダファイルのディレクトリ両方からファイルを検索し挿入

#define:識別子の定義、マクロ定義などに使用します。
#define 識別子 値
#define マクロ名 置換文字列
#define size 16  //プログラム中にある識別子sizeを値16に置き換えます
#define add(A, B) A+B  //add(A, B)をA+Bに置き換えます

#undef:定義された識別子を未定義にします。
#undef 識別子

#ifdef、#ifndef:識別子が定義されていれば、#endifまでの範囲を処理します。定義されていなければ無視されます。
#ifdef 識別子
  処理;
#endif

#ifdef DEBUG
  Serial.println(data, HEX);  //変数dataを16進数で出力
#endif

・#if、#elif、#else、#endif:条件が真偽の状態によって処理します。
#if 条件1
  条件1が真の処理;
#elif 条件
  条件2が真の処理;
#else
  条件1、2が偽の処理;
#endif

#define test
#if defined(test)
  test定義されているので処理されます。
#else
  処理されません。
#endif

◆組み込みマクロ
コンパイラによって最初から定義されているマクロです。
__LINE__ 現在の行番号
__FILE__ コンパイルされているファイル名
__DATE__ コンパイル時の日付 ( 月/日/年 )
__TIME__ コンパイル時の時間 ( 時:分:秒 )

●名前空間
名前空間は、名前の重複を避けるために有効な手段になります。スコープ解決演算子と呼ばれる「::」で区切って記述します。
stdという名前空間に存在するcoutは、「std::cout」になります。
毎回指定するのは面倒なため、using宣言を使用します。
#include <iostream>
using namespace std;

int main()
{
    cout << "ABCDE" << endl;  //「std::」を省略できる
    getchar();
}

また、coutだけを省略する場合は
using std::cout;
と記述します。

●クラス、継承
構造体と似ていますが、メンバとして変数と関数の両方を含めることができるイメージです。
メンバ変数、メンバ関数は3種類のアクセス制限をかけることができます。
public:外部から自由にアクセス可、private:外部からアクセス不可、protected:子クラスからもアクセス可
継承は、親となるクラスの内容をそのまま引き継ぎ、新たな子クラスを作成します。
#include <iostream>
using namespace std;

// クラス宣言
class calc {
private:
    int start_num = 0;
public:
    int num = 1;  // プロパティ(初期値 1)
    void set() {  // メソッド
        start_num = num;
    }
    void increment() {
        num++;
    }
    int get() {
        return num;
    }
};

class calc_dec : public calc {  // calcクラス継承
public:
    void decrement() {
        num--;
    }
};

int main() {
    calc obj;  // インスタンス化
    obj.num = 2;
    obj.set();
    obj.increment();
    cout << obj.get() << endl;  // 値を出力 3

    calc_dec obj_dec;
    obj_dec.decrement();
    cout << obj_dec.get() << endl;  // 値を出力 0
}


ページトップへ戻る