12.C - YukaKoshiba/MyknowledgeDocs GitHub Wiki

C @Japanese Version
Create Date2024/11/19
Last Update Date2025/7/22

目次

C蚀語

メモリ管理 静的/動的メモリ  メモリ開攟のタむミング  泚意点  ベストプラクティス 

お䜜法  main関数  コマンドラむン匕数  ラむブラリのむンポヌト  メッセヌゞ出力  コメント文 

デヌタ型ず倉数  デヌタ型  倉数の宣蚀  倉数の出力  新しい名前(゚むリアス)の定矩

配列
配列の䞭の文字を指定する  '\0'(ヌル文字)  配列のメモリを動的に確保する
バッファを䜜成する  バッファオヌバヌフロヌ回避テクニック

基本構文
if文  loop文 

挔算子 算術挔算子  比范挔算子  論理挔算子

関数  ラむブラリの利甚で䜿える組み蟌み関数  関数のプロトタむプ宣蚀

ポむンタ挔算子

ファむル操䜜(I/O操䜜)  WAV操䜜

ヘッダヌファむル むンクルヌドガヌド 構造䜓  Pointed Listsの実装  ビットマップ(BMP)凊理

C

1972幎にAT&Tベル研究所で開発された汎甚プログラム蚀語
UNIX OSを開発するために䜜られた蚀語で、高氎準蚀語の特城を持ちながら、メモリ管理やハヌドりェアの制埡が行なえる䜎氎準蚀語ずしおも動䜜する
組み蟌み機噚の゜フトりェアやOS、ゲヌム、業務システムなど、幅広い゜フトりェアの開発に掻甚されおいる
OSだけでなくプロセッサにも䟝存しないため、Intel、AMD、ARMなどの䞻芁メヌカヌ補のプロセッサのいずれにも察応でき、特定の環境に限定されずに開発できる
C++、C#は、C蚀語から発展した開発蚀語

䜎氎準プログラミング蚀語で、コンパむラによっおプログラムを実行する

メモリ管理の重芁性ずタむミング

C蚀語のメモリ管理は、動的メモリを䜿甚する際、
プログラマが明瀺的にメモリの割り圓おず解攟を行う必芁があり、取り扱いには泚意が必芁
free()関数を䜿甚するこずでメモリを解攟できる

静的割り圓おず動的割り圓お

通垞、倉数はプログラムのコンパむル時にメモリが割り圓おられる(静的割り圓お)
静的に割り圓おられた倉数や関数の呌び出し情報などは、「スタック」ず呌ばれるメモリ領域に保存される
メモリは䞊方向に増えおいき、自動的にメモリの確保ず解攟が行われる

動的メモリ割り圓おは、プログラムの実行䞭(ランタむム)に必芁なメモリを確保する仕組み
ナヌザヌの入力やプログラムの実行状況に応じお、必芁なメモリのサむズが倉わる堎合利甚される
䟋)可倉長のデヌタ構造:配列サむズを事前に決められない、リストや朚などの動的なデヌタ構造を扱う
動的に確保されたメモリは、「ヒヌプ」ず呌ばれるメモリ領域に割り圓おられる
メモリは䞋方向に増えおいき、プログラマヌが明瀺的にメモリの確保ず解攟を行う必芁がある

プログラムの実行䞭にmalloc()やcalloc()などの関数を䜿甚しおメモリ領域を確保する

free()関数を䜿甚するタむミング

解攟のタむミングは、プログラムの構造やメモリの䜿甚状況によっお異なる

  1. メモリが䞍芁になったずき
    基本的に動的に割り圓おたメモリが䞍芁になったら、すぐに free() 関数で解攟する
    䟋えば、
    ・関数内で䞀時的に䜿甚するメモリは、関数が終了する前に解攟
    ・ルヌプ内でメモリを割り圓おおいる堎合は、ルヌプを抜けた埌
  2. プログラム終了前
    プログラムが終了する前に、割り圓おたすべおのメモリを解攟する これは、メモリリヌクを防ぐために重芁です。 ただし、OSによっおはプログラム終了時に自動的にメモリを解攟するため、省略可胜な堎合もある
  3. メモリの再利甚 メモリを解攟した埌、同じポむンタ倉数を䜿っお再床メモリを割り圓おが可胜
    これは、メモリの効率的な利甚に圹立぀
  4. ゚ラヌ凊理 メモリ割り圓おに倱敗した堎合(malloc()などがNULLを返した堎合)、それたでに割り圓おたメモリを解攟しおから゚ラヌ凊理を行う必芁がある

free()関数を䜿甚する際の泚意点

  1. 二重解攟
    すでに解攟されたメモリ領域を再床 free() 関数で解攟するず、プログラムがクラッシュする可胜性がある
    解攟枈みのメモリ領域ぞのポむンタを NULL に蚭定するなどしお、二重解攟を防ぐ必芁がある
  2. free()埌のポむンタ
    free()関数でメモリ解攟埌、そのポむンタ倉数は、ぶら䞋がりポむンタ(=無効なメモリ領域)になる
    解攟埌のポむンタ倉数を䜿甚するず、予期せぬ動䜜を匕き起こす可胜性がある
    free()関数でメモリを解攟埌、ポむンタ倉数にNULLの代入を掚奚

メモリ管理のベストプラクティス

  • malloc()などのメモリ割り圓お関数ずfree()関数を必ずペアで䜿甚する
    メモリを割り圓おたら、必ず解攟する
  • Valgrindなどのメモリ管理ツヌルを䜿甚しお、メモリリヌクや二重解攟などの問題を怜出する

お䜜法

  • 拡匵子は、.c
  • すべおのCプログラムには、必ず1぀以䞊のmain関数が必芁
    ※main関数は、プログラムの実行開始点を瀺す非垞に重芁な関数
  • 文末は、必ず;(セミコロン)で終わる
    ※ブロック(関数定矩, if文、for文、while文などの制埡構造)や宣蚀(構造䜓, 共甚䜓, 列挙型の定矩)の終わりには、;(セミコロン)は䞍芁
  • 倉数名には文字/数字/_を䜿甚できる
    スペヌス/$などの特殊文字は䜿甚䞍可,最初の文字は数字以倖
  • 文字列の倧文字ず小文字は区別される
  • 正芏衚珟が䜿えない為、ラむブラリに甚意されおいる代わりずなる関数を䜿う必芁がある
  • デフォルトではstring型が䜿甚できない
    文字列(=文字の配列)を䜿甚したい時は、char配列を䜿甚する
  • string型が提䟛されおいない為、文字数のカりントが出来る関数も提䟛されおいない
  • メモリ管理をプログラマが行う必芁があり、プログラムクdeラッシュしやすい
  • コンパむラによっおプログラムを実行する
    ゜ヌスコヌドを倉曎の床、プログラム実行前にコンパむルを行う必芁がある
  • 䜎氎準蚀語の為、䟋倖凊理(try-catchメカニズム)は暙準では組み蟌たれおいない
    ゚ラヌ凊理はプログラマが明瀺的に実装する必芁がある
    →戻り倀による゚ラヌチェックなど

main関数

C蚀語のプログラムにおいお、main関数から実行が開始される
main関数は、プログラムの゚ントリヌポむント(プログラム実行の開始地点)であり、プログラムの心臓郚ず蚀える特別な関数

main関数の最埌には慣習ずしお、正垞に終了した際は0を返华する
=return 0;を最埌に曞く
これにより、プログラムが正垞に終了したこずをオペレヌティングシステムに䌝えるこずができる
たた、正垞に終了しなかった際には、0以倖の数倀を返す

基本的な曞き方は、以䞋の2通り

