C言語 チートシート

# 各チートシートへのリンク

[**入力**](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#入力)　`scanf("%d", &num);`　
[**出力**](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#出力)　`printf("%d\n", num);`

[if文](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#if文)　`if (1) {}`
[switch文](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#switch文)　`switch (num) {}`
[for文](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#for文)　`for (int i; i < num; i++) {}`
[while文](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#while文)　`while (1) {}`

<!--　( [break文](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#break文)　`break;`　[continue文](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#continue文)　`continue;` )-->
 
[数字](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#数字)　`int num = 0;` `float num = 0;`　
[文字](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#文字)　`char str = 'A';`
[**文字列**](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#文字列)　`char str[] = "hoge";` `sizeof(str) / sizeof(str)`
　( [文字列のコピー](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#文字列のコピー)　`strcpy(source_src, copy_str);` )
[**配列**](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#配列)　`int nums[] = {0, 1, 2};` `sizeof(nums) / sizeof(nums[0])`
　( [配列のコピー](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#配列のコピー)　`memcpy(copy_list, source_list, sizeof(list));` )

[**ポインタ**](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#ポインタ)

[**構造体**](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#構造体)　`struct <tag_name> {};`　`typedef struct {} <type_name>;`
[**共用体**](https://qiita.com/ysys_Ba/items/934a6e35faf3b7ed50b7#共用体)　`union <tag_name> {};`　`typedef union {} <type_name>;`

( [Python](https://qiita.com/ysys_Ba/items/d27282b888abbd1f43e7) )

# そもそもこのページは何？

ysys (@ysys_Ba) のためのチートシート
チートシートとしての機能性のために、ページと各章の最初にリンクを列挙しています
リンクからチートシートすべてに飛べるようになっているので、このページをブックマークしておけばいつでもすぐに参照できます（宣伝）

# チートシートについて

自分以外の人の参照性は基本的に考慮していませんが、もしそれでも参照したいという方がいれば自由に使ってください
チートシートではありますが、C言語は初心者ですしページがスカスカすぎるのも微妙なので、かなり基本的なことから記載されています（♰完全に理解♰したら、その項目は消すなりページの最後の方に移すなりする予定です）
ただ、あくまでもチートシートなのでまともな解説はなく不備も多々あります

# チートシート

## 入力

```C:input.c
#include <stdio.h>

int main(void){
    int num;
    printf("input >> ");

    // ここで入力
    scanf("%d", &num);
    
    printf("%d\n", num);
    return 0;
}
```

先に変数を定義しておいて、`scanf()` で変数に代入する
入力の型に応じて特殊文字 ( `%d` の部分 ) を `%c` とか `%s` とかに変更

|型|特殊文字|
|---|---|
|整数 ( int )|%d|
|実数 ( float )|%f|
|16進数|%x|
|文字 ( char )|%c|
|文字列 ( char )|%s|
|ポインタ|%p|

:::note warn
引数は変数名ではなく変数のアドレスであるため、アンパサンド `&` が必要であることに注意
( 文字列など変数名のみで変数のアドレスとなる場合、アンパサンド `&` は不要 )
:::

```C:input.c
#include <stdio.h>

int main(void){
    char str[100];
    printf("input >> ");
    
    // ここで入力
    scanf("%s", str);
    
    printf("%s\n", str);
    return 0;
}
```

## 出力

```C:output.c
#include <stdio.h>

int main(void) {
    int num = 334;

    // ここで入力
    printf("output >> %d\n", num);

    return 0;
}
```

`printf()` で文字列の中の指定した箇所に変数を代入して出力
入力とは異なり、引数は変数名で良い ( 文字列などもOK )

|型|特殊文字|出力形式|特殊文字|
|---|---|---|---|
|整数 ( int )|%d|10桁になるよう左から0詰め|%010d|
|||10桁になるよう右揃え|%10d|
|||10桁になるよう左揃え|%-10d|
|実数 ( float )|%f|小数点以下10桁|%.10f|
|16進数|%x|4バイト ( 8桁 ) 表記|"0x%08x"|
|文字 ( char )|%c|||
|文字列 ( char )|%s|10文字になるよう右揃え|%10s|
|||10文字になるよう左揃え|%-10s|
|ポインタ|%p|||

## if文

```C:if.c
#include <stdio.h>

int main(void) {
    int num;
    printf("input >> ");
    scanf("%d", &num);
    
    if (0 < num) {
        printf("minus");
    }
    else if (num == 0) {
        printf("zero");
    }
    else {
        printf("plus");
    }
}
```

ちょっと表記が違うだけで Python とほぼ同じ

## switch文

```C:switch.c
#include <stdio.h>

int main(void){
    int num;
    printf("input >> ");
    scanf("%d", &num);

    switch (num) {
        case 0:
            printf("zero");
            break;
        default:
            printf("%d", num);
            break;
    }
    return 0;
}
```

`case <値>:` で分岐させる ( セミコロン `;` ではなくコロン `:` )

:::note warn
`break;` を忘れると次の case に入ってしまうので、忘れないよう注意
:::

## for文

```C:for.c
#include <stdio.h>

int main(void){
    int nums[] = {0, 1, 2, 3, 4};

    for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {
        printf("%d\n", nums[i]);
    }
    
    return 0;
}
```

`for (<ループ前に実行する文>; <ループを続ける条件>; <１ループごとに実行する文>) {}`

for ループを指定回数回したい場合は以下のように書けばよい
`for (<カウンタを定義>; <カウンタが閾値未満>; <カウンタをインクリメント>) {}`

Python と異なり、ループを続ける条件を明示的に記すため、while文と似た感覚で使える
なおループを続ける条件を書かない場合は、Python の `while True:` と同じ無限ループとなる

## while文

```C:while.c
#include <stdio.h>

int main(void){
    int num = 0;

    while (num <= 10) {
        // ここでループを抜けるか判定
        printf("%d\n", num);
        num++;
    }
    
    return 0;
}
```

ちょっと表記が違うだけで Python とほぼ同じ
通常のwhile文では、ループ開始時にループを抜けるかの判定がある

```C:do while.c
#include <stdio.h>

int main(void){
    int num = 0;

    do {
        printf("%d\n", num);
        num++;
        // ここでループを抜けるか判定
    } while ( num < 0 );
    
    return 0;
}
```

do while文では、ループ終了時にループを抜けるかの判定がある ( 従って、条件式を満たさない場合も **1 回はループする** )

```C:while true.c
#include <stdio.h>

int main(void){
    int num = 0;

    while (1) {
        printf("%d\n", num);
        num++;
        if (num == 10) {
            break;
        }
    }
    
    return 0;
}
```

C言語では `true` をそのまま条件式として使えないため、代わりに `1` を使うことで無限ループを実装できる

## 数字

そのうち書く（多分）

## 文字

:::note warn
文字にはシングルクオーテーション `''` 、文字列にはダブルクオーテーション `""` を使う
:::

## 文字列

```C:string.c
#include <stdio.h>

int main() {
    char str[100] = "hoge";
    printf("%c\n", str[1]);

    str[1] = 'u';
    printf("%s\n", str);

    printf("%d\n", sizeof(str));

    return 0;
}
```

```C:result
>> o
>> huge
>> 100
```

`char <変数名>[<文字数>] = <文字列>;` が基本
文字数、文字列のいずれかは省略可能

`sizeof()` で ( 宣言時に確保した ) 文字数が分かる

`<変数名>[n]` で n 番目の文字を抽出できる ( **抽出した文字は文字列ではないことに注意** )

### 文字列のコピー

```C:string.c
#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "hoge";
    char str_copy[100];

    strcpy(str_copy, str);

    printf("%s\n", str_copy);
    return 0;
}
```

配列を別の配列にコピーする場合は、for文で値を 1 つずつ代入するか、`strcpy()` を使う
`strcpy()` の引数 : `strcpy(<コピー元の文字列>, <コピー先の文字列>)`

:::note warn
`#include <string.h>` を忘れないように
:::

## 配列

### 1 次元配列

```C:list.c
#include <stdio.h>

int main(void){

    // ここで配列を宣言
    int nums[5] = {0, 1, 2, 3, 4};

    for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {
        printf("%d\n", nums[i]);
    }    
    return 0;
}
```

`<要素の型> <配列名>[<要素数>] = <各要素の初期値>;` が基本
`sizeof()` でbyte数が分かるため、`sizeof(<配列>) / sizeof(<要素>)` とすることで、要素数が分かる

```C:list.c
#include <stdio.h>

int main(void){

    /* OK */
    int nums[5] = {0, 1, 2, 3, 4};
    int nums[] = {0, 1, 2, 3, 4}; // 要素数なし
    int nums[5]; //　初期値なし

    /* NG */
    int nums[];

    return 0;
}
```

要素数、初期値のいずれかは省略可能（初期値なしの場合は後から要素の値を入れる）

### 多次元配列

```C:list.c
#include <stdio.h>

int main(void){

    // ここで配列を宣言
    char keypad[4][3] = {
        {'1', '2', '3'}, 
        {'4', '5', '6'}, 
        {'7', '8', '9'}, 
        {'*', '0', 'H'}};
        
    for (int i = 0; i < sizeof(keypad) / sizeof(keypad[0]); i++) {
        for (int j = 0; j < sizeof(keypad[0]) / sizeof(keypad[0][0]); j++) {
            printf("%c ", keypad[i][j]);
        }    
        printf("\n");
    }
    return 0;
}
```

### 配列のコピー

```C:list.c
#include <stdio.h>
#include <string.h>  // memcpyを使うために必要

int main(void) {
    int nums[5] = {0, 1, 2, 3, 4};
    int nums_copy[5];

    // ここでコピー
    memcpy(nums_copy, nums, sizeof(nums));

    for (int i = 0; i < sizeof(nums_copy) / sizeof(nums_copy[0]); i++) {
        printf("%d ", nums_copy[i]);
    }
    return 0;
}
```

配列を別の配列にコピーする場合は、for文で値を 1 つずつ代入するか、`memcpy()` を使う
`memcpy()` の引数 : `memcpy(<コピー先の先頭アドレス>, <コピー元の先頭アドレス>, <byte数>)`

:::note warn
`#include <string.h>` を忘れないように
:::

## ポインタ

```C:pointer.c
int main(void) {
    int num = 10;
    int *p = NULL; // NULLポインタの宣言

    // ここでポインタ変数にアドレスを代入
    p = &num;

    printf("%p : %d", p, *p);
}
```
```C:result
>>> 00000062589FFCB4 : 10
```

宣言時に`*` をつけることで、指定した型のポインタ変数となる
ポインタ変数を定義する場合、`*` を型名の後に付けて `<型名>* <変数名>` としても、変数名の前に付けて `<型名> *<変数名>` としてもよい ( 前者で同時に複数のポインタ変数を宣言しようとすると、2 つ目以降がポインタ変数にならないので注意 )

```mermaid
graph LR;
    A("int型の変数num を宣言") -."num のアドレス ＆num"..-> C("num のアドレス\n＆num を p に代入")
    B("int型のポインタ変数\n*pを宣言") ==> C
    C ==> D("p のアドレスを出力")
    C ==> E("p のアドレスにある値\n*p を出力")
```
変数名の前にアドレス演算子 `&` をつけることで、その変数のアドレスとなる

ポインタ変数を入出力する場合、特殊文字 `%p` を用いる
ポインタ変数に間接演算子 `*` をつけることで、ポインタ変数が示すアドレスに格納されている値となる

### 配列とポインタ

```C:pointer.c
#include <stdio.h>

int main(void){
    int nums[] = {0, 1, 2, 3, 4};

    for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {
        printf("%d\n", *(nums+i)); // printf("%d\n", nums[i]); と同じ
    }
    
    return 0;
}
```

配列の変数は、配列の先頭の要素のポインタであるため、そのアドレスを加算することで、インデックスを指定して要素を取り出せる

## 構造体

```C:struct.c
#include <stdio.h>

int main(void){
    
    struct Member {
        char name[100];
        int age;
    };
    
    struct Member ysys = {"ysys", 25};
    printf("%s %d\n", ysys.name, ysys.age);

    return 0;
}
```

`struct <タグ名> { <メンバリスト> };` で構造体を宣言できる
`struct <タグ名> <変数名> = <値>;` でその構造体の変数を定義できる

```C:struct.c
#include <stdio.h>

int main(void){

    /* typedefで型名を定義 */
    typedef struct {
        char address[100];
        int postal_code;
    } Mail;

    Mail imperial_palace = {"東京都千代田区千代田１", 100-0001};
    printf("%s %d\n", imperial_palace.address, imperial_palace.postal_code);

    return 0;
}
```

`typedef` で予め型名を定義しておくことで、新たな変数を定義するときに `struct` を書かなくて良くなる

```C:struct.c
#include <stdio.h>

int main(void){

    struct Member {
        char name[100];
        int age;
    } ysys = {"ysys", 25};

    struct Member *p = &ysys;

    printf("%s %d\n", p->name, (*p).age);

    return 0;
}
```

:::note warn
構造体に対してもポインタ変数を定義できる
構造体のポインタ変数から値に変換する場合は、間接演算子ではなく**アロー演算子 `->` を使う**
:::

## 共用体

```C:union.c
#include <stdio.h>

int main(void){

    union Member {
        char class;
        int id;
    };

    union Member ysys;
    ysys.class = 'A';
    printf("%c %d\n", ysys.class, ysys.id);

    return 0;
}
```

```C:output
>> A 65 // 'A' の文字コード 65 がidとして出力されている
```

`union <タグ名> { <メンバリスト> };` で共用体を宣言できる

:::note warn
共用体は構造体とは異なり、複数のメンバが同一のメモリに格納されるため、新たなメンバの値が格納される度に他のメンバの値も書き換えられる
:::

```C:union.c
#include <string.h>

int main(void){

    typedef union {
        long date;
        struct {
            short date;
            short year;
        } date_s;
    } Date;

    Date today;
    today.date = 0x20240613;
    printf("%x\n", today.date);
    printf("%04x %04x\n", today.date_s.year, today.date_s.date);

    return 0;
}
```

```C:output
>> 20240613  //  long型 : 4 byte
>> 2024 0613 // short型 : 2 byte x 2
```

構造体と同様に `typedef` で宣言できる

共用体のメンバに構造体を用いることで、他のメンバの値をメモリごとに区切って抽出することができる

:::note warn
リトルエンディアンのためメモリの格納順が逆になっていることに注意
:::