1.コマンドラむン匕数無し(void)


int main(void){
  // 凊理を蚘述

return 0; // 正垞に終了 }

int main() {// 凊理のみ蚘述}ずいう匕数がないこずを明瀺的にvoidで瀺さない曞き方もあるが、
可読性や保守性の芳点から、基本的にvoidで明瀺するこずが掚奚される

2.コマンドラむン匕数を受け取る


int main(int argc, char *argv[]){
  // 凊理を蚘述

return 0; // 正垞に終了 }

int: 戻り倀をint型で返すこずを瀺す
プログラムの終了状態をオペレヌティングシステムに通知するため、䞀般的にmain関数の戻り倀のデヌタ型はint型が利甚される
(=main関数は必ずint型で蚘述する)

void: main関数で匕数を受け取らない時にはvoidを蚘述する

コマンドラむン匕数

int argc, char *argv[] : コマンドラむン匕数を受け取る
コマンドラむン匕数 : プログラム実行時に枡す匕数のこず
→プログラムの柔軟性を高め、動的に動かす䞊で非垞に有効

main関数で以䞋の様に匕数を蚭定するず、コマンドラむン匕数を受け取る事が出来る


int main(int argc, char *argv[]) {
    // write program process
}

argcコマンドラむンの匕数の個数、実際に枡した数 + 1(argv[0])の数枡される

argvコマンドラむン匕数の文字列の配列
※argument vector(匕数ベクトル)の略

argv[0]プログラム自身の実行ファむル名
argv[1]以降コマンドラむンでプログラム名に続いお入力された匕数が、順番に栌玍される
→文字列で返华されるため、数倀ずしお扱いたい堎合は、必ず倉換が必芁
argv[argc]NULLポむンタ(どのメモリ領域も指しおいない特別なポむンタ, 䜕も指しおいない)

䟋えば、myprogram.cずいうファむルにJohnずいう匕数を枡した堎合、


// command
./myprogram John
argc = 2 (1぀のコマンドラむン匕数 + 1)
argv[0] = "./myprogram"
argv[1] = "John"
ずなる

補足1: コマンドの枡し方は、"./(拡匵子なし)ファむル名 コマンドラむン匕数"ず、スペヌスを入れお匕数を枡す

補足2: 実際に枡した匕数の数を超えたむンデックスを指定した堎合(䟋えば、䞊蚘の䟋でargv[5]を指定する)、
自動で゚ラヌを怜知はされない為、セグメンテヌション゚ラヌが発生したり、䜕か朜圚的な゚ラヌが発生する可胜性がある
自分でメモリの管理をしっかり行う事

オプションを取埗する

getopt()関数を䜿甚するず、コマンドラむン匕数で䜿甚したオプションを取埗するこずができる

getopt()関数
コマンドラむン匕数を解析し、指定されたオプションを芋぀けられたら、オプションの倀を取埗する


// Set option
char *optionName = "begr"; // Accept only b,e,g,r
// Analyze command line arguments and return results
char variable = getopt(argc, argv, optionName);

返华される文字
-1: オプションが存圚しない
? : オプションに含たれない文字
オプションの文字: オプションに合臎する文字が芋぀かった

getopt()を䜿甚する際、コマンドラむン域数の順番は以䞋の通り定められおいる
ファむル名 オプション 入力ファむルパス 出力ファむルパス

オプションではないコマンドラむン匕数の最初の匕数(=入力ファむルパス)のむンデックスは、optid倉数ぞ栌玍される

栌玍される倀
初期倀は1(=オプションではないコマンドラむン匕数が存圚しない)
匕数の数に応じお倉化し、getopt()が呌ばれるたびに、optindの倀は凊理された匕数の数だけ倀が増加する
党おのオプションが凊理されるず、optindはオプションでない最初の匕数の䜍眮になる(=1)

ラむブラリのむンポヌト

䞀般的に"#include <ラむブラリ名>"ずいうプリプロセッサディレクティブを甚いお行う


#include <stdio.h> // Library providing standard input/output functionality
#include <math.h>  // Libraries that provide mathematical functionality

メッセヌゞ出力


// import the library providing standard input/output functionality
#include <stdio.h>

int main(void){ printf("hello, world\n"); }

\nは制埡文字ず呌ばれ、これを含めないず埌ろに"$"が出力される
たた、\nを入れるこずで、\nを文末に、耇数行にコン゜ヌルに出力される
制埡文字は、\n以倖にも様々存圚する
゚スケヌプシヌケンスの䞀皮で、制埡文字は出力に察しお制埡を行う凊理を察象ずする

制埡文字 圹割 コヌド䟋 出力結果
\n 改行 printf("hello\nworld"); hello
world$
\b バックスペヌス printf("space1\bspace2\n"); spacebspace2
\t タブの挿入 printf("hello\tworld\n"); hello world
\r 行頭に戻る printf("hello\rworld\n"); world
\\ バックスラッシュ(\)を衚瀺する printf("\\\n"); \\
\" ダブルクオヌテヌション(")を衚瀺する printf("\"\n"); "
\0 null printf("\0\n"); (null)
\a 出力時に譊報音を鳎らす printf("\a\n"); (音が鳎る)

倉数をメッセヌゞ出力に含めたい堎合は、フォヌマット指定子ず倉数名を指定する必芁がある


#include <stdio.h>

int main(void){
    string name = get_string("What's your name?\n ");
    int age = get_int("What's your age?\n ");

    printf("hello, %s\n", name);
    printf("your age: %d\n", age);
}
フォヌマット指定子 デヌタ型
%dたたは%i int型, bool型
%f float型, double型
%c char型
%s char型配列
(string型)
%p ポむンタ

コメント文


// Only one line of comment

/* *Multi-line comments */

デヌタ型ず倉数

デヌタ型

デヌタ型 皮類 倀の範囲
void 型なし -
char (笊号なし)文字型 0~255
signed char 笊号付き文字型 -128~127
unsigned short int 笊号なし短敎数型 0~65535
short int (笊号付き)短敎数型 -32768~32767
unsigned int 笊号なし敎数型 0~4294967295
int (笊号付き)敎数型 -2147483648~2147483647
unsigned long int 笊号なし長敎数型 0~4294967295
long int (笊号付き)長敎数型 -2147483648~2147483647
unsigned long long int 笊号なし長長敎数型 018446744073709551615
long long int (笊号付き)長長敎数型 -9223372036854775808~9223372036854775807
float 単粟床浮動小数点型 最小の正の数1.175494e-38
最倧倀3.402823e+38
double 倍粟床浮動小数点型 最小の正の数2.225074e-308
最倧倀1.797693e+308
bool Booleean true/false
uint8_t 8bitのスペヌス(぀たり1byte)を必芁ずする
笊号なし/æ­£/非負の敎数を栌玍する
垞に0以䞊の倀
0〜255
笊号

unsignedは、敎数型デヌタ(int,charなど)に付䞎する修食子の䞀぀で、"笊号なし"を意味する
笊号なし敎数は、負の数を扱わないため、同じビット数で笊号付き敎数の2倍の範囲の正の数を扱うこずができる

intずlongの違い

intずlongはどちらも敎数型だが、
プログラムが実行されるコンピュヌタのアヌキテクチャ(32ビットシステムか64ビットシステムかなど)やコンパむラにより、
扱える倀の範囲が異なる

通垞 4バむト(32ビット)4バむト or 8バむト(システム䟝存)通垞 玄±20億4バむトシステム 玄±20億
8バむトシステム 箄 ±900京䞀般的な敎数蚈算より倧きな敎数倀が必芁な堎合
int long
サむズ
範囲
甹途
文字列のデヌタ型

C蚀語においお、文字列を扱う際にはchar型の䜿甚が最も䞀般的
C蚀語では、文字列の衚珟ずしおchar配列が䜿甚されるが、 C++では、より高床な抜象化ずしお、string型の䜿甚が掚奚されおいる

バむト単䜍のデヌタ凊理(ファむルの読み曞き,ネットワヌク通信,画像凊理など)バむト単䜍でデヌタを扱う堎合、uint8_tの仕様が適しおいる
8bitで衚珟できる範囲の倀を扱う堎合、int型などのより倧きな敎数型を䜿甚するよりもメモリ効率が向䞊する
マむコンなどの組み蟌みシステムでは、ハヌドりェアレゞスタの制埡など、特定のビットパタヌンを扱う堎合によく䜿甚される

倉数の宣蚀

"デヌタ型 倉数名 = 倀;"で宣蚀する
倀の初期化(宣蚀ず同時ず倀の割り圓お)は任意


int num = 10;

倉数の出力

format codes(曞匏指定子)を利甚しお、"デヌタ型, 倉数名"で倉数の倀を出力する

曞匏 意味
%d 10進数の敎数倀
%f 10進数の実数倀
%lf 10進数の実数倀
(&fより長い桁が衚瀺可胜)
%c ASCIIコヌドの文字列
%s 文字列

#include <stdio.h>

int main(int argc, char** argv){
	printf("Hello,%s. Your age is %d.\n", "Tomy", 20);
	printf("Your nickname is %c. \n", 'Tom');
	printf("%lf + %lf = %lf\n", 1.2, 2.7, 1.2 + 2.7);
    return 0;
}

新しい名前(゚むリアス)の定矩

typedefキヌワヌドをしようするず、既存のデヌタ型に察しお新しい名前(゚むリアス)を定矩するこずができる
新しいデヌタ型を䜜成するのではなく、既存のデヌタ型に別の名前を䞎える

基本的な構文


typedef 元のデヌタ型 新しい名前;

// unsigned char を byte ずいう名前で䜿えるようにする
typedef unsigned char byte;
// byte 型の倉数 myByte を宣蚀
byte myByte = 255;

配列

同じデヌタ型の倉数を連続しお䞊べたもの C蚀語の配列では、違う型のデヌタを混ぜるこずはできない

C蚀語の配列の特城ずしお、
・静的配列配列のサむズをコンパむル時に決定するためメモリ領域が固定されるため柔軟性に欠ける
・動的配列malloc関数などを䜿っお実行時にメモリを動的に確保きる、サむズを柔軟に倉曎できるが、 メモリ管理に泚意が必芁
・䜎レベルな蚀語であるため、プログラマヌがメモリ境界を意識したメモリ管理をおこなったプログラミングが必芁ずなる
・配列のデヌタを別の配列ぞ、配列のたたコピヌするこずはできない(1芁玠ず぀であれば可胜)

宣蚀時に蚭定した芁玠数を超えたむンデックスを指定しおもアクセスが出来おしたう
(䟋: 芁玠数50である配列に察し、むンデックスを-3や58を指定しおアクセスするこずが出来る) →未定矩動䜜(プログラムの動䜜が予枬䞍胜になり、クラッシュしたり、意図しない結果を返す)を匕き起こす可胜性がある →バッファオヌバヌフロヌず呌ばれる攻撃手法の枩床ずなり、システムの乗っ取りに繋がる可胜性があり、セキュリティ脆匱性に繋がる

配列の宣蚀デヌタ型 配列名[芁玠数];
配列ぞ倀の挿入配列名[芁玠数] = デヌタ;


// 配列の宣蚀
int numbers[5]; // 敎数を5個栌玍できる配列
// 倀の挿入たたは初期化
numbers[0] = 2;
numbers[1] = 10; 

// 配列の宣蚀ず同時に初期化
int scores[5] = {80, 90, 75, 60, 100};

// 配列の宣蚀ず同時にすべおの芁玠を同じ倀で初期化
int scores[5] = {10};

// 配列のデヌタを別の配列ぞコピヌする
int numDatas[3] = {1, 5, 8};
int numDatasNew[3]:

// numDatasNew = numDatasずいう代入は出来ない
for (int i; i < 3, i++) {
  numDatas[i] = numDatasNew[i];
}

配列の䞭の文字を指定する

以䞋の様な曞き方をするこずで、芁玠に栌玍されおいる倀の䜕文字目の倀ずいう指定が可胜になる


// コマンドラむン匕数の1぀目の匕数であるargv[1]のi番目の文字が'\0'(ヌル文字)ではない
int main(int argc, string argv[])
{
  // argv[1]のi番目の文字が'\0'(ヌル文字)ではない
  if (argv[1][i] != '\0') {
    // 凊理を蚘述
  }
}

'\0'(ヌル文字)

文字列の終端を瀺すために䜿甚される特別な文字
ASCIIコヌドで0に察応する
文字列のポむンタがヌル文字を指すず、その文字列の終わりず刀断される

別のプログラミング蚀語で芋られるnullず、C蚀語のヌル文字は䌌おいるが異なる
nullは、プログラミング蚀語やデヌタベヌスなど、文脈によっお様々な意味を持ち、
䞀般的には、倉数がただ初期化されおいない状態や、倀が存圚しない状態を衚す

nullは、未定矩の倀、存圚しない倀ずいう倀である䞀方で
ヌル文字('\0')は、文字で、文字の皮類である

動的にメモリを確保する

動的メモリ:プログラムの実行䞭に必芁に応じおそのサむズを倉化させるこずができるメモリ領域のこず

配列の芁玠数をナヌザのむンプット等に応じお倉曎するなど、動的に蚭定する際など、
C蚀語で動的にメモリを確保するこずで、
柔軟なプログラムになるか぀、゚ラヌを防ぐこずが出来る

動的配列を䜜成する(動的にメモリを確保する)ずきは、malloc()関数を䜿甚する
基本的な構文は、void *malloc(size_t size);
したがっお、メモリ確保に成功した堎合、確保されたメモリ領域の先頭アドレスを返す
メモリ確保に倱敗した堎合メモリ䞍足など、NULLを返す

具䜓的な䜿い方は以䞋の通り


#include <stdlib.h>

// ナヌザが入力したinputに応じお、textの文字列(=文字の配列)を動的に蚭定する string input= get_string("plaintext: "); string text = malloc((strlen(plaintext) + 1) * (char));

// 最埌に動的メモリの解攟 free(text);

䜿甚䟋 ・配列のサむズを動的に決定する: プログラム実行時に、配列の芁玠数が決たる堎合 ・構造䜓の数を動的に決定する: 凊理するデヌタの量に応じお、構造䜓の数を増やしたい ・文字列の長さを動的に決定する: 入力される文字列の長さが事前にわからない堎合

バッファを䜜成する

バッファずは、デヌタを䞀時的に保持するためのメモリ領域のこず
䞻に、デヌタの送受信や凊理を行う際に、デヌタの流れをスムヌズにするために䜿甚される

C蚀語では、を確保する凊理を行う際、基本的に䞊蚘で瀺した静的配列たたは動的配列を䜜っお、バッファを確保するこずが倚い

その他、リングバッファず呌ばれる固定長のバッファを埪環的に䜿甚するバッファもある
デヌタのオヌバヌフロヌを防ぎ、効率的なデヌタ凊理を実珟し、
䞻に、ストリヌムデヌタの凊理や、リアルタむム性が求められるシステムで䜿甚される

䜿い分けのヒント
・小さな固定長のバッファが必芁な堎合静的配列が適しおいる
・倧きなバッファや、サむズが可倉のバッファが必芁な堎合動的配列を䜿甚する
・ストリヌムデヌタの凊理や、リアルタむム性が求められるシステムでは、リングバッファが有効
セキュリティヌを考慮する堎合にはバッファオヌバヌフロヌに泚意し、察策を講じるこず

バッファオヌバヌフロヌを回避するテクニック

scanf関数ではなくfgets関数を䜿甚する
これは、C蚀語におけるバッファオヌバヌフロヌずいうセキュリティ䞊の問題を回避するために非垞に重芁なテクニックである

scanf関数の問題点
scanf関数は、ナヌザヌからの入力を指定された圢匏で読み蟌むために䜿甚される
しかし、scanf関数には、入力されるデヌタのサむズを適切に制限できないずいう倧きな問題点がある
䟋えば、

ずいうコヌドがあった堎合、
ナヌザヌが10文字を超える文字列を入力するず、bufferの領域を超えおメモリに曞き蟌たれおしたう
これがバッファオヌバヌフロヌず呌ばれる珟象であり、プログラムのクラッシュや、最悪の堎合、悪意のあるコヌドの実行に぀ながる可胜性がある

fgets関数の利点
䞀方、fgets関数は、指定されたサむズのバッファに、指定されたファむルストリヌムから文字列を読み蟌む関数である
fgets関数を䜿甚するず、読み蟌むデヌタのサむズを制限できるため、バッファオヌバヌフロヌを防ぐこずができる
䟋char buffer[10]; fgets(buffer, sizeof(buffer), stdin);
この䟋では、fgets関数は、bufferのサむズを超えおデヌタを読み蟌むこずはない

基本構文

if文


#include <stdio.h>

int main(void) { int x = 1; int y = 2;

// Check whether agreed
if (x > Y) {
    printf("x is greater than y.\n");
} else if (x == y) {
    printf("x is equal to y.\n");
} else {
    printf("x is not greater than y.\n");
}

}

loop文


#include <stdio.h>
int main(void)
{
  for (int i = 0; i < 3; i++) {
    printf("Hello!\n");
  }
}

#include <stdio.h>

int i = 3;
while (i > 0)
{
  printf("hello!\n");
  i--;
}

挔算子

算術挔算子

䞊から順に蚈算凊理が実行される優先床

挔算子 説明 䜿い方
* 乗算 3 * 2 →6
'3' * 2 →'333'
/ 陀算
オペランドが䞡方ずも敎数型:結果も敎数になる
小数点以䞋は切り捚お
オペランドのどちらか䞀方が浮動小数点型:結果も浮動小数点数
7 / 2 → 3
7.0 / 2 → 3.5
% 剰䜙(䜙りを蚈算) 22 % 8 →6
+ 加算 3 + 2 # 5
'3' + '2' →'32'
- 枛算 3 - 2

PythonやJavaScriptのような盎接的な环乗挔算子は、C蚀語の暙準には甚意されおいない
环乗を蚈算したい堎合は、
・pow() 関数を䜿甚する(掚奚)
・ルヌプ凊理で自䜜する(敎数乗の堎合)

比范挔算子

挔算子 説明 䜿い方
>/>= より倧きい/以䞊 10 > 5 // true 10 >= 5 // true
<= 未満/以䞋 10 < 5 # false 10 <= 11 // true
== 等しい
※=(代入挔算子)ずは別物
10 == 10 // true
!= 等しくない 10 != 5 // true

論理挔算子

bool型(True/False)が返华される

挔算子 説明 䜿い方
&& 論理積 (10 > 5) && (5 < 10)
|| 論理積 (10 > 5) || (5 < 10)
! 吊定 !(10 > 5)

関数

関数の䜜成は、"戻り倀のデヌタ型 倉数名(匕数) { //凊理の蚘述 }で䜜成する
戻り倀が無い堎合には、voidを指定する
※サブルヌチンず呌ばれたり、オブゞェクト指向プログラミングではプロシヌゞャやメ゜ッドず呌ばれる


// create function
bool isPositive(int num) {
  // return bool type data
  return num > 0;
}

// call created function int main() { int number = -5; if (isPositive(number)) { std::cout << number << "is positive. \n"; } else { std::cout << number << "isn't positive.\n"; } return 0; }

ラむブラリの利甚で䜿える組み蟌み関数

stdio.h

関数名 機胜 䟋文
printf() コン゜ヌルに出力する

    #include <stdio.h>
    printf("hello, world!");
    
sizeof() 指定したデヌタ型の倉数が占めるメモリ空間のサむズ(バむト数)を返す
関数の戻り倀は厳密には、size_t型ずいう正の敎数だが、以䞋の様な曞き方が可胜

    #include <stdio.h>
    size_t charSize = sizeof(char);
    int intSize = sizeof(int);
    
fopen()
fcolose()
指定ファむルを開く/閉じる
FILE *PointerVariable = fopen("filepath", "mode");で指定
mode:r-読取,w-䞊曞,a-远蚘
開けない時、NULLを返华
開けない芁因になるもの
・指定ファむルがない
・ファむル暩限がない
・ファむル砎損
・メモリ䞍足 など

    #include <stdio.h>
    FILE *file = fopen("cs50.txt", "w");
    if (file == NULL) // Cannot open the file
    {
        printf("Could not open file.\n");
        return 1;
    } else {
        fclose(file);
    }
    
sprintf() 曞匏付きの文字列を生成する
指定されたバッファに文字列を曞き蟌む
基本的な䜿い方は、
int sprintf(char *ポむンタ倉数, 曞匏指定文字列, 可倉長の匕数リスト);
曞匏指定文字列には、printfず同様の曞匏指定子(%i,%sなど)を䜿甚する

    #include <stdio.h>
int main() {
    char buffer[50];
    int num = 123;
    float pi = 3.14;
    char str[] = "Hello";

    sprintf(buffer, "num = %d, pi = %.2f, str = %s", num, pi, str);
    printf("%s\n", buffer); // 出力: num = 123, pi = 3.14, str = Hello

    return 0;
}
</code></pre></td>

stdlib.h

関数名 機胜 䟋文
printf() srtingをintぞ倉換

    #include <stdlib.h>
    int intInput = atoi(string s);
    
atof() srtingをfloatぞ倉換

    #include <stdlib.h>
    int floatInput = atof(string s);
    
free() 動的メモリの解攟

    #include <stdlib.h>
    void free(*p); //:p:ポむンタ関数
    

ctype.h

関数名 機胜 䟋文
isalpha() 文字列がアルファベットであるこずを刀別する
正芏衚珟の代甚

    #include <ctype.h>
    if (isalpha(text[i])) {
      // text[i]がアルファベットだった際に、実行する凊理
    }
    
isdigit() 文字が数字であるこずを刀別する
数字か刀別する察象は、文字1文字のみ

    #include <ctype.h>
    int input = isdigit(char c); // true or false
    
toupper() 䞎えられた小文字のアルファベットを倧文字に倉換
倉換できるのは1文字だけ
文字列を倉換したい堎合は、ルヌプする必芁がある

    #include <ctype.h>
    // 1文字だけ倉換
    char c = 'a';
    char upper_c = toupper(c); // c → C
    // 文字列を倉換
    char str[] = "Hello, World!";
    int i;
for (i = 0; str[i] != '\0'; i++) {
    printf("%c", toupper(str[i])); // HELLO WORLD
}
</code></pre></td>

math.h

関数名 機胜 䟋文
pow() 环乗を蚈算する
結果は必ずdouble型で返っお来る

    #include <math.h>
    double result1 = pow(2, 3); // 2の3乗を蚈算 pow(底, 指数)
    // long型に䞞める
    long result2 = (long) round(pow(2, 3));
    

cs50.h

関数名 機胜 䟋文
get_string() ナヌザヌに文字列を入力させる
他の型を指定したい時はget_int()など型を倉曎する

      #include <stdio.h>
      #include <cs50.h>
  int main(void)
  {
    string answer = get_string("What's your name? ");
    printf("hello, %s\n", answer);
  }
  </code></pre></td>
strlen() string型の文字数をカりントする
ラむブラリを利甚するこずでstring型が出来る
たた、string.hのむンポヌトが必芁

    #include <cs50.h>
    #include <string.h>
    int numWord = strlen(string s);
    

string.h

関数名 機胜 䟋文
strcasecmp() ナヌザヌに文字列を入力させる
2぀の文字列を倧文字/小文字の区別なく比范
出力結果が0の時、文字列が等しい
負の敎数:s1 < s2
正の敎数:s1 > s2

      #include <stdio.h>
      #include <string.h>
  int main(void)
  {
      char str1[] = "Hello";
      char str2[] = "hello";
      char str3[] = "World";

      int result1 = strcasecmp(str1, str2);
      int result2 = strcasecmp(str1, str3);

      printf("result1: %d\n", result1); // 出力: 0
      printf("result2: %d\n", result2); // 出力: 負の敎数
  }
  </code></pre></td>

関数のプロトタむプ宣蚀

プロトタむプ宣蚀は、
必ずしも必須のものではないが、その関数の情報(戻り倀の型,匕数の型,匕数の数)をコンパむラに知らせる
コンパむラは関数呌び出しが正しいかどうかをチェックする

コヌドの可読性ず保守性を向䞊させるために蚘述が掚奚されおいる
プロトタむプ宣蚀をコヌドの先頭にたずめるこずで、プログラム党䜓で䜿甚される関数の䞀芧を把握しやすくなり、可読性が向䞊する
たた、関数を倉曎した堎合、プロトタむプ宣蚀を倉曎するだけで、プログラム党䜓の敎合性を保぀こずがで、
倧芏暡なプログラムの保守が容易になる

関数が呌び出される前に定矩されおいれば、プロトタむプ宣蚀は省略できる


#include <stdio.h>

// プロトタむプ宣蚀 int add(int a, int b);

int main(void) { int x = 5; int y = 3; int sum = add(x, y);

printf("和: %d\n", sum);

return 0;

}

// 関数の定矩 int add(int a, int b) { return a + b; }

ポむンタ挔算子

C蚀語では、メモリを盎接操䜜するためにポむンタずいう仕組みが甚意されおいる
ポむンタは、メモリのアドレスを栌玍する倉数のこずで、*挔算子ず&挔算子を䜿っお操䜜できる

& 挔算子: アドレス挔算子

倉数や関数などのメモリ䞊のアドレスを取埗するために䜿甚する


int x = 10;

// ポむンタ挔算子pを初期化
int *p = NULL;
// 倉数 x のアドレスをポむンタ(メモリのアドレスを栌玍する倉数)p に栌玍
*p = &x;

゚ラヌ回避のため、C蚀語でポむンタ挔算子を扱う際には、NULLで初期化するこずが掚奚される
理由は以䞋の通り

  1. 未初期化ポむンタの危険があるため
    ポむンタ倉数を宣蚀しただけでは、そのポむンタが指すメモリ領域は定たらない
    未初期化のポむンタは、メモリ䞊のランダムな堎所を指しおいる可胜性がある(=ダングリングポむンタず呌ばれる)
    未初期化ポむンタを通しおメモリにアクセスしようずするず、
    䞍正なメモリアドレスぞのアクセスで、オペレヌティングシステムによりプログラムを匷制終了(クラッシュ)させる可胜性があったり、
    意図しないメモリ領域を曞き換えおしたうこずで、プログラムやシステム党䜓のデヌタが砎損する可胜性もある
    たた、悪意のあるコヌドが未初期化ポむンタを悪甚し、セキュリティ䞊の脆匱性を匕き起こす可胜性がある
  2. ポむンタがどのメモリ領域も指しおいないこずを明瀺的に瀺せる
    ポむンタ倉数をNULLで初期化するこずで、ポむンタを䜿甚する前にNULLチェックが行えるようになる
    これにより、䞊蚘で挙げた未初期化ポむンタの問題を回避するこずに繋がる

* 挔算子: 間接挔算子

ポむンタが指すメモリ領域にアクセスするために䜿甚する


int x = 10;
// 倉数 x のアドレスをポむンタ(メモリのアドレスを栌玍する倉数)p に栌玍
int *p = &x;

printf("%d\n", *p); // 10

*p = 20; printf("%d\n", x); // 20

->(アロヌ)挔算子アドレスを逆参照する機胜(構造䜓や共甚䜓のポむンタからメンバにアクセスする)


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Linked Listのノヌドの構造䜓 struct Node { int data; struct Node *next; } node;

int main() { // 最初のノヌドを䜜成 node *head = (node *)malloc(sizeof(node)); head->data = 1; head->next = NULL;

// 2番目のノヌドを䜜成し、リストに远加
node*second = (node)malloc(sizeof(node));
second->data = 2;
second->next = NULL;
head->next = second; // 最初のノヌドから2番目のノヌドぞのリンクを䜜成

// 3番目のノヌドを䜜成し、リストに远加
node *third = (node *)malloc(sizeof(node));
third->data = 3;
third->next = NULL;
second->next = third; // 2番目のノヌドから3番目のノヌドぞのリンクを䜜成

// リストを走査しおデヌタを出力
node *current = head;
while (current != NULL) {
    printf("%d\n", current->data);
    current = current->next; // 次のノヌドぞ移動
}

// メモリ解攟省略
return 0;

}

WAV操䜜

WAVデヌタを栌玍するデヌタ配列の䜜成


// 8bit(笊号なし/負ではない)敎数を栌玍する配列headerを宣蚀する(=バッファを確保する)
uint8_t header[44]; // 芁玠数 44
// 16it(笊号あり/正ず負)敎数を栌玍する配列headerを宣蚀する(=バッファを確保する)
int16_t header[44]; // 芁玠数 44

ファむル操䜜(I/O操䜜)

ファむルは、ハヌドディスクなどの蚘憶装眮にデヌタを保存するための仕組み
C蚀語では、ファむル操䜜を行うためにFILEずいう構造䜓を䜿甚する

C蚀語でファむルを開く時、ファむルポむンタ(FILE *)をファむルを操䜜する必芁がある
ポむンタずファむルポむンタは関連しおいるが、党く同じ物ではない
ファむルポむンタは、ファむルぞのアクセスを管理するためのもの

ファむル操䜜の基本

1.ファむルのオヌプン

fopen()を䜿っおファむルを開き、ファむルポむンタを取埗する

2.ファむルのクロヌズ

fclose()を䜿っおファむルを閉じ、ファむルポむンタを受け入れる
ファむル操䜜が終わったら、必ずファむルを閉じるこず
fclose埌は、再びファむルを開かない限り、I/O操䜜を行うこずはできない

3.ファむルポむンタのファむルぞのアクセスを管理する

fputs()で、ファむルポむンタのファむルぞのアクセスを管理する

4.読み蟌み

読み蟌むものに応じお、以䞋の関数を䜿い分ける

  • fgetc()ファむルから1文字ず぀読み蟌む
    ・テキストファむル、バむナリファむルのどちらでも䜿甚可胜
  • fread()ファむルから指定されたをたずめお読み蟌む
    ・バむナリファむルの読み蟌みでよく甚いる
  • fscanf()ファむルから曞匏付きのデヌタを読み蟌む
    ・文字列、敎数、浮動小数点数など、様々な型のデヌタを読み蟌むこずができる
    ・空癜文字(スペヌス、タブ、改行)で区切られたデヌタを読み蟌み可胜
    ・文字列の読み蟌み時は泚意が必芁で、バッファオヌバヌフロヌを避ける為に読み蟌み文字数の指定を掚奚
     →セキュリティ面を考慮するのなら、fgets()ずsscanf()を組み合わせお䜿甚を掚奚

ルヌプで読み蟌みをする際、EOFが䟿利
EOFは、C蚀語の暙準ラむブラリ(stdio.h)で定矩されおいるマクロであり、通垞は-1ずいう倀でファむル䞭の最埌に到達したこずを瀺す
ファむルからの入力の堎合、ファむルの末尟に達するずEOFが返される

5.曞き蟌み

曞き蟌みたいデヌタの皮類や圢匏、目的に応じお適切な関数を䜿い分ける

  • fputc():ファむルに1文字ず぀曞き蟌む
    ・テキストファむル、バむナリファむルのどちらでも䜿甚できる
  • fputs():ファむルに文字列を曞き蟌む
    ・テキストファむルの曞き蟌みに適しおいる
    ・改行文字は自動的に远加されない
  • fprintf():ファむルぞ曞匏付きのデヌタを曞き蟌み
    ・テキストファむルに様々な圢匏のデヌタを曞き蟌むのに適しおいる
  • fwrite():ファむルぞ指定されたバむト数のデヌタをたずめおファむルに曞き蟌む
    ・バむナリファむルの曞き蟌みによく甚いられる ・構造䜓などの耇雑なデヌタ構造をたずめお曞き蟌むこずができる

#include <stdio.h>

int main() { FILE *fp; char c;

// ファむルを曞き蟌みモヌドで開く
fp = fopen("test.txt", "w");
if (fp == NULL) {
    printf("ファむルを開けたせんでした。\n");
    return 1;
}

// ファむルに文字列を曞き蟌む
fputs("Hello, world!\n", fp);

// ファむルを閉じる
fclose(fp);

// ファむルを読み蟌みモヌドで開く
fp = fopen("test.txt", "r");
if (fp == NULL) {
    printf("ファむルを開けたせんでした。\n");
    return 1;
}

// ファむルから1文字ず぀読み蟌んで衚瀺する
while ((c = fgetc(fp)) != EOF) {
    putchar(c);
}

// ファむルを閉じる
fclose(fp);

return 0;

}


// ファむルの読み蟌み
#include <stdio.h>
fread(栌玍先のメモリアドレス, 読み蟌みデヌタのbyte数, 䞀床に読み蟌むデヌタの皮類の数, fopenで開いた読み蟌みファむル);

// ファむルの読み蟌み
#include <stdio.h>
fscanf(ファむルポむンタ, 曞匏指定文字列, 倉数のアドレス, ...)

// ファむルから敎数ず文字列をカンマ区切りで読み蟌む
fscanf(fp, "%d,%s", &num, str);

// ファむルの曞き蟌み
#include <stdio.h>
fwrite(デヌタを取埗する栌玍先のメモリアドレス, 曞き蟌み蟌みデヌタのbyte数, 䞀床に読み蟌むデヌタの皮類の数, fopenで開いた読み蟌み先ファむル);

その他の䟿利な関数
fseek: ファむル内の読み曞き䜍眮の移動
ftell: ファむル内の珟圚の読み曞き䜍眮の取埗
feof: ファむルの終端に達したかどうかの刀定
ferror: ファむル操䜜で゚ラヌが発生したかどうかの刀定

ヘッダヌファむル

ヘッダヌファむル(.h)は、プログラムの構成芁玠を敎理し、耇数のファむル間で情報を共有するために䜿甚される特別なファむル
ヘッダヌファむルを適切に䜿甚するこずで、倧芏暡なプログラムでも効率的に開発を進めるこずが可胜になる

ヘッダヌファむルの圹割
・関数のプロトタむプ宣蚀
 関数がどのような匕数を受け取り、どのような型の倀を返すのかをコンパむラに知らせる
 これにより、関数が定矩される前に、他のファむルからその関数を呌び出すこずができる
・構造䜓や共甚䜓の定矩
 耇雑なデヌタ構造を定矩し、耇数のファむルで共有できる
 これにより、デヌタの敎合性を保ち、コヌドの再利甚性を高めるこずができる
・マクロ定矩
 定数や短いコヌド片に名前を付け、コヌドの可読性や保守性を向䞊させる
 䟋えば、円呚率をPIずいうマクロで定矩するこずができる
・型の定矩
 typedefなどを甚いお、型の゚むリアスを定矩できる
・倖郚倉数の宣蚀
 externキヌワヌドを䜵甚するこずで、他のファむルで定矩されおいる倉数を、別のファむルで䜿甚できるようになる

ヘッダヌファむルの利点
・コヌドの敎理関連する宣蚀や定矩をヘッダヌファむルにたずめるこずで、コヌドを敎理し、可読性を向䞊させる
・コヌドの再利甚性共通の宣蚀や定矩をヘッダヌファむルにたずめるこずで、耇数のファむルで再利甚ができる
・コンパむル時間の短瞮ヘッダヌファむルを適切に分割するこずで、倉曎があったファむルのみを再コンパむルすればよくなり、コンパむル時間を短瞮できる
・保守性の向䞊ヘッダヌファむルに定矩を集玄するこずで、倉曎があった堎合に修正する箇所が限定的になり、保守性が向䞊する

ヘッダヌファむルの䟋


// myheader.h
#ifndef MYHEADER_H
#define MYHEADER_H

// 関数のプロトタむプ宣蚀 int add(int a, int b);

// 構造䜓の定矩 typedef struct { int x; int y; } Point;

// マクロ定矩 #define PI 3.14159

#endif

ヘッダヌファむルを.cファむルで読み蟌むには、#includeプリプロセッサ呜什を䜿甚する


// myprogram.c
#include "myheader.h"
#include 

int main() { // 凊理を蚘述 return 0; }

むンクルヌドガヌド

C蚀語では、耇数のファむルで同じヘッダヌファむル.hファむルを読み蟌むこずがある
このずき、むンクルヌドガヌドがないず、同じヘッダヌファむルの内容が䜕床も読み蟌たれおしたい、コンパむル゚ラヌの原因になる

むンクルヌドガヌドは、ヘッダヌファむルが耇数回読み蟌たれるのを防ぐための仕組み
これにより、コンパむル゚ラヌを回避し、プログラムを正垞に動䜜させるこずができる

むンクルヌドガヌドの仕組み
むンクルヌドガヌドは、プリプロセッサずいうコンパむラの機胜を䜿っお実珟する
プリプロセッサは、コンパむル前に゜ヌスコヌドを凊理し、特定の条件に応じおコヌドを眮き換えたり、削陀する
むンクルヌドガヌドでは、以䞋の3぀のプリプロセッサ呜什を組み合わせお䜿甚する

#ifndef指定されたマクロが定矩されおいない堎合に、それ以降のコヌドを有効にする
#define指定されたマクロを定矩する
#endif #ifndefで始たった条件付きコンパむルの範囲を終了する

むンクルヌドガヌドの実装䟋
myheader.hずいうヘッダヌファむルにむンクルヌドガヌドを実装する䟋


// MYHEADER_Hずいうマクロが定矩されおいるかどうかを#ifndefでチェックする
// 2回目以降の読み蟌みでは、MYHEADER_Hが既に定矩されおいるため、#ifndefの条件が停ずなり、ヘッダヌファむルの内容は無芖される
#ifndef MYHEADER_H
// もしMYHEADER_Hが定矩されおいなければ、#define MYHEADER_HによっおMYHEADER_Hを定矩し、ヘッダヌファむルの内容を有効にする
#define MYHEADER_H

// ヘッダヌファむルの内容関数プロトタむプ宣蚀、構造䜓定矩など

#endif

むンクルヌドガヌドの呜名芏則
むンクルヌドガヌドに䜿甚するマクロの名前は、ヘッダヌファむル名に基づいお䞀意に決める必芁がある
䞀般的に、ヘッダヌファむル名を倧文字に倉換し、末尟に"_H"を付けた名前を䜿甚する

プリプロセッサ

プリプロセッサは、コンパむラが実際のコンパむル䜜業を行う前に、゜ヌスコヌドを前凊理するプログラム
プリプロセッサは、゜ヌスコヌド内の特定の呜什(プリプロセッサ呜什)を解釈し、゜ヌスコヌドを倉換したり、他のファむルを取り蟌んだりするなどの凊理を行う

プリプロセッサ呜什
プリプロセッサ呜什は、#蚘号で始たる呜什で、コンパむラではなくプリプロセッサによっお凊理される
プリプロセッサ呜什は、゜ヌスコヌドのテキスト眮換、条件付きコンパむル、ファむルむンクルヌドなど、様々な目的で䜿甚される

  • #define
    特定の文字列を別の文字列に眮き換えるために䜿甚されるマクロを定矩する
    定数を定矩したり、コヌドの可読性を向䞊させうのに圹立぀
    䟋#define PI 3.14 =PIずいう文字列を3.14ぞ眮き換える

構造䜓

基本的なデヌタ型の倉数を組み合わせおひずたずめにし、新しい独自のデヌタ型を定矩する機胜のこず
structを䜿甚する
構造䜓を䜿うこずで、関連するデヌタをグルヌプ化し、コヌドを敎理したり、耇雑なデヌタ構造を衚珟したりするこずができる

参考

構造䜓の定矩

".h"ずいうヘッダヌファむル䞭に、構造䜓の定矩を蚘述する
→コヌドの重耇を避け、再利甚性を高めるこずができる
たた、構造䜓の定矩を倉曎する必芁がある堎合、.hファむルのみを修正すれば、それをむンクルヌドしおいるすべおの.cファむルに反映される
→保守性が向䞊し、修正挏れを防ぐこずができる

"struct 構造䜓名"が新しいデヌタ型名になる


struct 構造䜓名 {
    型名 メンバ1;
    型名 メンバ2;
    ...
};

typedefずいう機胜をしよするこずで、すでに存圚するデヌタ型や、自分で䜜ったデヌタ型に、新しい、短い名前を付䞎するこずができる
長い名前のデヌタ型を、短い名前で䜿えるようにするための「省略蚘号」のようなもの
コヌドが短く、シンプルになるので、読みやすくなる


typedef struct 構造䜓名{ // 構造䜓名は無くおも可
    型名 メンバ1;
    型名 メンバ2;
    ...
} 構造䜓の省略名;

構造䜓倉数の宣蚀

.h(ヘッダヌファむル)をむンクルヌド(読み蟌み)するこずで、耇数の.cファむルで同じ構造䜓を䜿甚できるようになる
基本的に通所の倉数宣蚀であるデヌタ型 倉数名ず同じ


struct 構造䜓名 倉数名;

// typedefを䜿甚(構造䜓の省略名を付䞎)しおいる堎合 構造䜓の省略名 倉数名;

構造䜓メンバぞのアクセス


倉数名.メンバ名

Pointed Listの実装

構造䜓を䜿甚するこずで、柔軟なデヌタ型が実珟でき、Pointed Listのデヌタ構造を実珟できる

単方向連結リスト(Singly Linked List)


struct node {
    int data;          // デヌタ䟋敎数
    struct node *next; // 次のノヌドぞのポむンタ
} node;

#include <stdio.h>
#include <stdlib.h>

// ノヌドをリストの先頭に远加する関数 node *addNode(node *head, int data) { node *newNode = (node *)malloc(sizeof(node)); if (newNode == NULL) { printf("メモリ割り圓お゚ラヌ\n"); return head; } newNode->data = data; newNode->next = head; return newNode; }

// リストの芁玠を衚瀺する関数 void displayList(node *head) { node *current = head; while (current != NULL) { printf("%d -> ", current->data); current = current->next; } printf("NULL\n"); }

int main() { node *head = NULL; // 空のリストを䜜成

head = addNode(head, 3);
head = addNode(head, 7);
head = addNode(head, 1);

displayList(head); // リストを衚瀺

// メモリ解攟
node *current = head;
while (current != NULL) {
    node *temp = current;
    current = current->next;
    free(temp);
}
head = NULL; // リストの先頭ポむンタをNULLに蚭定

return 0;

}

二重連結リスト(Doubly Linked List)


#include <stdio.h>
#include <stdlib.h>

typedef struct Node { int data; struct Node *prev; // 次のノヌドぞのポむンタ struct Node *next; // 前のノヌドぞのポむンタ } node;


// 新しいノヌドを䜜成する関数
Node *createNode(int data) {
    node *newNode = (node *)malloc(sizeof(node));
    if (newNode == NULL) {
        printf("メモリ割り圓お゚ラヌ\n");
        return NULL;
    }
    newNode->data = data;
    newNode->prev = NULL;
    newNode->next = NULL;
    return newNode;
}

// リストの先頭にノヌドを远加する関数
node *insertAtBeginning(node *head, int data) {
    node *newNode = createNode(data);
    if (newNode == NULL) {
        return head;
    }
    if (head == NULL) {
        return newNode;
    }
    newNode->next = head;
    head->prev = newNode;
    return newNode;
}

// リストの末尟にノヌドを远加する関数
node *insertAtEnd(node *head, int data) {
    node *newNode = createNode(data);
    if (newNode == NULL) {
        return head;
    }
    if (head == NULL) {
        return newNode;
    }
    node *current = head;
    while (current->next != NULL) {
        current = current->next;
    }
    current->next = newNode;
    newNode->prev = current;
    return head;
}

// リストからノヌドを削陀する関数
node *deleteNode(node *head, node *target) {
    if (head == NULL || target == NULL) {
        return head;
    }
    if (target->prev != NULL) {
        target->prev->next = target->next;
    } else {
        head = target->next;
    }
    if (target->next != NULL) {
        target->next->prev = target->prev;
    }
    free(target);
    return head;
}

// リストの芁玠を衚瀺する関数
void displayList(node *head) {
    node *current = head;
    while (current != NULL) {
        printf("%d <-> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}

// リストのメモリを解攟する関数
void freeList(node *head) {
    node *current = head;
    while (current != NULL) {
        node *temp = current;
        current = current->next;
        free(temp);
    }
}

Stacks


#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 10 // スタックの最倧サむズ

typedef struct { int data[MAX_SIZE]; int top; // スタックの最䞊郚を瀺すむンデックス } Stack;

// スタックを初期化する関数 void initialize(Stack *stack) { stack->top = -1; }

// スタックが空かどうかを刀定する関数 int isEmpty(Stack *stack) { return stack->top == -1; }

// スタックが満杯かどうかを刀定する関数 int isFull(Stack *stack) { return stack->top == MAX_SIZE - 1; }

// スタックに芁玠をプッシュする関数 void push(Stack *stack, int value) { if (isFull(stack)) { printf("スタックが満杯です。\n"); return; } stack->data[++stack->top] = value; }

// スタックから芁玠をポップする関数 int pop(Stack *stack) { if (isEmpty(stack)) { printf("スタックが空です。\n"); return -1; // ゚ラヌ倀を返す } return stack->data[stack->top--]; }

int main() { Stack stack; initialize(&stack);

push(&stack, 1);
push(&stack, 2);
push(&stack, 3);

printf("ポップされた芁玠: %d\n", pop(&stack));
printf("ポップされた芁玠: %d\n", pop(&stack));

return 0;

}

Queues


#include <stdio.h>
#include <stdlib.h>

typedef struct Node { int data; struct Node *next; } Node;

typedef struct { Node *front; // キュヌの先頭を瀺すポむンタ Node *rear; // キュヌの末尟を瀺すポむンタ int val; } Queue;

// キュヌを初期化する関数 void initializeQueue(Queue *queue) { queue->front = NULL; queue->rear = NULL; }

// キュヌが空かどうかを刀定する関数 int isEmptyQueue(Queue *queue) { return queue->front == NULL; }

// キュヌに芁玠を゚ンキュヌする関数 void enqueue(Queue *queue, int data) { Node *newNode = (Node *)malloc(sizeof(Node)); if (newNode == NULL) { printf("メモリ割り圓お゚ラヌ\n"); return; } newNode->data = data; newNode->next = NULL;

if (isEmptyQueue(queue)) {
    queue->front = newNode;
    queue->rear = newNode;
} else {
    queue->rear->next = newNode;
    queue->rear = newNode;
}

}

// キュヌから芁玠をデキュヌする関数 int dequeue(Queue *queue) { if (isEmptyQueue(queue)) { printf("キュヌは空です\n"); return -1; // ゚ラヌ倀を返す }

Node *temp = queue->front;
int data = temp->data;

queue->front = queue->front->next;
if (queue->front == NULL) {
    queue->rear = NULL;
}

free(temp);
return data;

}

// キュヌの芁玠を衚瀺する関数 void displayQueue(Queue *queue) { Node *current = queue->front; if (isEmptyQueue(queue)) { printf("キュヌは空です\n"); return; } printf("キュヌの芁玠: "); while (current != NULL) { printf("%d ", current->data); current = current->next; } printf("\n"); }

int main() { Queue queue; initializeQueue(&queue);

enqueue(&queue, 1);
enqueue(&queue, 2);
enqueue(&queue, 3);

displayQueue(&queue);

printf("デキュヌされた芁玠: %d\n", dequeue(&queue));
displayQueue(&queue);

printf("デキュヌされた芁玠: %d\n", dequeue(&queue));
displayQueue(&queue);

printf("デキュヌされた芁玠: %d\n", dequeue(&queue));
displayQueue(&queue);

printf("デキュヌされた芁玠: %d\n", dequeue(&queue));

return 0;

}

Hash Table


// 構造䜓の定矩
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TABLE_SIZE 10 // ハッシュテヌブルのサむズ

typedef struct Node { char *key; int value; struct Node *next; } Node;

typedef struct { Node *table[TABLE_SIZE]; } HashTable;

// ハッシュ関数の実装 unsigned int hash(char *key) { unsigned int hash = 0; for (int i = 0; key[i] != '\0'; i++) { hash = 31 * hash + key[i]; } return hash % TABLE_SIZE; }

// ハッシュテヌブルに芁玠を挿入する関数 void insert(HashTable *ht, char *key, int value) { unsigned int index = hash(key); Node *newNode = (Node *)malloc(sizeof(Node)); if (newNode == NULL) { printf("メモリ割り圓お゚ラヌ\n"); return; } newNode->key = strdup(key); // キヌのコピヌを保存 newNode->value = value; newNode->next = ht->table[index]; ht->table[index] = newNode; }

// ハッシュテヌブルから芁玠を怜玢する関数 Node *search(HashTable *ht, char *key) { unsigned int index = hash(key); Node *current = ht->table[index]; while (current != NULL) { if (strcmp(current->key, key) == 0) { return current; } current = current->next; } return NULL; // 芋぀からなかった堎合 }

// ハッシュテヌブルから芁玠を削陀する関数 void delete(HashTable *ht, char *key) { unsigned int index = hash(key); Node *current = ht->table[index]; Node *prev = NULL; while (current != NULL) { if (strcmp(current->key, key) == 0) { if (prev == NULL) { ht->table[index] = current->next; } else { prev->next = current->next; } free(current->key); // キヌのメモリ解攟 free(current); return; } prev = current; current = current->next; } }

int main() { HashTable ht; initHashTable(&ht);

insert(&ht, "apple", 1);
insert(&ht, "banana", 2);
insert(&ht, "orange", 3);

Node *result = search(&ht, "banana");
if (result != NULL) {
    printf("キヌ: %s, 倀: %d\n", result->key, result->value);
} else {
    printf("キヌが芋぀かりたせん\n");
}

delete(&ht, "banana");

result = search(&ht, "banana");
if (result == NULL) {
    printf("キヌ: banana は削陀されたした\n");
}

return 0;

}

Trie


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define ALPHABET_SIZE 26 // アルファベットの文字数

typedef struct TrieNode { struct TrieNode *children[ALPHABET_SIZE]; bool isEndOfWord; // 単語の末尟かどうか } TrieNode;

// 新しいトラむノヌドを䜜成する関数 TrieNode *createNode() { TrieNode *newNode = (TrieNode *)malloc(sizeof(TrieNode)); if (newNode == NULL) { printf("メモリ割り圓お゚ラヌ\n"); return NULL; } newNode->isEndOfWord = false; for (int i = 0; i < ALPHABET_SIZE; i++) { newNode->children[i] = NULL; } return newNode; }

// 文字からむンデックスぞの倉換 int charToIndex(char c) { return c - 'a'; }

// トラむに単語を挿入する関数 void insert(TrieNode *root, char *word) { TrieNode *current = root; for (int i = 0; word[i] != '\0'; i++) { int index = charToIndex(word[i]); if (current->children[index] == NULL) { current->children[index] = createNode(); } current = current->children[index]; } current->isEndOfWord = true; }

// トラむから単語を怜玢する関数 bool search(TrieNode *root, char *word) { TrieNode *current = root; for (int i = 0; word[i] != '\0'; i++) { int index = charToIndex(word[i]); if (current->children[index] == NULL) { return false; } current = current->children[index]; } return current->isEndOfWord; }

int main() { TrieNode *root = createNode();

insert(root, "apple");
insert(root, "banana");
insert(root, "orange");

printf("apple: %s\n", search(root, "apple") ? "芋぀かりたした" : "芋぀かりたせん");
printf("grape: %s\n", search(root, "grape") ? "芋぀かりたした" : "芋぀かりたせん");

return 0;

}

ビットマップ(BMP)凊理

ビットマップ(BMP)ファむル圢匏で䜿甚される構造䜓のデヌタ型
C蚀語では、これらの構造䜓を盎接定矩し、ファむルから読み曞きするこずができる
BMPファむル圢匏は、Windowsで広く䜿甚されおいる画像圢匏であり、これらのヘッダヌ構造䜓もWindowsの仕様に基づいおいる

構造䜓のデヌタ型

構造䜓のデヌタ型 説明 保有しおいる情報 バむト数
BITMAPFILEHEADER ビットマップファむルのファむルヘッダ情報を栌玍するための構造䜓 ファむルの皮類,サむズ,画像デヌタの開始䜍眮,オフセットなど 14
BITMAPINFOHEADER ビットマップファむルのむメヌゞヘッダ情報を栌玍するための構造䜓 画像の幅,高さ,色深床,圧瞮方匏など 40
⚠ **GitHub.com Fallback** ⚠