Copy

MIDORIAck ソフトウェア材料の倉庫

Contents ♪

C言語標準ライブラリ
ISOのC言語標準ライブラリ関数の実例付き関数リファレンスです。
標準ライブラリからベーシックで使用頻度が高いものと、ライブラリ関数と共によく使われるいくつかのPOSIX準拠関数を合わせて200関数くらい並べています。POSIX準拠関数には、タイトルの末尾に[POSIX]を付けています。
2024.07.28
abort プログラムを異常終了させる
stdlib.h
void abort(void)
プログラムを異常終了させる。
abort()で終了したときは、SIGABRTシグナルを送信する。
aborttest.c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    abort();

    return 0;
}
$ ./aborttest
中止 (コアダンプ)
exit()に比べるとabort()は強制終了の意味が強い。
2024.07.28
abs 絶対値を求める
stdlib.h
int abs(int x)
long labs(long x)
math.h
double fabs(double x)
x 数値
return 求める絶対値
絶対値を求める。
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int n;
    n = abs(-20);
    printf("%d\n", n); 

    return 0;
}
20
fabs()のみmath.h。
2025.04.26
access ファイルのアクセス権限または存在を調べる[POSIX]
unistd.h
int access(const char *pathname, int mode)
pathname 調べるファイルまたはディレクトリパス
mode 調べるアクセス権を以下からORで指定する(F_OKのみ単独で指定する)。
F_OK、または0 存在するか
R_OK 読み出し可
W_OK 書き込み可
X_OK 実行可
return 0: 指定アクセスは許可される、-1: 指定アクセスは許可されない
(F_OKではファイルのあり・なし)
access()を呼び出すプロセスから指定するファイル・ディレクトへ指定するアクセスが許可されるか、あるいはファイルが存在するかを調べる。
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    int r; 
    if ((r = access("/etc/hosts", 0)) == 0)
        printf("/etc/hosts exists\n");
    if ((r = access("/etc/xxxx", 0)) != 0) {
        printf("/etc/xxxx does not exists (%d)\n", errno);
        if (errno == ENOENT)
            printf("\terror ENOENT\n");     // 存在しない 
    }
    if ((r = access("/etc/hosts", W_OK)) == 0) {
        printf("/etc/hosts is Write OK\n");
    } else {
        printf("/etc/hosts is Write NG (%d)\n", errno);
        if (errno == EACCES)
            printf("\terror EACCES\n");     // 要求するアクセスが拒否された
    }
    if ((r = access("/etc/X11/Xreset", R_OK | X_OK)) == 0)
        printf("/etc/X11/Xreset is Read/Exec OK\n");
    return 0;
}
/etc/hosts exists
/etc/xxxx does not exists (2)
    error ENOENT
/etc/hosts is Write NG (13)
    error EACCES
/etc/X11/Xreset is Read/Exec OK
2025.04.26
alarm 指定秒後にSIGALRMシグナルを送信する[POSIX]
unistd.h
unsigned int alarm(unsigned int seconds)
seconds seconds秒後にSIGALRMを送信する。
return その前にalarm()で設定した場合の残り秒数。
前の呼び出しで残っている秒数がなければ0。
指定する秒数後にSIGALRMシグナルを自身のプロセスへ送信する設定を行う。
設定したらalarm()関数は直ちに返る。
alarm()を呼び出してそのシグナルまでの時間を待たずにalarm()を呼び出した場合、そのalarm()は前のalarm()の残り秒数を戻り値に返す。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void sighdr(int s)
{
    printf("Catch signal %d\n", s);
    exit(0);
}

int main(int argc, char *argv[])
{
    int r;
    if (signal(SIGALRM, sighdr) == SIG_ERR) {
        printf("error\n");
    }
    alarm(5);           // このアラームは次のalarm()で再設定される
    sleep(1);
    r = alarm(3);       // 3秒後にSIGALRMがハンドラに捕捉される
    printf("SETALARM %d\n", r);
    pause()
    return 0;
}
SETALARM 4
Catch signal 14
2024.07.28
asctime tm構造体の日付時刻を文字列に変換する
time.h
char *asctime(const struct tm *tm)
tm 日時曜日
return 日付時刻の文字列領域のポインタ
戻り値が参照する文字列は静的な文字列領域のポインタである。実行するたびに文字列の内容は更新される。
tm構造体に格納されている日付時刻を文字列に変換する。
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    time_t t;
    struct tm *t_tm;
    char    *st;

    time(&t);
    t_tm = localtime(&t);
    st = asctime(t_tm);

    printf("%s\n", st);
    return 0;
}
Mon Feb 26 19:50:28 2018
2024.07.28
assert 条件によりプログラムの実行を中止する
assert.h
void assert(expression)
expression 条件式
expressionの式の結果が偽(0)の場合、エラーメッセージを出力しプログラムの実行を中止する。
#include <stdio.h>
#include <assert.h>

int main(int argc, char *argv[])
{
    int a = 10;

    assert(a == 9);

    return 0;
}
asserttest: asserttest.c:8: main: Assertion 'a == 9' failed.
2024.07.28
atexit プログラム終了時に実行する関数を登録する
stdlib.h
int atexit(void (*function)(void))
function 正常終了時に呼び出す関数ポインタ
return 0: 登録成功、0以外: 登録失敗
functionに与えた関数が、exit()やmain()のreturnによりプログラムが終了する直前に呼び出される。
#include <stdio.h>
#include <stdlib.h>

void fin(void)
{
    printf("Finish\n");
}

int main(int argc, char *argv[])
{
    atexit(fin);
    exit(0);
}
Finish
2024.07.28
atoi 文字列を数値型に変換する
stdlib.h
int atoi(const char *nptr)
long atol(const char *nptr)
double atof(const char *nptr)
nptr 数値を表す文字列
return 変換した数値
変換不可能な場合は0または0.0
数値を表す文字列を数値型(int、long、double)に変換する。
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    double n;

    n = atof("123.456789");
    printf("123.456789 -> %f\n", n);
    n = atof("12345.67A89");
    printf("12345.67A89 -> %f\n", n);
    n = atof("ABC");
    printf("ABC -> %f\n", n);

    return 0;
}
123.456789 -> 123.456789
12345.67A89 -> 12345.670000
ABC -> 0.000000
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int n;

    n = atoi("123");
    printf("123 -> %d\n", n);
    n = atoi("1.23");
    printf("1.23 -> %d\n", n);
    n = atoi("ABC");
    printf("ABC -> %d\n", n);

    return 0;
}
123 -> 123
1.23 -> 1
ABC -> 0
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int n;

    n = atol("123456789");
    printf("123456789 -> %d\n", n);
    n = atol("1234567.89");
    printf("1234567.89 -> %d\n", n);
    n = atol("ABC");
    printf("ABC -> %d\n", n);

    return 0;
}
123456789 -> 123456789
1234567.89 -> 1234567
ABC -> 0
正常変換された0(0.0)とエラーの場合の0(0.0)は区別がつかないことに注意。
2025.04.26
basename dirname パスからディレクトリ名/ファイル名部分を抜き出す[POSIX]
libgen.h
string.h
char *dirname(char *path)
char *basename(char *path)
path パス名※
return basename: パス名の最後のファイル名へのポインタを返す。
dirname: パス名の最後のファイル名までの途中のパス名へのポインタを返す。
パスがディレクトリで終わるなら最後のディレクトリとその前までのパスで分割する。
ファイル・ディレクトリのパス名から、最後のファイル名(ディレクトリで終わるならディレクトリ名)と、それまでのディレクトリパスを分割する。
basename()はファイル名、dirname()はディレクトリパス名を返す。
何れもディレクトリの場合の最後の「/」は外されて返る。
次は、POSIXのドキュメントから引用したパターンである。
path            dirname         basename
"/usr/lib"      "/usr"          "lib"
"/usr/"         "/"             "usr"
"usr"           "."             "usr"
"/"             "/"             "/"
"."             "."             "."
".."            "."             ".."
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *path1 = strdup("/usr/share/X11/rgb.txt");
    printf("%s\n", basename(path1));
    printf("%s\n", dirname(path1));
    free(path1);
    char *path2 = strdup("/usr/share/X11/locale/");
    printf("%s\n", basename(path2));
    printf("%s\n", dirname(path2));
    return 0;
}
rgb.txt
/usr/share/X11
locale
/usr/share/X11
引数に指定する文字列ポインタのpathは、その内容が変更される可能性があるので、面倒だが上の例のようにパス名の文字列をstrdup()などで別途確保したものを渡すべきである。
2024.07.28
bsearch 昇順ソートされた配列を二分木検索する
stdlib.h
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
    int (*compar)(const void *, const void *))
key 一致検索する値を示すポインタ
base 昇順ソートされている配列の先頭
nmemb 配列の要素数
size 配列の1要素のサイズ(バイト数)
compar 昇順ソートに適用されている大小比較を行う関数
配列の昇順ソートがこの関数により作成されたものでなければ、期待する検索結果は得られない。この関数は2つの引数の値(数値に限らない)の大小を比較して、以下の戻り値を返すものとする。
0 第1引数=第2引数
負数 第1引数<第2引数
1以上 第1引数>第2引数
この関数が比較する対象は数値や文字に限らない。
return 配列baseから一致した要素のポインタ
NULL: 見つからない
昇順にソートされた配列baseから、keyに一致する要素の場所を二分木検索により検索する。
comparには配列の昇順ソートに適用された比較関数を指定する。
#include <stdio.h>
#include <stdlib.h>

int comp(const void * val1, const void * val2)
{
    if(*(int *)val1 == *(int *)val2)
        return 0;
    else if(*(int *)val1 < *( int * )val2)
        return -1;
    return 1;
}

int main(int argc, char *argv[])
{
    int arr[ ] = { 3, 4, 8, 5, 0, 10 };
    int key = 5;
    int *val;

    qsort(arr, 6, sizeof(int), comp);
    val = bsearch(&key, arr, 6, sizeof(int), comp);
    printf("%d\n", *val);

    return 0;
}
5
2024.07.28
ceil 浮動小数点値の小数点切り上げ
math.h
double ceil(double x)
x 浮動小数点値
return xの小数点切り上げ値
引数の浮動小数点値xの小数点の切り上げ値(xを下回らない最小の整数)を返す。
#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
    printf("%f\n", ceil(2.01)); 
    return 0;
}
3.000000
2025.04.26
chdir カレントディレクトリを変更する[POSIX]
unistd.h
int chdir(const char *path)
path 変更先ディレクトリ
return 0: 成功、-1: 失敗(存在しないパス、アクセス違反など) 
実行中プロセスのカレントディレクトリを変更する。
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char    pwd[1024];
    int r;
    r = chdir("/etc");
    printf("%d %s\n", r, getcwd(pwd, sizeof(pwd)));
    r = chdir("wpa_supplicant");
    printf("%d %s\n", r, getcwd(pwd, sizeof(pwd)));
    r = chdir("/usr/xxx");
    printf("%d %s\n", r, getcwd(pwd, sizeof(pwd)));
    return 0;
}
0 /etc
0 /etc/wpa_supplicant
-1 /etc/wpa_supplicant
2025.04.26
chmod ファイルのモードを変更する[POSIX]
sys/stat.h
int chmod(const char *pathname, mode_t mode)
pathname 変更するファイル
mode ファイルモードを以下のフラグのORで指定する。
S_IRUSR (00400) 所有者読み取り
S_IWUSR (00200) 所有者書き込み
S_IXUSR (00100) 所有者実行 
S_IRGRP (00040) グループ読み取り
S_IWGRP (00020) グループ書き込み
S_IXGRP (00010) グループ実行
S_IROTH (00004) 他人読み取り
S_IWOTH (00002) 他人書き込み
S_IXOTH (00001) 他人実行
S_ISVTX (01000) スティッキービット
S_ISUID (04000) set-user-ID
S_ISGID (02000) set-group-ID
あるいは8進数で0765のように指定してもよい。
return 0: 成功、-1: 失敗
指定するファイルまたはディレクトリーのモードを変更する。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    struct stat inf;
    mode_t setmod;
    stat("test.file", &inf);
    printf("org=%08o\n", inf.st_mode);
    setmod = inf.st_mode;
    setmod |= (S_IWOTH | S_IXUSR);  // その他+w 所有者+x
    setmod &= ~S_IWGRP;             // グループ-w
    if (chmod("test.file", setmod) == 0) {
        stat("test.file", &inf);
        printf("new=%08o\n", inf.st_mode);
    }
    if (chmod("test.file", 0777) == 0) {
        stat("test.file", &inf);
        printf("oct=%08o\n", inf.st_mode);
    }
    return 0;
}
org=00100664
new=00100746
oct=00100777
2025.04.26
chown ファイルの所有者を変更する[POSIX]
unistd.h
int chown(const char *pathname, uid_t owner, gid_t group)
pathname 変更するファイル
owner ユーザID
group グループID
return 0: 成功、-1: 失敗
指定するファイルまたはディレクトリーの所有者を変更する。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    struct stat inf;
    stat("test.file", &inf);
    printf("org uid:%d gid:%d\n", (int)inf.st_uid, (int)inf.st_gid);
    if (chown("test.file", 1000, 1000) == 0) {
        stat("test.file", &inf);
        printf("new uid:%d gid:%d\n", (int)inf.st_uid, (int)inf.st_gid);
    }
    return 0;
}
org uid:0 gid:7
new uid:1000 gid:1000
2024.07.28
clearerr ファイル入出力エラーのリセット
stdio.h
void clearerr(FILE *stream)
stream ファイルストリーム
ファイルの書き込み/読み込みのエラーが発生したときのエラー状態、ファイル終端を越えて読み込もうとしたときのエラー状態をリセットする。
エラー状態はclearerr()を呼び出して状態をリセットするまで保持されるので、エラー発生状態をferror()やfeof()でチェックしたら、直ちにclearerr()を呼び出す必要がある。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;

    if ((fp = fopen("file", "w")) != NULL) {
        if (fgetc(fp) == -1) {
            printf("Error %d\n", ferror(fp));
            clearerr(fp);
        }
        printf("Error %d Reset\n", ferror(fp));
        fwrite("ABCDE", 5, 1, fp);
        fclose(fp);
    }
    if ((fp = fopen("file", "r")) != NULL) {
        while (!feof(fp)) {
            fgetc(fp);
            printf("EOF? %d\n", feof(fp));
        }
        clearerr(fp);
        printf("EOF? %d Reset\n", feof(fp));
        fclose(fp);
    }

    return 0;
}
Error 1
Error 0 Reset
EOF? 0
EOF? 0
EOF? 0
EOF? 0
EOF? 0
EOF? 1
EOF? 0 Reset
2024.07.28
clock プログラムが使用したCPU時間を得る
time.h
clock_t clock(void)
return 使用したCPU時間
プログラムの実行に使用したCPU時間を返す。
関数が返す値を定数CLOCKS_PER_SECで割ると秒単位で得られる。
#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main(int argc, char *argv[])
{
    clock_t t1, t2;
    unsigned long i;
    t1 = clock();
    for(i = 0 ; i < 1000000000L ; i++);
    t2 = clock();
    printf("cpu %f sec\n",
        (double)(t2 - t1)/CLOCKS_PER_SEC);

    return 0;
}
cpu 1.577750 sec
2025.04.26
clock_gettime clock_settime 紀元(Epoch)からの経過秒数を取得/設定する[POSIX]
time.h
int clock_gettime(clockid_t clk_id, struct timespec *tp)
int clock_settime(clockid_t clk_id, const struct timespec *tp)
clk_id カーネルサポートのクロックIDを指定する。
通常はリアルタイムクロックを示すCLOCK_REALTIMEを指定する。
tp 取得または設定するtimespec構造体
return 0: 成功、-1:失敗
clock_gettime()は、紀元(Epoch 1970-01-01 00:00:00 (UTC))からの経過秒数と、秒内で経過したナノ秒を取得する。clock_settime()は指定クロックに設定する。
struct timespecは次のように定義されている。
struct timespec {
    time_t   tv_sec;        /* seconds */
    long     tv_nsec;       /* nanoseconds */
};
#include <stdio.h>
#include <sys/time.h>
#include <time.h>

int main(int argc, char *argv[])
{
    struct timespec ts;
    struct timeval tv;
    clock_gettime(CLOCK_REALTIME, &ts);
    printf("clock_gettime sec=%ld nanosec=%ld\n%s", ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
    gettimeofday(&tv, NULL);
    printf("gettimeofday sec=%ld nanosec=%ld\n%s", tv.tv_sec, tv.tv_usec, ctime(&ts.tv_sec));
    return 0;
}
clock_gettime sec=1745573492 nanosec=675256079
Fri Apr 25 18:31:32 2025
gettimeofday sec=1745573492 nanosec=675301
Fri Apr 25 18:31:32 2025
clock_gettime()は、POSIXで非推奨とされているgettimeofday()の代替とされている。
2024.07.28
ctime 紀元(Epoch)からの経過秒数を日時の文字列に変換する
time.h
char *ctime(const time_t *timep)
timep 紀元(Epoch)からの経過秒
return 日付時刻の文字列領域のポインタ
戻り値で参照される文字列は静的な文字列領域のポインタなので、実行するたびに文字列の内容は更新される。
紀元(Epoch 1970-01-01 00:00:00 (UTC))からの経過秒数を、日付時刻を表す文字列に変換する。
変換した時刻の文字列は現地時刻(日本時間)になる。
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    time_t  t;
    char    *st;

    t = time(NULL);
    st = ctime(&t); 
    
    printf("%s\n", st);
    return 0;
}
Thu Feb 22 19:28:07 2018
2024.07.28
difftime 2つの時間の差を求める
time.h
double difftime(time_t time1, time_t time0)
time1 紀元(Epoch)からの経過秒(経過した後の時間)
time0 紀元(Epoch)からの経過秒(開始の時間)
return 時間の差(秒)
時刻time0からtime1の間の経過時間を求める。
時間の前後を逆に指定するとマイナスの値が返る。
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    time_t t1, t2;
    double tdif;

    t1 = time(NULL);
    sleep(3);
    t2 = time(NULL);
    tdif = difftime(t2, t1);
    printf("t2-t1 %3.1fsec\n", tdif);

    return 0;
}
t2-t1 3.0sec
2024.07.28
div 整数の割り算の商と余りを求める
stdlib.h
div_t div(int numerator, int denominator)
ldiv_t ldiv(long numerator, long denominator)
numerator 分子の整数
denominator 分母の整数
return 構造体div_t(ldiv()はldiv_t)のquotに商、remに余り
整数numerator/denominatorの割り算の商と余りを求める。
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    div_t dv;
    dv = div(7, 3);
    printf("7/3 = %d...%d\n",
        dv.quot, dv.rem);

    return 0;
}
7/3 = 2...1
2024.07.28
exit プログラムを終了する
stdlib.h
void exit(int status)
status 終了ステータスコード
プログラムの実行を終了する。
statusの数値を終了ステータスとして、プログラムの呼び出し元プロセスに引き渡す。終了ステータスは0~255の値で、0は正常終了、それ以外は正常ではない終了状態を示す。
exittext.c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    exit(50);

    return 0;
}
$ ./exittest ; echo "$?"
50
exit()でプログラムが終了するとき、開いていたファイルはすべて閉じられる。
2024.07.28
exp 自然対数の底eの指数関数
math.h
double exp(double x)
x 浮動小数点値
return eのx乗
自然対数の底eのx乗を求める。
#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
    printf("exp(1.0) = %f\n", exp(1.0));

    return 0;
}
exp(1.0) = 2.718282
2024.07.28
fclose ファイルを閉じる
stdio.h
int fclose(FILE *stream)
stream ファイルストリーム
return 0: 正常、EOF: エラー
開いたファイルストリームstreamを閉じる。
閉じる前に、バッファリングされているまだ書き込まれていないデータを全て書き込む。
fclosetest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;

    if ((fp = fopen("file", "w")) != NULL) {
        fwrite("012345", 6, 1, fp);
        fclose(fp);
    }

    return 0;
}
$ ./fclosetest
$ cat file
012345
2024.07.28
feof ファイル読み込みの終端エラーチェック
stdio.h
int feof(FILE *stream)
stream ファイルストリーム
return 0: ファイルの終端は越えていない
0以外: ファイルの終端を越えて読み込もうとした
ファイルstreamの終端(EOF)を超えて読み込もうとしてエラーになったかどうかを判定する。
feof()は直前に実行したファイルアクセスがエラーになったときEOFを越えたアクセスによるものかどうかを調べることができる。これ以外の要因のエラーはferror()で判定する。
EOFを越えた読み込みが発生したときのエラー状態はclearerr()を呼び出して状態をリセットするまで保持されるので、feof()でエラーを判定したら直ちにclearerr()を呼び出す必要がある。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    int c;

    if ((fp = fopen("file", "w")) != NULL) {
        fwrite("ABCD", 4, 1, fp);
        fclose(fp);
    }
    if ((fp = fopen("file", "r")) != NULL) {
        while (!feof(fp)) {
            c = fgetc(fp);
            printf("%d EOF? %d\n", c, feof(fp));
        }
        clearerr(fp);
        fclose(fp);
    }

    return 0;
}
65 EOF? 0
66 EOF? 0
67 EOF? 0
68 EOF? 0
-1 EOF? 1
2024.07.28
ferror ファイルの書き込み・読み込みエラーチェック
stdio.h
int ferror(FILE *stream)
stream ファイルストリーム
return 0: ファイルの書き込み・読み込みエラーは発生していない
0以外: ファイルの書き込み・読み込みエラーが発生した
ファイルstreamのエラーを判定する。
直前のファイルへの書き込み・読み込みでエラーが発生したかどうかを調べることができる。ファイル終端を超えて読み込もうとしたかはferror()ではなくfeof()で調べるべきである。ファイルを開く時点でのエラーはfopen()の戻り値で判定できる。
書き込みまたは読み込みのエラーが発生したときのエラー状態は、clearerr()を呼び出して状態をリセットするまで保持されるので、ferror()でエラーを判定したら直ちにclearerr()を呼び出す必要がある。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;

    if ((fp = fopen("file", "w")) != NULL) {
        if (fgetc(fp) == -1) {
            printf("Error %d\n", ferror(fp));
            clearerr(fp);
        }
        fwrite("ABCDE", 5, 1, fp);
        printf("Error %d\n", ferror(fp));
        fclose(fp);
    }
    return 0;
}
Error 1
Error 0
2024.07.28
fflush ファイルストリームバッファの内容をファイルに書き出す
stdio.h
int fflush(FILE *stream)
stream ファイルストリーム
return 0: 成功、EOF: エラー
ファイルstreamへの書き込みバッファの中のデータを強制的に書き出す。ディスクドライブへの反映を強制的に行う。
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    char buf[ BUFSIZ ];

    setbuf(stdout, buf);
    puts("ABCDEFG\n");
    sleep(3);
    fflush(stdout);

    return 0;
}
(3秒後に表示される)
ABCDEFG
2024.07.28
fgetc ファイルから文字を読み込む
stdio.h
int fgetc(FILE *stream)
int getc(FILE *stream)
stream ファイルストリーム
return 読み込んだ文字
EOF: エラー
ファイルstreamから1文字を読み込む。
streamにstdinを指定した場合は標準入力から入力される。
fgetctest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    int c;

    fp = fopen("ifile", "r");
    c = fgetc(fp);
    fclose(fp);
    printf("%c\n", c);
    c = fgetc(stdin);
    printf("%c\n", c);

    return 0;
}
$ echo "W" > ifile
$ ./fgetctest 
W
X   --> 入力待ちでキーボードからXを入力
X
getc()はfgetc()と同じである。
2024.07.28
fgetpos ファイルストリームの位置を取得する
stdio.h
int fgetpos(FILE *stream, fpos_t *pos)
stream ファイルストリーム
pos ファイル位置の格納先のfpos_t型変数のポインタ
return 0: 成功、-1: エラー
開いているファイルstreamの読み込み・書き込みを行う現在の位置を取得しposへ格納する。
fpos_tは処理系によって整数型と構造体型で異なるかもしれない。fgetpos()で取得したposはfsetpos()で使用されることが望ましい。
fgetpostest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    fpos_t pos;

    if ((fp = fopen("file", "w")) != NULL) {
        fgetpos(fp, &pos);
        fputs("012345", fp);
        fsetpos(fp, &pos);
        fwrite("ABC", 3, 1, fp);
        fclose(fp);
    }
    return 0;
}
$ ./fgetpostest
$ cat file
ABC345
ftell()と同じ機能。
2024.07.28
fgets ファイルから文字列を読み込む
stdio.h
char *fgets(char *s, int size, FILE *stream)
s 文字列を格納するバッファのポインタ
size 最大バイト数
stream ファイルストリーム
return sのポインタ、NULL: エラー
ファイルstreamから最大でsize-1バイトの文字列を読み込み、バッファsに格納する。
バッファsに読み込んだ文字列の終端には自動的に0が書き込まれる。
fgetstest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    char s[5];

    fp = fopen("ifile", "r");
    fgets(s, 5, fp);
    fclose(fp);
    puts(s);

    return 0;
}
$ echo "abcde" > ifile
$ ./fgetstest
abcd
2024.07.28
floor 浮動小数点値を超えない最大の整数値
math.h
double floor(double x)
x 浮動小数点値
return 浮動小数点値xを超えない最大の整数値
xを超えない最大の整数値を求める。
#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
    printf("%f\n", floor(-1.2));
    printf("%f\n", floor(-0.2));
    printf("%f\n", floor(0));
    printf("%f\n", floor(1.2));
    printf("%f\n", floor(5.0));

    return 0;
}
-2.000000
-1.000000
0.000000
1.000000
5.000000
2024.07.28
fmod 割り算の余りを求める
math.h
double fmod(double x, double y)
x 分子
y 分母
return x/yの除算の余剰
x/yの浮動小数点の除算の余りを返す。
#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
    printf("%5.2f\n", fmod(5.0, 1.4));

    return 0;
}
0.80
2025.04.26
fnmatch 文字列のワイルドカードマッチを行う[POSIX]
#include <fnmatch.h>
int fnmatch(const char *pattern, const char *string, int flags)
pattern ファイルパス名のワイルドカードを使ったパターン
string 一致を調べる文字列
flags 次のオプションをORで指定できる。不要な場合は0を指定する。
FNM_NOESCAPE バックスラッシュのエスケープを無効にする
FNM_PATHNAME 「/」をワイルドカードで一致させない
FNM_CASEFOLD 大文字小文字の区別をしない(GNU拡張)
return 0: 一致、FNM_NOMATCH(=1): 不一致、それ以外の非0: エラー
パス名の一致を調べるときに使うワイルドカードによるパターンに、文字列が一致するかを調べる。
パス名のワイルドカード一致を確認するための関数だが、パス名に限らず任意の文字列に使ってもかまわない。
#label fnmatch.c
#include <stdio.h>
#include <fnmatch.h>

int main(int argc, char *argv[])
{
    int m = fnmatch("*_12.?x", "Abc_12.zx", 0);
    printf("result %d\n", m);
    return 0;
}
result 0
2024.07.28
fopen ファイルを開く
stdio.h
FILE *fopen(const char *path, const char *mode)
path ファイルパス
mode モード
return ファイルストリーム、NULL: エラー
ファイル名(ファイルパス)pathをモードmodeで開き、ファイルストリームのポインタを取得する。
modeには開くファイルについて、読み取り可能/書き込み可能を文字列で指定する。
モード 操作 既存ファイル 新規ファイル
r 読み取り 内容を保持 エラー
w 書き込み 内容を破棄 新規作成
a 末尾から追加書き込み 内容を保持 新規作成
r+ 読み取りと書き込み 内容を破棄 エラー
w+ 読み取りと書き込み 内容を破棄 新規作成
a+ 読み取りと末尾から追記 内容を保持 新規作成
Microsoftの処理系では、テキストファイルとバイナリファイルのそれぞれでファイル入出力の振る舞いが異なり、バイナリファイルを開く場合は、モードに「b」の文字を追加する必要がある。またデフォルトはテキストファイルだが明示的に「t」を指定してもかまわない。
Microsoftの処理系でのbとtの指定方法をまとめると次のようなる。
モード 操作 テキストファイル バイナリファイル
r 読み取り r, rt rb
w 書き込み w, wt wb
a 末尾から追加書き込み a, at ab
r+ 読み取りと書き込み r, r+t, rt+ r+b, rb+
w+ 読み取りと書き込み w+, w+t, wt+ w+b, wb+
a+ 読み取りと末尾から追記 a+, a+t, at+ a+b, ab+
LinuxUNIX系(POSIX系)ではバイナリとテキストファイルの区別はなく、すべてバイナリファイルのように扱う。Linux処理系でも「b」や「t」を付けられるが、どちらも処理は変わらない。
Microsoft処理系でのテキストファイルは、改行コードの読み取りと書き込み時に次のような変換を行う。
書き込み時 0x0aを(0x0d 0x0a)に変換
読み取り時 (0x0d 0x0a)を0x0aに変換
0x1a(CTRL-Z)はEOF(ファイル末尾)として解釈する。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    char s[ 20 ];

    if ((fp = fopen("file", "w")) != NULL) {
        fwrite("012345", 6, 1, fp);
        fclose(fp);
    }
    if ((fp = fopen("file", "a+")) != NULL) {
        fputs("ABCDEF", fp);
        fclose(fp);
    }
    if ((fp = fopen("file", "r")) != NULL) {
        fgets(s, sizeof(s), fp);
        fclose(fp);
    }
    puts(s);
    return 0;
}
012345ABCDEF
2024.07.28
fputc 文字をファイルに書き込む
stdio.h
int fputc(int c, FILE *stream)
int putc(int c, FILE *stream)
c 書き込む文字
stream ファイルストリーム
return 書き込んだ文字
EOF: エラー
文字cをファイルstreamに書き込む。
streamにstdoutを指定した場合は標準出力に出力する。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;

    fp = fopen("ofile", "w");
    fputc('X', fp);
    fclose(fp);

    fputc('A', stdout);

    return 0;
}
A

$ cat ofile
X
putc()はfputc()と同じである。
2024.07.28
fputs 文字列をファイルへ書き込む
stdio.h
int fputs(const char *s, FILE *stream)
s 書き込む文字列
stream ファイルストリーム
return 0以上の整数
EOF: エラー
文字列sをファイルstreamへ書き込む。
ただし、文字列sの終端の0は書き込まない。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;

    fp = fopen("ofile", "w");
    fputs("abcd", fp);
    fclose(fp);

    return 0;
}
$ cat ofile
abcd
2024.07.28
fread ファイルからデータを読み込む
stdio.h
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
ptr 読み込んだデータを格納するバッファのポインタ
size 読み込みサイズ(nmemb=1あたり)
nmemb 読み込み個数(sizeバイトを1とした個数)
stream ファイルストリーム
return 読み込んだ個数
途中で末尾に到達したかエラーの場合はnmembより少ない値が返る。
ファイルstreamから、サイズsizeバイトをnmemb個のデータを読み込みバッファptrに格納する。
size×nmembが読み込むバイト数となる。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    char s[ 10 ];

    if ((fp = fopen("file", "w")) != NULL) {
        fwrite("012345", 7, 1, fp);
        fclose(fp);
    }
    if ((fp = fopen("file", "r")) != NULL) {
        fread(s, sizeof(s), 1, fp);
        fclose(fp);
    }
    puts(s);
    return 0;
}
012345
2024.07.28
free 動的に割り当てられたメモリ領域を解放する
stdlib.h
void free(void *ptr)
ptr 動的に割り当てられたメモリ領域のポインタ
(NULLを与えた場合はなにも処理をしない)
malloc()などで動的に取得したメモリ領域ptrを解放(返却)する。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char *p;

    p = (char *)malloc(10);
    memcpy(p, "ABCDEFGHI", 10);
    puts(p);
    free(p);
    return 0;
}
ABCDEFGHI
2024.07.28
freopen ファイルを閉じてから新たにファイルを開く
stdio.h
FILE *freopen(const char *path, const char *mode, FILE *stream)
path ファイルパス
mode モード
stream ファイルストリーム
return ファイルストリーム
NULL: エラー
ファイルstreamを一旦閉じ、ファイルpath、モードmodeで同じstreamで開きなおす。
freopentest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
        
    if ((fp = freopen("file.stdout", "w", stdout))
        != NULL) {
        printf("Write to file");
        fclose(fp);
    }

    return 0;
}
$ ./freopentest
$ cat file.stdout
Write to file
modeの指定方法はfopen()と同じ。
2024.07.28
frexp 浮動小数点値を可数部と指数部に分解する
math.h
double frexp(double x, int *exp)
x 浮動小数点値
exp xの指数部(2のexp乗となる値)
return xの可数部
浮動小数点値xの可数部(小数成分)と指数部(整数成分)に分解し、可数部を戻り値で返し、指数部を引数のexpに返す。これらは、それぞれ 
x = 戻り値 * 2^exp
が成り立つ値になる。
#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
    int exp;
    double x;
    x = frexp(5.0, &exp);
    printf("%f %d\n",x, exp); 

    return 0;
}
0.625000 3
2024.07.28
fseek ファイルストリームを移動する
stdio.h
int fseek(FILE *stream, long offset, int origin)
stream ファイルストリーム
offset オフセット
origin 移動する基準位置
SEEK_CUR: 現在位置
SEEK_END: ファイルの最後
SEEK_SET: ファイルの先頭
return 0: 成功、-1: エラー
開いているファイルstreamの読み込み・書き込みを行う位置を、基準位置originからoffsetバイトの位置に移動する。
offsetはマイナス値を指定できる。Microsoftの処理系でテキストファイルとして開いたファイルに対しては、改行文字の変換により正しい結果が保障されない。
fseektest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    char s[ 10 ];

    if ((fp = fopen("file", "w")) != NULL) {
        fputs("012345", fp);
        fseek(fp, 2, SEEK_SET);
        fwrite("ABC", 3, 1, fp);
        fclose(fp);
    }
    return 0;
}
$ ./fseektest
$ cat file
01ABC5
2024.07.28
fsetpos ファイルストリームを移動する
stdio.h
int fsetpos(FILE *stream, const fpos_t *pos)
stream ファイルストリーム
pos 移動先の位置が格納されたfpos_t型変数のポインタ
return 0: 成功、-1: エラー
開いているファイルstreamの読み込み・書き込みを行う位置を位置情報posが指定する位置へ移動する。
移動先が格納されたposは、fgetpos()で取得したfpos_t型の変数ポインタであることを期待している。fpos_tは処理系によって整数型と構造体型で異なるかもしれない。
fsetpostest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    fpos_t pos;

    if ((fp = fopen("file", "w")) != NULL) {
        fgetpos(fp, &pos);
        fputs("012345", fp);
        fsetpos(fp, &pos);
        fwrite("ABC", 3, 1, fp);
        fclose(fp);
    }
    return 0;
}
$ ./fsetpostest
$ cat file
ABC345
fseek()と同じ機能。
2024.07.28
ftell ファイルストリーム位置を取得する
stdio.h
long ftell(FILE *stream)
stream ファイルストリーム
return ファイル先頭から現在位置のオフセット(バイト)
-1: エラー
開いているファイルstreamの読み込み・書き込みを行う現在の位置を取得する。
Microsoftの処理系でテキストファイルとして開いたファイルに対しては、改行文字の変換により正しい結果が保障されないため使用すべきでない。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    int ofs;

    if ((fp = fopen("file", "w")) != NULL) {
        fputs("012345", fp);
        ofs = ftell(fp);
        printf("%d\n", ofs);
        fclose(fp);
    }

    return 0;
}
6
2024.07.28
fwrite ファイルへデータを書き込む
stdio.h
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
ptr 書き込むデータが格納されたバッファのポインタ
size 書き込みサイズ(nmemb=1あたり)
nmemb 書き込み個数(sizeバイトを1と数えた個数)
return 書き込んだ個数
途中で書き込みに失敗したか、エラーの場合はnmembより少ない値が返る。
ファイルstreamへ、バッファptrからサイズsizeバイトのデータをnmemb個書き込む。
size×nmembが書き込むバイト数となる。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    char s[ 10 ];

    if ((fp = fopen("file", "w")) != NULL) {
        fwrite("012345", 7, 1, fp);
        fclose(fp);
    }
    if ((fp = fopen("file", "r")) != NULL) {
        fread(s, sizeof(s), 1, fp);
        fclose(fp);
    }
    puts(s);
    return 0;
}
012345
2024.07.28
getchar 標準入力からの1文字読み込む
stdio.h
int getchar(void)
return 読み込んだ文字
EOF: エラー
標準入力(通常はキーボード)から1文字読み込む。
#include <stdio.h>

int main(int argc, char *argv[])
{
    int c;

    printf(">");
    c = getchar();
    putchar(c);

    return 0;
}
>M
M
2025.04.26
getpid getppid プロセスIDを取得する[POSIX]
sys/types.h
unistd.h
pid_t getpid(void)
pid_t getppid(void)  
return プロセスID
getpid()は現在のプロセスのプロセスID(PID)を取得する。
getppid()は現在のプロセスの親プロセスのプロセスID(PPID)を取得する。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char *env;

    printf("PID=%d\n", getpid());
    printf("PPID=%d\n", getppid());
    return 0;
}
PID=137311
PPID=126793
2025.04.26
gettimeofday settimeofday 紀元(Epoch)からの経過秒数を取得/設定する(非推奨)[POSIX]
sys/time.h
int gettimeofday(struct timeval *tv, struct timezone *tz)
int settimeofday(const struct timeval *tv , const struct timezone *tz)
tv 取得または設定するtimevel構造体
tz タイムゾーンだが、NULLを指定すべきとされている。
return 0: 成功、-1:失敗
clock_gettime()は、紀元(Epoch 1970-01-01 00:00:00 (UTC))からの経過秒数と、秒内で経過したナノ秒を取得する。clock_settime()は指定クロックに設定する。
#include <stdio.h>
#include <sys/time.h>
#include <time.h>

int main(int argc, char *argv[])
{
    struct timespec ts;
    struct timeval tv;
    clock_gettime(CLOCK_REALTIME, &ts);
    printf("clock_gettime sec=%ld nanosec=%ld\n%s", ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
    gettimeofday(&tv, NULL);
    printf("gettimeofday sec=%ld nanosec=%ld\n%s", tv.tv_sec, tv.tv_usec, ctime(&ts.tv_sec));
    return 0;
}
clock_gettime sec=1745573492 nanosec=675256079
Fri Apr 25 18:31:32 2025
gettimeofday sec=1745573492 nanosec=675301
Fri Apr 25 18:31:32 2025
gettimeofday()はPOSIXで非推奨であり、clock_gettime()が代替するとされている。
2025.04.26
getcwd カレントディレクトリパスを取得する[POSIX]
unistd.h
char *getcwd(char *buf, size_t size)
buf カレントディレクトリパスを引数戻り値で返す。
size 格納先のbufのサイズ
return カレントディレクトリ格納先ポインタ(bufのポインタ)
NULL: 失敗
実行中プロセスのカレントディレクトリのフルパス名を取得する。
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char    pwd[1024];
    int r;
    chdir("/etc/X11");
    printf("%s\n", getcwd(pwd, sizeof(pwd)));
    return 0;
}
/etc/X11
2024.07.28
getenv setenv putenv unsetenv 環境変数を取得・設定・削除する
stdlib.h
char *getenv(const char *name)
int setenv(const char *name, const char *value, int overwrite)
int putenv(char *string)
unsetenv(const char *name)
name 環境変数名の文字列ポインタ
value 環境変数名に設定する値の文字列ポインタ
overwrite 既存の環境変数を、0: 上書きを無視する、0以外: 上書きを許可する
string 「環境変数名=値」で指定する文字列ポインタ
return getenv()は、指定された環境変数に設定されている値の文字列ポインタを返す。
戻り値で参照される文字列は静的な文字列領域のポインタである。
setenv()とunsetenv()は、0:成功、-1:失敗
putenv()は、0:成功、0以外:失敗
getenv()は、文字列nameで指定する環境変数名の設定値を返す。
setenv()とputenv()は文字列で与える環境変数を設定する。putenv()は「変数名=値」の書式で指定できる。
unsetenv()は環境変数を削除する。
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char *env;

    env = getenv("LANG");
    puts(env);
    setenv("TESTENV", "ABC", 0);
    puts(getenv("TESTENV"));
    setenv("TESTENV", "123", 1);    // 既存変数の上書き許可
    puts(getenv("TESTENV"));
    setenv("TESTENV", "XYZ", 0);    // 既存変数への上書きは無視する
    puts(getenv("TESTENV"));
    putenv("TESTENV=XYZ");
    puts(getenv("TESTENV"));
    unsetenv("TESTENV");
    return 0;
}
ja_JP.UTF-8
ABC
123
123
XYZ
2024.07.28
gmtime 紀元(Epoch)からの経過秒数をtm構造体に変換する
time.h
struct tm *gmtime(const time_t *timep);
timep 紀元(Epoch)からの経過秒
return tm構造体のポインタ
戻り値で参照されるtm構造体は静的な構造体領域のポインタなので、gmtime()を実行するたびに構造体の内容は更新される。
紀元(Epoch 1970-01-01 00:00:00 (UTC))からの経過秒数から、日付時刻をtm構造体に変換する。
tm構造体には、年月日時分秒曜日の各要素のメンバ変数に値が設定される。tm構造体に格納される時刻は協定世界時UTC(日本時間の9時間前)である。
struct tm {
    int tm_sec;        /* 秒 (0-60) */
    int tm_min;        /* 分 (0-59) */
    int tm_hour;       /* 時間 (0-23) */
    int tm_mday;       /* 月内の日付 (1-31) */
    int tm_mon;        /* 月 (0-11) */
    int tm_year;       /* 年 - 1900 */
    int tm_wday;       /* 曜日 (0-6, 日曜 = 0) */
    int tm_yday;       /* 年内通算日 (0-365) */
    int tm_isdst;      /* 夏時間 */
};
月が0から始まることに注意。
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    time_t t;
    struct tm *t_tm;

    time(&t);
    t_tm = gmtime(&t);

    printf("\t%d\n",t_tm->tm_year+1900);
    printf("\t%d\n",t_tm->tm_mon+1);
    printf("\t%d\n",t_tm->tm_mday);
    printf("\t%d\n",t_tm->tm_hour);
    printf("\t%d\n",t_tm->tm_min);
    printf("\t%d\n",t_tm->tm_sec);
    printf("\t%d\n",t_tm->tm_wday);
    printf("通算日\t%d\n",t_tm->tm_yday);
    printf("夏時間\t%d\n",t_tm->tm_isdst);

    return 0;
}
年  2018
月  2
日  22
時  11
分  36
秒  20
曜  4
通算日  52
夏時間  0
2024.07.28
isalnum isalpha etc. 文字の種類を判定する
ctype.h
int isalnum(int c)
int isalpha(int c)
int isdigit(int c)
int isblank(int c)
int isspace(int c)
int iscntrl(int c)
int isgraph(int c)
int islower(int c)
int isupper(int c)
int isprint(int c)
int ispunct(int c)
int isxdigit(int c)
c 調べたい文字
return 0以外: 該当する 0: 該当しない 
引数の文字cの種類を判定する。判定する種類について以下の関数がある。
判定関数 cを判定する文字の種類
isalnum 英字(a〜z・A-Z)または数字(0〜9)
isalpha 英字(a〜z・A-Z)
isdigit 数字(0〜9)
isblank 空白文字(スペース・タブ)
isspace 空白文字(空白・タブ・改行・復帰)
isgraph 表示可能文字(空白文字ではない)
isprint 表示可能文字(スペース含む・タブ除く)
islower 英字の小文字(a〜z)
isupper 文字の大文字(A~Z)
iscntrl 制御文字(0x00~0x1F、0x7F)
ispunct 区切り文字(英数字・空白文字・改行以外の記号文字全て)
isxdigit 16進数を表す文字(0~9、a~f、A~F)
#include <stdio.h>
#include <ctype.h>

int main(int argc, char *argv[])
{
    int c;  
    for (c = '0' ; c <= 'z' ; c++) {
        printf("%c - %d\n", c, isalnum(c));
    }
    return 0;
}
1 - 8       @ - 0       .
2 - 8       A - 8       .
.           B - 8       _ - 0
.           .           a - 8
9 - 8       .           c - 8
: - 0       X - 8       .
; - 0       Y - 8       .
.           Z - 8       y - 8
.           [ - 0       z - 8
「該当」判定の場合0以外の値はほとんどは1ではないので、==1のように判断しないように。
2025.04.26
kill プロセスにシグナルを送信する[POSIX]
signal.h
int kill(pid_t pid, int sig)
pid シグナルの送信先プロセスID
sig シグナル番号
return 0: 成功、-1:失敗
指定するプロセスへシグナルを送信する。
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>

void sighdr(int s)
{
    printf("Catch signal %d\n", s);
}

int main(int argc, char *argv[])
{
    signal(SIGINT, sighdr);
    kill(getpid(), SIGINT);
    return 0;
}
Catch signal 2
2024.07.28
localeconv 数値の書式に関するロケール(地域・言語)情報を取得する
locale.h
struct lconv *localeconv(void)
return ロケール情報
数値の書式に関するロケールのカテゴリ
LC_MONETARY(通貨の形式)
LC_NUMERIC(数値の形式)
の現在のロケール設定を取得する。
#include <stdio.h>
#include <locale.h>

int main(int argc, char *argv[])
{
    struct lconv *conv;

    setlocale(LC_ALL, "ja_JP.UTF-8");
    conv = localeconv();

    printf("[%s] 小数点文字\n",
        conv->decimal_point);
    printf("[%s] 千の区切り文字\n",
        conv->thousands_sep);
    printf("[%s] 国際通貨記号\n",
        conv->int_curr_symbol);
    printf("[%s] ローカル通貨記号\n",
        conv->currency_symbol);
    printf("[%s] 通貨の小数点文字\n",
        conv->mon_decimal_point);
    printf("[%s] 通貨の千の区切り文字\n",
        conv->mon_thousands_sep);
    printf("[%s] 正の数値を表す記号\n",
        conv->positive_sign);
    printf("[%s] 負の数値を表す記号\n",
        conv->negative_sign);
    printf("[%d] 国際分割桁\n",
        conv->int_frac_digits);
    printf("[%d] ローカル分割桁\n",
        conv->frac_digits);

    return 0;
}
[.] 小数点文字
[,] 千の区切り文字
[JPY ] 国際通貨記号
[¥] ローカル通貨記号
[.] 通貨の小数点文字
[,] 通貨の千の区切り文字
[] 正の数値を表す記号
[-] 負の数値を表す記号
[0] 国際分割桁
[0] ローカル分割桁
2024.07.28
localtime 紀元(Epoch)からの経過秒数をtm構造体に変換する(日本時間)
time.h
struct tm *localtime(const time_t *timep);
timep 紀元(Epoch)からの経過秒
return tm構造体のポインタ
戻り値で参照されるtm構造体は静的な構造体領域のポインタなので、gmtime()を実行するたびに構造体の内容は更新される。
紀元(Epoch 1970-01-01 00:00:00 (UTC))からの経過秒数から、日付時刻をtm構造体に変換する。
tm構造体には、年月日時分秒曜日の各要素のメンバ変数に値が設定される。tm構造体に格納される時刻は現地時刻(日本時間)である。
struct tm {
    int tm_sec;        /* 秒 (0-60) */
    int tm_min;        /* 分 (0-59) */
    int tm_hour;       /* 時間 (0-23) */
    int tm_mday;       /* 月内の日付 (1-31) */
    int tm_mon;        /* 月 (0-11) */
    int tm_year;       /* 年 - 1900 */
    int tm_wday;       /* 曜日 (0-6, 日曜 = 0) */
    int tm_yday;       /* 年内通算日 (0-365) */
    int tm_isdst;      /* 夏時間 */
};
月が0から始まることに注意。
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    time_t t;
    struct tm *t_tm;

    time(&t);
    t_tm = localtime(&t);

    printf("\t%d\n",t_tm->tm_year+1900);
    printf("\t%d\n",t_tm->tm_mon+1);
    printf("\t%d\n",t_tm->tm_mday);
    printf("\t%d\n",t_tm->tm_hour);
    printf("\t%d\n",t_tm->tm_min);
    printf("\t%d\n",t_tm->tm_sec);
    printf("\t%d\n",t_tm->tm_wday);
    printf("通算日\t%d\n",t_tm->tm_yday);
    printf("夏時間\t%d\n",t_tm->tm_isdst);

    return 0;
}
年  2018
月  2
日  22
時  20
分  24
秒  21
曜  4
通算日  52
夏時間  0
2024.07.28
log 自然対数関数
math.h
double log(double x)
x 浮動小数点値
return xの自然対数
xの自然対数(eを底とする対数)を返す。
#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
    double x;

    printf("%f\n", log(2.718281828459));

    return 0;
}
1.000000
2024.07.28
log10 常用対数関数
math.h
double log10(double x)
x 浮動小数点値
return xの常用対数
xの常用対数(10を底とする対数)を返す。
#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
    double x;

    printf("%f\n", log10(10.0));

    return 0;
}
1.000000
2024.07.28
malloc 動的にメモリ領域を取得する
stdlib.h
void *malloc(size_t size)
void *calloc(size_t nmemb, size_t size)
nmemb ブロック数(calloc)
size 割り当てるバイト数(malloc)、ブロックサイズ(calloc)
return 割り当てられたメモリ領域のポインタ
NULL: 失敗 
malloc()は、sizeバイトのメモリ領域を取得する。
割り当てられたメモリは0でクリアされている保証はない。
calloc()は、nmemb個のsizeバイト(nmemb x sizeバイト)のメモリ領域を取得する。
取得した領域は自動的に0でクリアされる。
動的に確保したメモリはfree()で解放(返却)する。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char *p;

    p = (char *)malloc(10);
    memcpy(p, "ABCDEFGHI", 10);
    puts(p);
    free(p);
    return 0;
}
ABCDEFGHI
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int *ar;
    int i;

    ar = (int *)calloc(3, sizeof(int));
    ar[ 0 ] = 10;
    ar[ 1 ] = 20;
    ar[ 2 ] = 30;
    for (i = 0 ; i < 3 ; i++)
        printf("%d\n", ar[ i ]);
    return 0;
}
10
20
30
2024.07.28
mblen マルチバイト文字のバイト数を調べる
stdlib.h
int mblen(const char *s, size_t n)
s 文字列(調べるマルチバイト文字)
n 最大バイト数
return マルチバイト文字のバイト数
-1: 有効なマルチバイト文字ではない
sの位置のマルチバイト文字のバイト数を調べる。
#include <stdio.h>
#include <locale.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "ja_JP.utf8");
    printf("あ len=%d\n", mblen("", 4)); // UTF-8
    printf("a  len=%d\n", mblen("a", 4));

    return 0;
}
あ len=3
a  len=1
2024.07.28
memchr メモリ領域内に最初に文字が現れる位置を探す
string.h
void *memchr(const void *s, int c, size_t n)
s メモリ領域の開始ポインタ
c 探す文字
n メモリ領域サイズ
return 探す文字に一致したメモリ領域の中のポインタ
NULL: 見つからない
sが示すポインタからnバイトまでのメモリ領域の中で、最初に文字cが現れる位置を探し、一致した位置をsの中のポインタで返す。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *p;
    p = (char *)memchr("ABCDE", 'C', 6);
    puts(p);

    return 0;
}
CDE
2024.07.28
memcmp メモリ領域を比較する
string.h
int memcmp(const void *s1, const void *s2, size_t n)
s1 比較元メモリ領域のポインタ
s2 比較先メモリ領域のポインタ
return 0: 一致する、0以外:一致しない
2つのメモリ領域s1とs2を先頭からnバイトまで比較する。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char s1[ 5 ] = { 0x11, 0x22, 0x33, 0x44, 0x55 };
    char s2[ 2 ] = { 0x11, 0x22 };  

    if (memcmp(s1, s2, 2) ==0 ) {
        puts("s1 = s2\n");
    }
    return 0;
}
s1 = s2
2024.07.28
memcpy メモリ領域をコピーする
string.h
void *memcpy(void *dest, const void *src, size_t n)
dest コピー先のメモリ領域のポインタ
src コピー元のメモリ領域のポインタ
n コピーするバイト数
return destのポインタ
メモリ領域srcからnバイトのデータをdestが示すメモリ領域へコピー(上書き)する。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char dest[ 6 ];
    char src[ ] = { 'A', 'B', 'C', 'D', 'E', 0 };
    memcpy(dest, src, 6);
    puts(dest);
    return 0;
}
ABCDE
2024.07.28
memmove メモリ領域をコピーする(メモリ重複可)
string.h
void *memmove(void *dest, const void *src, size_t n)
dest コピー先のメモリ領域のポインタ
src コピー元のメモリ領域のポインタ
n コピーするバイト数
return destのポインタ
メモリ領域srcからnバイトのデータをdestが示すメモリ領域へコピーする。
memcpy()と異なるのは、destとsrcの領域が重なっていても、srcの内容がコピー中に破壊しないことが保証されていることである。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char dest[ 8 ];
    dest[ 0 ] = 'A'; 
    dest[ 1 ] = 'B'; 
    dest[ 2 ] = 'C'; 
    dest[ 3 ] = '0'; 
    memmove(&dest[ 2 ], dest, 4);
    puts(dest);
    return 0;
}
ABABC0
memcpy()でもコンパイラによっては、重複するメモリ間でも正しくコピーできる結果になるかもしれないが、常に保証されているわけではない。
2024.07.28
memset メモリ領域をデータで埋める
string.h
void *memset(void *s, int c, size_t n)
s データを設定するメモリ領域のポインタ
c 設定するデータ(0x00~0xff)
n バイト数
return sのポインタ
メモリ領域sからnバイトの領域を、cで指定された1バイトデータを連続的に設定する。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char s[ 5 ];
    memset(s, 0, 5);
    memset(s, 'A', 4); 
    puts(s);
    return 0;
}
AAAA
2025.04.26
mkdir rmdir ディレクトリを作成・削除する[POSIX]
sys/stat.h
sys/types.h
int mkdir(const char *pathname, mode_t mode)
unistd.h
int rmdir(const char *pathname)
pathname 作成・削除するディレクトリのパス
mode 作成するディレクトリのファイルモード
ファイルモードはchmod()に指定するものと同様。
chmod()
return 0: 正常、-1: 失敗
mkdir()はディレクトリを作成する。
rmdir()は空のディレクトリを削除する。
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    mkdir("dir1", 0775);
    mkdir("dir2", 0775);
    rmdir("dir1");
    return 0;
}
2024.07.28
mktime 日付時刻(日本時間)を紀元からの経過秒数に変換する
time.h
time_t mktime(struct tm *tm)
tm 年月日時分秒曜日(現地時間)
return 紀元(Epoch 1970-01-01 00:00:00 (UTC))からの経過秒
tm構造体に格納されている日付時刻(日本時間)を、紀元(Epoch 1970-01-01 00:00:00 (UTC))からの経過秒数に変換する。
引数で与えるtm構造体のtm_wdayとtm_ydayは、実行時に再計算されて上書き更新される。
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    time_t t;
    struct tm t_tm;

    t_tm.tm_year = 118;
    t_tm.tm_mon = 1;
    t_tm.tm_mday = 2;
    t_tm.tm_hour = 0;
    t_tm.tm_min = 0;
    t_tm.tm_sec = 0;

    t = mktime(&t_tm);

    printf("EPOCH %lu\n", t);
    printf("wday %d\n", t_tm.tm_wday);
    printf("yday %d\n", t_tm.tm_yday);
    return 0;
}
EPOCH 1517497200
wday 5
yday 32
2024.07.28
modf 浮動小数点値を整数と小数に分解する
math.h
double modf(double x, double *iptr)
x 浮動小数点値
iptr 浮動小数点値xの整数部分
return 浮動小数点値xの小数部分
浮動小数点値xを整数と小数に分解し、小数を戻り値で返し、整数を引数のiptrに返す。
#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
    double s, d;

    s = modf(123.456, &d);
    printf("%f %f\n", d, s); 

    return 0;
}
123.000000 0.456000
2024.07.28
offsetof 構造体メンバの構造体先頭からのオフセットを得る
stddef.h
size_t offsetof(type, member)
type 構造体名
member 構造体typeのメンバ名
return 指定の構造体の先頭から指定したメンバまでのオフセットバイト数
構造体typeの先頭からメンバmemberまでのオフセットバイト数を求める。
typeは構造体の変数ではなく構造体名を指定し、memberも構造体のメンバ名を指定する。オフセット計算は、構造体アライメントが考慮される(個々の構造体メンバのサイズを上から順に加算した値と同じになるとは限らない)。
この関数はマクロで実装されている。
#include <stdio.h>
#include <stddef.h>

int main(int argc, char *argv[])
{
    struct ofs {
        char a[ 16 ];
        short b[ 2 ];
        int c; 
    };
    printf("a =%lu\n", offsetof(struct ofs, a)); 
    printf("b =%lu\n", offsetof(struct ofs, b)); 
    printf("d =%lu\n", offsetof(struct ofs, c)); 

    return 0;
}
a =0
b =16
c =20
2025.04.26
pause シグナルの捕捉を待機する[POSIX]
unistd.h
int pause(void)

return シグナルの捕捉が確認されpause()が返るときに常に-1を返す。
プロセスを中断する。プロセスを終了させるシグナルが捕捉された時点で中断から復帰し関数が返る。
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    printf("Hello\n");
    pause();        // CTRL-Cで待機が終了する
    return 0;
}
2024.07.28
perror システムエラーメッセージを出力する
errno.h
void perror(const char *s)
s システムエラーメッセージと共に出力する任意のメッセージ文字列
NULL: システムエラーメッセージのみ出力
直前に発生したシステムエラーのメッセージを標準出力に出力する。
#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    fp = fopen("ed5f89f718b", "r");
    if (fp == NULL) {
        perror("ERROR");
        perror(NULL);
    }

    return 0;
}
ERROR: No such file or directory
No such file or directory
2024.07.28
pow べき乗関数
math.h
double pow(double x, double y)
x 浮動小数点値
y べき乗
return xのy乗
xのy乗を求める。
#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
    printf("%f\n", pow(1.6, 3));

    return 0;
}
4.096000
2024.07.28
printf 書式に従い文字列を表示する
stdio.h
int printf(const char *format, ...)
int fprintf(FILE *stream, const char *format, ...)
int sprintf(char *str, const char *format, ...)
int snprintf(char *str, size_t size, const char *format, ...)
stream ファイルストリーム
str 格納先文字列バッファのポインタ
size 最大格納バイト数(終端NULLを含めて指定)
format 書式付出力文字列
... format中の書式に置き換えて出力する変数(可変長引数)
return 出力文字数(終端NULLは含まない)
負数: エラー
文字列をformatの書式に従いファイルまたはバッファへ出力(表示)する。
printf()は標準出力へ表示する。fprintf()はstreamのファイルへ出力し、sprintf()/snprintf()はバッファへ出力する。formatには可変長引数の各変数の値を出力するための書式を記述する。
sprintf()/snprintf()のstrには自動的に終端のNULL(0)が追加される。sizeは終端のNULL(0)を含めたサイズを指定する。この戻り値は、formatが書式変換後にstrに書き込もうとした終端NULLを除いた文字数なので、戻り値はsize未満でない場合は、strに格納する文字列の末尾が切り詰められたことを示している。文字列を切り詰めても終端のNULLは格納される。
sprintf()はsizeの指定がないので、strに確保した領域を超えて書き込まれる可能性がある。
formatに記述する書式は%に続けて次のように指定する。
%[フラグ][フィールド幅][.精度][長さ修飾子]変換指定子
formatの文字列に現れる%書式は、可変長引数の変数の並び順に対応し、それぞれの変数型で指定しなければならない。
#include <stdio.h>

int main(int argc, char *argv[])
{
    int             i       = 1000;
    short           si      = 65535;
    long            li      = 0xffffffff;

    unsigned int    ui      = 1000;
    unsigned short  us      = 65535;
    unsigned long   ul      = 0xffffffff;

    printf("int                     [%d]\n",    i);
    printf("short                   [%hd]\n",   si);
        /* short型は、%d %uでもかまわない */
    printf("long                    [%ld]\n",   li);

    printf("unsigned int            [%u]\n",    ui);
    printf("unsigned short          [%hu]\n",   us);
    printf("unsigned long           [%lu]\n",   ul);

    return 0;
}
int                     [1000]
short                   [-1]
long                    [-1]
            -->64bitの場合は4294967295が表示される
unsigned int            [1000]
unsigned short          [65535]
unsigned long           [4294967295]
#include <stdio.h>

int main(int argc, char *argv[])
{
    int             i       = 1000;

    printf("int    [%6d] (桁指定)\n", i);
    printf("int    [%06d] (桁指定 頭に0)\n", i);
    printf("int    [%+d] (常に符号付き) \n", i);
    printf("int    [%-6d] (左寄り) \n", i);
    printf("int    [%+06d] (桁指定&0付&符号付)\n", i);

    return 0;
}
int    [  1000] (桁指定)            
int    [001000] (桁指定 頭に0)      
int    [+1000] (常に符号付き)      
int    [1000  ] (左寄り)            
int    [+01000] (桁指定&0付&符号付) 
#include <stdio.h>

int main(int argc, char *argv[])
{
    int             i       = 1000;
    short           si      = 65535;
    long            li      = 0xffffffff;

    unsigned int    ui      = 1000;
    unsigned short  us      = 65535;
    unsigned long   ul      = 0xffffffff;

    printf("int                     [%x]\n",    i);
    printf("short                   [%hx]\n",   si);
    printf("long                    [%lx]\n",   li);

    printf("unsigned int            [%x]\n",    ui);
    printf("unsigned short          [%hx]\n",   us);
    printf("unsigned long           [%lx]\n",   ul);

    return 0;
}
int                     [3e8]
short                   [ffff]
long                    [ffffffff]
unsigned int            [3e8]
unsigned short          [ffff]
unsigned long           [ffffffff]
#include <stdio.h>

int main(int argc, char *argv[])
{
    int             i       = 1000;

    printf("int    [%x] (16進数)\n", i);
    printf("int    [%4x] (16進数 桁指定)\n", i);
    printf("int    [%04x] (16進数 桁指定 頭に0)\n", i);
    printf("int    [%X] (16進数 大文字)\n", i);
    printf("int    [%4X] (16進数 桁指定 大文字)\n", i);
    printf("int    [%04X] (16進数 桁指定 頭に0 大文字)\n", i);

    return 0;
}
int    [3e8] (16進数)                     
int    [ 3e8] (16進数 桁指定)              
int    [03e8] (16進数 桁指定 頭に0)        
int    [3E8] (16進数 大文字)              
int    [ 3E8] (16進数 桁指定 大文字)       
int    [03E8] (16進数 桁指定 頭に0 大文字) 
#include <stdio.h>

int main(int argc, char *argv[])
{
    float           f       = 3.1416;
    double          d       = 0.031416;

    printf("float    [%f]\n", f);
    printf("double   [%f]\n", d);
    printf("double   [%e] (指数形)\n", d);
    printf("float    [%5.3f] (桁/精度指定)\n", f);
    printf("float    [%07.3f] (桁精度指定 頭0)\n", f);
    printf("double   [%+f] (常に符号を表示)\n", d);
    printf("double   [%-10f] (左寄せ)\n", d);
    printf("double   [%-+10f] (符号&左寄せ) \n", d);

    return 0;
}
float    [3.141600]
double   [0.031416]
double   [3.141600e-02] (指数形)
float    [3.142] (桁/精度指定)
float    [003.142] (桁精度指定 頭0)
double   [+0.031416] (常に符号を表示)
double   [0.031416  ] (左寄せ)
double   [+0.031416 ] (符号&左寄せ)
#include <stdio.h>

int main(int argc, char *argv[])
{
    char            c       = '*'; 
    char            *s      = "ABCDEFG";

    printf("char     [%c]\n", c);
    printf("char     [%d] (整数で)\n", c);
    printf("char     [%x] (16進数で) \n", c);
    printf("string   [%s]\n", s);
    printf("string   [%10s] (桁指定)\n", s);
    printf("string   [%.4s] (最大桁指定)\n", s);
    printf("string   [%-10s] (桁指定&左寄せ)\n", s);

    return 0;
}
char     [*]
char     [42] (整数で)
char     [2a] (16進数で) 
string   [ABCDEFG]
string   [   ABCDEFG] (桁指定)
string   [ABCD] (最大桁指定)
string   [ABCDEFG   ] (桁指定&左寄せ)
#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("%%\n"); /* 「%」そのもの */

    return 0;
}
%
fprintftest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    int val = 100;
    FILE *fp;

    fprintf(stdout, "val=%d\n", val);
    fp = fopen("print.txt", "w");
    fprintf(fp, "val=%d\n", val);
    fclose(fp);
    return 0;
}
$ ./fprintftest
val=100
$ cat print.txt
val=100
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char str[ 8 ];
    int len;

    len = snprintf(str, sizeof(str), "val=%d", 1000); 
    printf("%s\nlen=%d\n", str, len);

    return 0;
}
val=100
len=8
本来「val=1000」と表示されるはずのところがサイズ制限で切り詰められている。lenが示す8とは、本来格納するはずだった「val=1000」の終端NULLを除いたバイト数。strには「val=100」+終端NULLの合計8バイトが格納される。
2024.07.28
putchar 標準出力へ1文字書き込む
stdio.h
int putchar(int c)
c 出力する文字
return 出力した文字
EOF: エラー
標準出力(通常は端末)へ1文字を出力(表示)する。
#include <stdio.h>

int main(int argc, char *argv[])
{
    int c;

    printf(">");
    c = getchar();
    putchar(c);

    return 0;
}
>M
M
2024.07.28
puts 標準出力へ文字列を書き込む
stdio.h
int puts(const char *s)
s 出力する文字
return 0以上: 成功、EOF: エラー
標準出力(通常は端末)へ文字列を出力(表示)する。
#include <stdio.h>

int main(int argc, char *argv[])
{
    puts("abcdefg");

    return 0;
}
abcdefg
2024.07.28
qsort 配列をソートする
stdlib.h
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
base ソートする配列の先頭ポインタ
ソート完了後は中身が元の順番から並び替えられている。
nmemb ソートする配列の要素数
size ソートする配列のひとつの要素のサイズ(バイト数)
compar 大小比較を行う関数
2つの引数を比較して、次の戻り値を返すものとする。
0: 引数1 = 引数2
負数: 引数1 < 引数2
1以上: 引数1 > 引数2
配列baseを、関数comparにより比較して配列をソートする。
baseはqsort()実行後に並び替えにより内容が変わる。baseはvoid型ポインタで指定し配列要素の型がわからないためsizeでサイズを指定する必要がある。
#include <stdio.h>
#include <stdlib.h>

int comp(const void * val1 , const void * val2)
{
    if(*(int *)val1 == *(int *)val2)
        return 0;
    else if(*(int *)val1 < *( int * )val2)
        return -1;
    return 1;
}

int main(int argc, char *argv[])
{
    int arr[ ] = { 3, 4, 12, 9, 0, 10 };
    int i;

    qsort(arr, 6, sizeof(int), comp);
    for (i = 0 ; i < 6 ; i++)
        printf("%d\n", arr[ i ]);
    return 0;
}
0
3
4
9
10
12
2024.07.28
raise シグナルを送信する
signal.h
int raise(int sig)
signum シグナル(signal()を参照)
return 0: 成功、0以外: エラー
自分自身のプロセスにシグナルsigを送信する。
#include <stdio.h>
#include <signal.h>

void sighdr(int s)
{
    printf("Catch signal %d\n", s);
}

int main(int argc, char *argv[])
{
    signal(SIGINT, sighdr);
    raise(SIGINT);

    return 0;
}
Catch signal 2
2024.07.28
rand 乱数を発生する
stdlib.h
int rand(void)
return 0~RAMD_MAX(通常は32767)の整数
0~RAMD_MAX(一般に32767)の間の整数の乱数を発生する。
rand()は、事前にsrand()で乱数のシード(種)を変更しない限り毎回同じパターンになるので、srand()と併用すべきである。
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int r, i;

    for (i = 0 ; i < 4 ; i++) {
        r = rand() % 10;
        printf("%d\n", r);
    }
    putchar('\n');
    srand(time(NULL));
    for (i = 0 ; i < 4 ; i++) {
        r = rand() % 10;
        printf("%d\n", r);
    }
    return 0;
}
3        0
6        9
7        9
5        6
2024.07.28
realloc 動的に割り当てられたメモリのサイズを変更する
stdlib.h
void *realloc(void *ptr, size_t size)
ptr サイズ変更前の動的に割り当てられたメモリ領域
size 変更後のサイズ
return サイズが変更されたメモリ領域のポインタ
malloc()などで動的に割り当てられたptrが示すメモリ領域のサイズをsizeに変更して再割り当てを行う。
ptrの変更前の領域のデータはサイズ変更後も保持される。ただし、サイズが小さくなる場合は元のデータの一部は消失する。
サイズ変更後のメモリ領域は新たに割り当てられるため、変更前とは異なる場所を指し示す。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char *p;

    p = (char *)malloc(10);
    memcpy(p, "ABCDEFGHI", 10);
    puts(p);
    p = (char *)realloc(p, 12);
    memcpy(p, "ABCDEFGHIJK", 12);
    puts(p);
    free(p);
    return 0;
}
ABCDEFGHI
ABCDEFGHIJK
2024.07.28
remove ファイル(ディレクトリ)を削除する
stdio.h
int remove(const char *pathname)
pathname 削除するファイルまたはディレクトリパス
return 0: 成功、-1: エラー
pathnameのパス名のファイルまたはディレクトリを削除する。
removetest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    remove("rm_file");
    remove("rm_dir");
    return 0;
}
$ touch rm_file
$ mkdir rm_dir
drwxrwxrwx 1 root root      0  3月 15 18:58 rm_dir
-rwxrwxrwx 1 root root      0  3月 15 18:58 rm_file

$ ./removetest
$ ls -l
(表示されない)
2024.07.28
rename ファイル(ディレクトリ)名を変更する
stdio.h
int rename(const char *oldpath, const char *newpath)
oldpath 変更前のファイルまたはディレクトリパス
newpath 変更後のファイルまたはディレクトリパス
return 0: 成功、-1: エラー
oldpathのパス名のファイルまたはディレクトリをnewpathのパス名に変更する。
変更後にカレントディレクトリ以外のパスを指定した場合は、そのディレクトリへ移動する。
ファイルの変更で、newpathがすでに存在している場合は置き換えられる。ディレクトリの変更で、newpathがすでに存在している場合は変更できない。
renametest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    rename("rn_file", "RN_FILE");
    rename("rn_dir", "RN_DIR");
    return 0;
}
$ touch rn_file
$ mkdir rn_dir
drwxrwxrwx 1 root root      0  3月 16 09:27 rn_dir
-rwxrwxrwx 1 root root      0  3月 16 09:27 rn_file

$ ./renametest
$ ls -l
drwxrwxrwx 1 root root      0  3月 16 09:27 RN_DIR
-rwxrwxrwx 1 root root      0  3月 16 09:27 RN_FILE
2024.07.28
rewind ファイルストリームの位置を先頭に移動する
stdio.h
void rewind(FILE *stream)
stream ファイルストリーム
開いているファイルstreamのアクセスを、ファイル先頭に移動する。
rewindtest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;

    if ((fp = fopen("file", "w")) != NULL) {
        fputs("012345", fp);
        rewind(fp);
        fwrite("ABC", 3, 1, fp);
        fclose(fp);
    }

    return 0;
}
$ ./rewindtest
$ cat file
ABC345
2024.07.28
scanf 書式に従いデータを入力する
stdio.h
int scanf(const char *format, ...)
int fscanf(FILE *stream, const char *format, ...)
int sscanf(const char *str, const char *format, ...)
str 入力文字列
stream ファイルストリーム
format 書式文字列
... formatに従い代入される変数(変数を参照するポインタでなければならない)のリスト(可変長引数)
return 解釈と代入が成功した個数
0: 最初から失敗したことを示す
EOF: 1つも変換せずに読み込みが終了した。または読み込みエラー
fscanf()は、ファイルstreamからの入力をformatに従い読み込み、可変長引数の各変数の値へ代入する。scanf()は標準入力から読み込む。sscanf()はstrの文字列を入力とする。
書式はprintf()の書式と同様な表記方法を使う。scanf()は標準入力から文字列を入力するので、端末でキーボード入力待ちになる。キーボード入力の場合、改行とスペース(タブ)は、文字列の末尾と解釈される。fscanf()のファイルstreamをstdinとした場合はscanf()と等価である。
#include <stdio.h>

int main(int argc, char *argv[])
{
    int val;
    char str[ 10 ];

    puts("int>");
    scanf("%d", &val);
    printf("[%d]\n\n", val);

    getc(stdin);    // 標準入力バッファに残留した改行の読み出し
    puts("str>");
    scanf("%s", str);
    printf("[%s]\n\n", str);

    getc(stdin);
    puts("int+str>");
    scanf("%d%s", &val, str);
    printf("[%d,%s]\n\n", val, str);

    getc(stdin);
    puts("#int>");
    scanf("#%d", &val);
    printf("[%d]\n", val);

    return 0;
}
int>
100
[100]

str>
ABCD
[ABCD]

int+str>
345 XYZ
[345,XYZ]

#int>
#999
[999]
#include <stdio.h>

int main(int argc, char *argv[])
{
    int val;
    FILE *fp;

    fp = fopen("scan.txt", "w");
    fprintf(fp, "1234");
    fclose(fp);

    fp = fopen("scan.txt", "r");
    fscanf(fp, "%d", &val);
    printf("[%d]\n", val);
    fclose(fp);
    return 0;
}
[1234]
#include <stdio.h>

int main(int argc, char *argv[])
{
    int val;
    char data[ 10 ];

    printf("data> ");
    scanf("%s", data);
    sscanf(data, "%d", &val);
    printf("[%d]\n", val);
    return 0;
}
data> 500
[500]
2024.07.28
setbuf ストリームにバッファを指定する
stdio.h
void setbuf(FILE *stream, char *buf)
stream ファイルストリーム
buf ストリームに割り当てるバッファ
NULLを指定すると、ユーザバッファの指定を解除する。
return 0: 成功、0以外: エラー
ファイルストリームstreamにシステムから自動的に用意される入出力バッファの代わりに、ユーザが用意したバッファbufを割り当てる。
bufに用意するバッファのサイズはBUFSIZを指定すべきである。
#include <stdio.h>

int main(int argc, char *argv[])
{
    char buf[BUFSIZ];

    setbuf(stdout, buf);
    printf("ABCDEFG\n");
    buf[ 0 ] = 'X';
    sleep(5);
    fflush(stdout);
    setbuf(stdout, NULL);

    return 0;
}
(5秒後に表示する)
XBCDEFG
2024.07.28
setlocale ロケール(地域・言語)を設定する
locale.h
char *setlocale(int category, const char *locale)
category カテゴリ
LC_ALL: すべてのカテゴリ
LC_COLLATE: 文字列の比較や変換
LC_CTYPE: 文字の種類
LC_MONETARY: 通貨の形式
LC_NUMERIC: 数値の形式 (小数点など)
LC_TIME: 日付/時刻の形式
locale 次のフォーマットに従うロケールの指定
language[_territory][.codeset][@modifier]
例 en_US.utf8, ja_JP.utf8
あるいは、"C"を指定するとANSI規格に最低限準拠のデフォルトの指定、空文字にすると処理系に依存を意味する。
return categoryに設定されているロケール文字列
NULL: エラー
ロケール(国/地域に固有な言語、数値表記、日時表記、通貨表記)を設定する。またはlocaleをNULLとして呼び出すことで、指定のcategoryに現在設定されているロケールの文字列を取得する。
categoryに設定対象のロケールのカテゴリの種別値を指定する。文字列localeには、そのカテゴリに設定したいロケーションを示す文字列を指定する。Linuxでは、システムがサポートしているロケールを「local -a」コマンドで調べることができる。
#include <stdio.h>
#include <time.h>
#include <locale.h>

int main(int argc, char *argv[])
{
    time_t  t;
    struct tm *t_tm;
    char s[ 128 ];

    t = time(NULL);
    time(&t);
    t_tm = localtime(&t);
    strftime(s, sizeof(s), "%c", t_tm);
    printf("%s\n", s);

    if (setlocale(LC_TIME, "ja_JP.UTF-8") != NULL) {
        strftime(s, sizeof(s), "%c", t_tm);
        printf("%s\n", s);
    }

    return 0;
}
Tue May  1 14:16:01 2018
2018年05月01日 14時16分01秒
2024.07.28
setvbuf ストリームにバッファを指定する(モード指定)
stdio.h
int setvbuf(FILE *stream, char *buf, int mode, size_t size)
stream ファイルストリーム
buf ストリームに割り当てるバッファ
mode _IOFBF: フルバッファリング(バッファフルまでデータを書き込まない)
_IOLBF: 行バッファリング(改行文字が入ると書き込む)
_IONBF: バッファリングしない(bufとsizeは無視される)
size バッファサイズ
return 0: 成功、0以外: エラー
ファイルストリームstreamにシステムから自動的に用意される入出力バッファの代わりに、ユーザが用意したバッファbufを割り当てる。
モードmodeで、バッファリングの振る舞いを指定できる。指定するバッファbufのサイズをsizeで指定できる。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char buf[5];

    setvbuf(stdout, buf, _IOFBF, 5);
    putchar('A');
    putchar('B');
    putchar('C');
    putchar('D');
    sleep(3);
    putchar('E');
    setvbuf(stdout, buf, _IOLBF, 5);
    // 改行での書き出しに変更する。次の改行でEと改行が書出される
    putchar('\n');

    return 0;
}
3秒後に表示される
ABCDE
2024.07.28
signal シグナルハンドラを設定する
signal.h
void (*signal(int signum, void (*sighandler)(int signum)))(int signum);
signum シグナル  
  SIGHUP (1) ハングアップ検出、プロセスの死亡
  SIGINT (2) キーボード割り込み (Ctrl-C)
  SIGQUIT (3) キーボードによる中止 (Ctrl-Break)
  SIGILL (4) 不正な命令
  SIGABRT (6) abort()からの中断
  SIGFPE (8) 浮動小数点例外
  SIGUSR1 (10) ユーザー定義シグナル1
  SIGSEGV (11) 不正なメモリー参照
  SIGUSR2 (12) ユーザー定義シグナル2
  SIGPIPE (13) 読み手の無いパイプへの書き出し
  SIGALRM (14) alarm()からのタイムアウト
  SIGTERM (15) 終了要求
  SIGCHLD (17) 子プロセスの一時停止または終了
  SIGCONT (18) 一時停止 からの再開
  SIGTSTP (20) 端末より入力された一時停止
  SIGTTIN (21) バックグランドプロセスの端末入力
  SIGTTOU (22) バックグランドプロセスの端末出力
sighandler シグナルハンドラ
return シグナルハンドラ
SIG_ERR: エラー
シグナルsignumが発生時に実行するハンドラsighandlerを設定する。
signaltest.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void sighdr(int s)
{
    printf("Catch signal %d\n", s);
    exit(0);
}

int main(int argc, char *argv[])
{
    if (signal(SIGINT, sighdr) == SIG_ERR) {
        printf("error\n");
    }
    pause();
    return 0;
}
$ ./signaltest
(キーボードからCTRL-Cを入力)
^CCatch signal 2
$
SIGKILL(9)とSIGSTOP(19)は捕捉できない。
2025.04.26
sleep 指定秒数の間実行を休止する[POSIX]
unistd.h
unsigned int sleep(unsigned int seconds)
seconds 休止秒数
return 指定する秒数を休止した場合は0、割り込みで中断した場合は残り秒数。
引数に指定する秒数の間実行を休止する。
止まっている間に(無視できない)シグナルが割り込んだ場合、sleep()が中断される。※
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    sleep(3);               // ここで3秒間プログラムが止まる
    printf("Sleep out");    // プログラム開始後3秒で表示される
    return 0;
}
コーディング上は正しく見えても時間通り停止していないという現象がまれに起こる。時間的なタイミングに厳しいシステムでのsleep()の使用には注意した方がよい。
2024.07.28
sqrt 平方根
math.h
double sqrt(double x)
x 浮動小数点値
return xの平方根
値xの平方根を求める。
#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
    printf("%f\n", sqrt(2.0));

    return 0;
}
1.414214
2024.07.28
srand randが生成する乱数のシード(種)を設定する
stdlib.h
void srand(unsigned int seed)
seed 乱数発生のシード(種)の値
rand()が生成する乱数のシード(種)を設定する。
乱数を生成するrand()は毎回同じパターンの乱数を発生する。srand()により乱数のシード(種)となる整数値を設定した後でrand()を実行することで、乱数パターンを変化させることができる。ただし、rand()の乱数を毎回変化させるにはsrand()に指定するシードも毎回変えなければならない。
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int r, i;

    for (i = 0 ; i < 4 ; i++) {
        r = rand() % 10;
        printf("%d\n", r);
    }
    putchar('\n');
    srand(time(NULL));
    for (i = 0 ; i < 4 ; i++) {
        r = rand() % 10;
        printf("%d\n", r);
    }
    return 0;
}
3        0
6        9
7        9
5        6
2025.04.26
stat ファイルの状態を取得する[POSIX]
sys/types.h
sys/stat.h
unistd.h
int stat(const char *pathname, struct stat *buf)

pathname 状態を取得するファイル
buf 状態を格納する構造体ポインタ
return 0: 成功、-1:失敗
指定するファイルの状態情報(デバイス上の情報、アクセスモード、所有者、サイズなど)を取得する。
状態情報を格納するstruct statには次のメンバが定義されている。
dev_t     st_dev;     デバイスID
ino_t     st_ino;     inode番号
mode_t    st_mode;    アクセスモード
nlink_t   st_nlink;   ハードリンク数
uid_t     st_uid;     所有者のユーザーID
gid_t     st_gid;     所有者のグループID
dev_t     st_rdev;    デバイスID(特殊ファイルの場合)
off_t     st_size;    全体のサイズ[Byte]
blksize_t st_blksize; ブロックサイズ
blkcnt_t  st_blocks;  ブロック数[512B]
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    struct stat inf;
    stat("index.html", &inf);
    printf("devid:\t%d\n", (int)inf.st_dev);
    printf("inode:\t%d\n", (int)inf.st_ino);
    printf("mode:\t%08o\n", inf.st_mode);
    printf("nlink:\t%d\n", (int)inf.st_nlink);
    printf("uid:\t%d\n", (int)inf.st_uid);
    printf("gid:\t%d\n", (int)inf.st_gid);
    printf("devid2:\t%d\n", (int)inf.st_rdev);
    printf("size:\t%d\n", (int)inf.st_size);
    printf("blksiz:\t%d\n", (int)inf.st_blksize);
    printf("blkcnt:\t%d\n", (int)inf.st_blocks);
}
devid:  66306
inode:  3277768
mode:   00100664
nlink:  1
uid:    1000
gid:    1000
devid2: 0
size:   5728
blksiz: 4096
blkcnt: 16
2024.07.28
strcat 文字列を連結する
string.h
char *strcat(char *dest, const char *src)
char *strncat(char *dest, const char *src, size_t n)
dest 連結先の文字列のポインタ
src 連結する文字列のポインタ
n 連結する最大バイト数
return destのポインタ
文字列destの後ろに文字列srcを連結する。
destが確保しておくべき領域は、
(destの文字列の長さ<NULL含まず>) + (srcの文字列の長さ<NULL含まず>) + 1
strncat()は、
(destの文字列の長さ<NULL含まず>) + n + 1
バイト以上が必要。destは必ずNULL終端される。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char dest[ 3 + 4 + 1 ] = "ABC";
    char *src = "DEFG";

    puts(dest);
    puts(src);

    strcat(dest, src);
    puts(dest);

    return 0;
}
ABC
DEFG
ABCDEFG
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char dest[ 3 + 2 + 1 ] = "ABC";
    char *src = "DEFG";

    puts(dest);
    puts(src);

    strncat(dest, src, 2);
    puts(dest);

    return 0;
}
ABC
DEFG
ABCDE
2024.07.28
strchr 文字列中に最初に文字が現れる位置を探す
string.h
char *strchr(const char *s, int c)
s 文字列
c 探す文字
return 探す文字に一致した文字列sの中のポインタ
NULL: 見つからない
文字列sの中で、先頭から最初に文字cが現れる位置を探し、一致した位置を指す文字列sの中のポインタを返す。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *p;
    p = strchr("ABCDEFG", 'C');
    puts(p);

    return 0;
}
CDEFG   
2024.07.28
strcmp 2つの文字列を比較する
string.h
int strcmp(const char *s1, const char *s2)
int strncmp(const char *s1, const char *s2, size_t n)
s1 文字列1
s2 文字列2
n 比較するバイト数
return 0: 一致する、0以外: 一致しない
2つの文字列s1とs2を比較する。strncmp()の場合は先頭からnバイトまでを比較する。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char s[ 10 ];

    putchar('>');
    scanf("%s", s);
    if(strcmp("ABC", s) == 0)
        printf("ABC == %s\n", s);
    else
        printf("ABC != %s\n", s);

    return 0;
}
>ABV
ABC != ABV

>ABC
ABC == ABC
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char s[ 10 ];

    putchar('>');
    scanf("%s", s);
    if(strncmp("ABC", s, 3) == 0)
        printf("ABC == %s\n", s);
    else
        printf("ABC != %s\n", s);
    return 0;
}
>ABCDE
ABC == ABCDE
>ABEFG
ABC != ABEFG
2024.07.28
strcoll ロケールに基づいて2つの文字列を比較する
string.h
int strcoll(const char *s1, const char *s2)
s1 文字列1
s2 文字列2
return 0: 一致する、0以外: 一致しない
現在のロケール(LC_COLLATE)に従って、2つの文字列s1とs2を比較する。
#include <stdio.h>
#include <locale.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int     l;

    setlocale(LC_ALL, "ja_JP.utf8");
    l = strcoll("a c", "abc");
    printf("ja %d\n", l);
    setlocale(LC_ALL, "en_US.utf8");
    l = strcoll("a c", "abc");
    printf("en %d\n", l);

    return 0;
}
ja -66
en 1
2024.07.28
strcpy 文字列をコピーする
string.h
char *strcpy(char *dest, const char *src)
char *strncpy(char *dest, const char *src, size_t n)
dest コピー先のバッファ
src コピーする文字列
n コピーする最大バイト数
return destのポインタ
文字列srcを文字列バッファdestへコピーする。
destのバッファサイズは、srcの文字列の長さ+1バイト以上が必要。strncpy()の場合は、nがsrcの長さ以下の場合、destはNULL終端されない。たとえばsrcが"ABC"という文字列をdestにコピーするには、nは最低4でなければならない。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char dest[ 5 + 1 ];

    strcpy(dest, "ABCD");
    puts(dest);

    return 0;
}
ABCD
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char dest[ 5 + 1 ];

    strcpy(dest, "xxxxx");
    strncpy(dest, "ABCD", 4);
    puts(dest);
    strncpy(dest, "ABCD", 5);
    puts(dest);

    return 0;
}
ABCDx
ABCD
2024.07.28
strcspn 指定の文字を使っていない文字列の長さを得る
string.h
size_t strcspn(const char *s, const char *reject)
s 調べる文字列
reject 使わない文字のリスト
return rejectの中の文字を使わない連続したバイト数
文字列sの先頭から、rejectに含まれない文字だけを使った文字が連続するバイト数を返す。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int len;

    len = strcspn("C$D.8-20", "1234567890-");
    printf("%d\n", len);

    return 0;
}
4
2025.04.26
strdup 文字列をコピーする
string.h
char *strdup(const char *s)
s コピーする文字列
return コピーを生成した文字列のポインタ、NULL: メモリ確保失敗
指定文字列のコピーを生成する。
コピー先領域は動的にメモリを確保する。したがってstrdup()でコピーした文字列は、使用後にfree()で開放する必要がある。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *s = "ABCDEFG";
    char *copy = strdup(s);
    copy[0] = 'Z'; 
    printf("%s\n", s);      // オリジナル
    printf("%s\n", copy);   // 先頭文字が変更されている
    free(copy);
    return 0;
}
ABCDEFG
ZBCDEFG
POSIXからC23へ採用された標準ライブラリとしては新しい関数なので、コンパイラオプションを-std=c99のようにするとエラーになる。
2024.07.28
strerror システムエラー番号の説明文を返す
string.h
char *strerror(int errnum)
errnum システムエラー番号
return エラー番号の説明文の文字列ポインタ
システムエラー番号errnumが示すエラーを説明する文字列を返す。
一般的にerrnumには、システムエラー番号(errno.hで定義される番号)が格納されるグローバル変数errnoを指定する。
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    fp = fopen("ed5f89f718b", "r");
    if (fp == NULL) {
        puts(strerror(errno));
    }

    return 0;
}
No such file or directory
2024.07.28
strftime strptime 日付時刻を構造体・文字列間で変換する(フォーマット指定)
time.h
size_t strftime(char *s, size_t max, const char *format, const struct tm *tm)
char *strptime(const char *s, const char *format, struct tm *tm)
s 日付時刻を表す文字列を格納するバッファ
strftime()は引数戻り値、strptime()は入力。
max 終端NULLを含めた変換最長サイズ
format 書式
tm 年月日時分秒曜日情報
strftime()は入力、strptime()は引数戻り値。
return strftime()は変換した文字列長(終端NULLは含まない)
0: 長さがmaxで指定した値より大きくなる(エラー)
strptime()は変換で解釈した文字の次のポインタを返す。全て変換できたらNULLを返す。
strftime()は、tm構造体に格納されている日付時刻を、フォーマットに従った文字列に変換する。
strptime()はその逆を行う。ctime()やasctime()とは異なり、変換先文字列に静的なメモリ領域を使用しない。
strptime()は、POSIXの機能を有効にする_XOPEN_SOURCEマクロを定義する必要がある。
フォーマットは次の通り。
%c 一般的な日付時刻表記 Tue Feb 27 15:30:44 2018
2018年02月27日15時31分36秒
%Y 西暦4桁 2018
%C 西暦上2桁 19, 20..
%y 西暦下2桁 00~99
%m 月(1桁の場合先頭を0) "01"~"12"
%-m 月(1桁の場合先頭を空白) " 1"~"12"
%~m 月(1桁の場合先頭を詰める) "1"~"12"
%b 月の略名 Sep/9月
%B 月の名前 September/9月
%d 日(1桁の場合先頭を0) "01"~"31"
%-d 日(1桁の場合先頭を空白) " 1"~"31"
%~d 日(1桁の場合先頭を詰める) "1"~"31"
%A 曜日の名前 Tuesday/火曜日
%a 曜日の略名 Tue/火
%w 日曜日を0とした週の番号 0~6
%u 月曜日を1とした週の番号 1~7
%H 時(24時: 1桁の場合先頭を0) "00"~"23"
%_H 時(24時: 1桁の場合先頭を空白) " 0"~"23"
%-H 時(24時: 1桁の場合先頭を詰める) "0"~"23"
%I 時(12時: 1桁の場合先頭を0) "01"~"12"
%_I 時(12時: 1桁の場合先頭を空白) " 1"~"12"
%-I 時(12時: 1桁の場合先頭を詰める) "1"~"12"
%M 00~59
%S 00~59閏秒は「60」になる
%p 午前と午後表記 午前/午後、AM/PM
正午は午後、深夜0時は午前
%P 午前と午後表記(小文字表示) 午前/午後、am/pm
%n %t 改行・タブ
%% '%' 文字
%s 紀元 (Epoch) からの通算秒数
%z UTCからの時差 日本ならば+0900
#define _XOPEN_SOURCE
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    time_t t;
    struct tm *t_tm;
    char    s[ 128 ];

    time(&t);
    t_tm = localtime(&t);
    if (strftime(s, sizeof(s),
        "%Y/%m/%d %H:%M:%S %A", t_tm) > 0) {
        printf("%s\n", s);
        if (strptime(s, "%Y/%m/%d %H:%M:%S %A", t_tm) > 0) {
            printf("%s\n", asctime(t_tm));
        }
    }
    return 0;
}
2025/04/25 21:27:03 Friday
Fri Apr 25 21:27:03 2025
2024.07.28
strlen 文字列の長さを求める
string.h
size_t strlen(const char *s)
s 文字列
return 文字列の長さ(終端NULLを除くバイト数)
文字列sの長さ(バイト数)を返す。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int len;
    len = strlen("ABCDEFGHIJK");
    printf("len=%d\n", len);

    return 0;
}
len=11
2024.07.28
strpbrk 文字列から指定の文字が現れる位置を探す
string.h
char *strpbrk(const char *s, const char *accept)
s 調べる文字列
accept 文字のリスト
return 文字列sの先頭からacceptの文字に最初に一致した位置
NULL: 見つからない
文字列sの先頭から、文字列acceptに含まれるいずれかの文字が最初に現れる位置を返す。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *p;

    p = strpbrk("41_C+06A8", "ABC");
    puts(p);

    return 0;
}
C+06A8
2024.07.28
strrchr 文字列中に最後に文字が現れる位置を探す
string.h
char *strrchr(const char *s, int c)
s 文字列
c 探す文字
return 探す文字に一致した文字列sの位置
NULL: 見つからない
文字列sの中で、末尾から最初に文字cが現れる位置を探し、一致した位置を文字列sの中のポインタを返す。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *p;
    p = strrchr("ABCABC", 'B');
    puts(p);

    return 0;
}
BC
2024.07.28
strspn 指定の文字だけを使った文字列の長さを得る
string.h
size_t strspn(const char *s, const char *accept)
s 調べる文字列
accept 使う文字のリスト
return acceptの中の文字だけで連続するバイト数
文字列sの先頭から、文字列acceptに含まれる文字だけを使った文字が連続するバイト数を返す。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int len;

    len = strspn("32-06A8", "1234567890-");
    printf("%d\n", len);

    return 0;
}
5
2024.07.28
strstr 文字列中に部分文字列が一致する位置を探す
string.h
char *strstr(const char *s, const char *ps)
s 文字列
ps 探す部分文字列
return 探す部分文字列に一致した開始位置の文字列sの位置
NULL: 見つからない
文字列sの中で、先頭から最初に部分文字列psが一致する位置を探し、一致した文字列sの中のポインタを返す。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *p;
    p = strstr("ABCDEFG", "CDE");
    puts(p);
    p = strstr("ABCDEFG", "CDX");
    if (p == NULL)
        puts("NOT FOUND");

    return 0;
}
CDEFG
NOT FOUND
2024.07.28
strtod strtol strtoul 文字列を数値型に変換する
stdlib.h
double strtod(const char *n, char **endptr)
long int strtol(const char *n, char **endptr, int base)
unsigned long int strtoul(const char *n, char **endptr, int base)
n 数値を表す文字列
先頭に空白が入っていてもよい。+-の符号可。小数点可。指数Eの表記可。
endptr 数値として解釈できない文字が現れた文字列nの位置のポインタを引数戻り値で返す。全ての文字が変換できた場合はNULLが返る。
特に必要がない場合はNULLを指定する。
base 基数(進数)2~36
0: 文字列フォーマットから自動判別
先頭が0x、0で始まる場合16進数、8進数と解釈する。それ以外は10進数。
return 変換した数値(浮動小数点・整数)
HUGE_VAL: オーバーフロー
LONG_MIN: アンダーフロー
数値を表す文字列nを数値型(double、unsigned long)に変換する。
文字列全てが数値を表していなくても、先頭から変換できるところまで変換する。
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    double val;
    char *endptr;

    val = strtod("123.567", NULL);
    printf("123.567 = %10.4f\n", val);
    val = strtod("-1.23", NULL);
    printf("-1.23 = %10.4f\n", val);
    val = strtod("123e-2", NULL);
    printf("123e-2 = %10.4f\n", val);
    val = strtod("123.45XYZ", &endptr);
    printf("123.45XYZ = %10.4f endptr=%s\n", val, endptr);

    return 0;
}
123.567 =   123.5670
-1.23 =    -1.2300
123e-2 =     1.2300
123.45XYZ =   123.4500 endptr=XYZ
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    long val;
    char *endptr;

    val = strtol("123", NULL, 10);
    printf("123 = %ld\n", val);
    val = strtol("123", NULL, 8);
    printf("123(oct) = %ld\n", val);
    val = strtol("123", NULL, 16);
    printf("123(hex) = %ld\n", val);
    val = strtol("0x7Af", NULL, 0);
    printf("0x7Af = %04lx\n", val);
    val = strtol(" -12XYZ", &endptr, 0);
    printf(" -12XYZ = %ld endptr=%s\n",
        val, endptr);

    return 0;
}
123 = 123
123(oct) = 83
123(hex) = 291
0x7Af = 07af
 -12XYZ = -12 endptr=XYZ
2024.07.28
strtok 文字列をトークンに分割する
string.h
char *strtok(char *str, const char *delim)
str トークンを分割する文字列
strtok()実行の初回のみstrを指定する。2個目以降の実行ではNULLを指定する。
文字列定数は指定できない。
delim 区切り文字のリスト
return 分割したトークンのポインタ
NULL: 終了
文字列strを区切り文字delimで区切った部分文字列(トークン)に分割し返す。
delimは区切り文字とする複数の文字を文字列として与える。例えば「,」と空白を区切りとするならば、" ,"という文字列を指定する。文字列strが複数のトークンに区切られるならば、strtok()を複数回実行して先頭から順番に分割したトークンを取り出す。
初回に実行するstrtok()のstrのみ分割したい文字列のポインタを指定する。初回実行で先頭のトークンが戻り値で得られたら、次のトークンを取り出すためにstrtok()を呼び出す。このとき引数strにはNULLを指定する。2つ目以降のstrtok()のstrにはNULLを指定する。そしてstrtok()の戻り値にNULLが返ると、すべてのトークン分割が終了する。
strtok()は、初回に指定する文字列strを2回目実行以降も保持する。注意すべきは、strtok()を実行するたびに、最初に与えた文字列strの中身にNULL終端を加えていくので、文字列strはstrtok()実行後は元の文字列が破壊されることである。従ってstrに文字列定数を与えることはできない。
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char str[] = "12A,BC DEFG,xyz89";
    char *p;

    p = strtok(str, " ,");
    puts(p);
    while ((p = strtok(NULL, " ,")) != NULL) {
        puts(p);
    }
    return 0;
}
12A
BC
DEFG
xyz89
2024.07.28
strxfrm ロケールに基づいた文字列に変換する
string.h
size_t strxfrm(char *dest, const char *src, size_t n)
dest 変換先文字列バッファ
src 変換元文字列
n 変換する最大バイト数
return 変換したバイト数(終端NULLは含まない)
文字列srcをロケールに基づいた文字列に変換し、バッファdestに格納する。
ロケールの設定によっては、2つの文字列をstrcmp()で比較した場合とstrcoll()で比較した場合の結果が異なることがある。そのような場合、比較する文字列をstrxfrm()で変換すると、strcmp()で比較した結果がロケールを考慮した比較を行うstrcoll()で比較した場合と同じ結果が得られるようになる。
#include <stdio.h>
#include <locale.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int l, c;
    char s1[ 4 ], s2[ 4 ];

    setlocale(LC_ALL, "en_US.utf8");
    l = strcoll("a c", "abc");
    c = strcmp("a c", "abc");
    printf("before:strcoll=%d strcmp=%d\n", l, c);
    strxfrm(s1, "a c", sizeof(s1));
    strxfrm(s2, "abc", sizeof(s2));
    l = strcoll(s1, s2);
    c = strcmp(s1, s2);
    printf("after:strcoll=%d strcmp=%d\n", l, c);

    return 0;
}
before:strcoll=1 strcmp=-1
after:strcoll=1 strcmp=1
2024.07.28
system シェルコマンドを実行する
stdlib.h
int system(const char *command)
command シェルのコマンドライン
return コマンドの終了ステータス
コマンドが終了したかどうかを調べるには、戻り値をWIFEXITEDマクロに通し、コマンドの終了ステータスの値は、戻り値をWEXITSTATUSマクロに通すことで得られる。
commandがNULLの場合で、シェルが有効ならば0以外を、シェルが利用できない場合は0を返す。
コマンドライン文字列commandのシェルコマンドを実行する。
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int st;

    st = system("sleep 5");

    while(!WIFEXITED(st));
    printf("Status %d\n", WEXITSTATUS(st));

    return 0;
}
(5秒後に)
Status 0
2024.07.28
time 紀元から現在までの経過秒数を得る
time.h
time_t time(time_t *t);   
紀元(Epoch)からの経過秒(戻り値と同じ値)
引数戻り値で取得する必要がない場合はNULLを指定する。
return 紀元(Epoch)からの経過秒
-1: エラー
紀元(Epoch 1970-01-01 00:00:00 (UTC))からOSの現在時刻までの経過秒数を返す。
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    time_t  t1, t2;

    t1 = time(NULL);
    time(&t2);
    
    printf("time return %lu arg %lu\n", t1, t2);
    return 0;
}
time return 1519294132 arg 1519294132

* 2018年2月22日19:00頃
2024.07.28
tmpfile 一時ファイルを作成する
stdio.h
FILE *tmpfile(void)
return ファイルストリーム
NULL: エラー
一時的なバイナリファイルを作成する。
fopen()のモードを"w+"で指定したファイルに相当するファイルストリームを開き、戻り値に返す。このファイルはfclose()で閉じるか、プログラムが終了した時点で自動的に削除される(そしてディスク上には残らない)。一時ファイルのファイル名を知ることはできない。一時ファイルはプログラム実行中にしか存在できない。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    char s[ 20 ];

    if ((fp = tmpfile()) != NULL) {
        fputs("ABCDEFG", fp);
        fseek(fp, 0, SEEK_SET);
        fwrite("1234", 3, 1, fp);
        fseek(fp, 2, SEEK_SET);
        fgets(s, sizeof(s), fp);
        fclose(fp);
    }
    puts(s);
    return 0;
}
3DEFG
2024.07.28
tmpnam 重複しない一時ファイルの名前を生成する
stdio.h
char *tmpnam(char *s)
生成した文字列を格納するバッファ
NULLを指定した場合は静的な領域に格納される。
return 生成した文字列へのポインタ
(バッファsを指定した場合はsへのポインタ)
一時ファイルのファイル名に利用できる重複しないでたらめな文字列を生成する。tmpnam()を呼び出すごとに異なる文字列を返す。
文字列バッファsを指定した場合は、生成された文字列はバッファsに格納され、sがNULLの場合は静的な文字列領域に格納される。Linuxでは生成される名前の先頭に/tmpのディレクトリが自動的に付加される。
#include <stdio.h>

int main(int argc, char *argv[])
{
    char name[ 256 ];
    int i;

    for (i = 0 ; i < 5 ; i++) {
        printf("%s\n", tmpnam(name));
    }
    return 0;
}
/tmp/filepcmjZr
/tmp/filei7m9k8
/tmp/filetqc0GO
/tmp/fileWUYS2u
/tmp/filelPNLob
2024.07.28
tolower 大文字を小文字に変換する
ctype.h
int tolower(int c)
c 変換する英大文字
return 変換した英小文字
英字以外と英小文字はそのまま
英字の大文を小文字に変換する。
#include <stdio.h>
#include <ctype.h>

int main(int argc, char *argv[])
{
    int c;

    c = tolower('A'); 
    printf("%c\n", c);
    c = toupper(c); 
    printf("%c\n", c);

    return 0;
}
a
A
2024.07.28
toupper 小文字を大文字に変換する
ctype.h
int toupper(int c)
c 変換する英小文字
return 変換した英大文字
英字以外と英大文字はそのまま
英字の小文字を大文字に変換する。
英字以外と英大文字はそのまま返す。
#include <stdio.h>
#include <ctype.h>

int main(int argc, char *argv[])
{
    int c;

    c = tolower('A'); 
    printf("%c\n", c);
    c = toupper(c); 
    printf("%c\n", c);

    return 0;
}
a
A
2024.07.28
va_start 可変長引数を解析する
stdarg.h
void va_start(va_list ap, last)
type va_arg(va_list ap, type)
void va_end(va_list ap)
ap 可変長引数を処理するための変数
last va_start()に指定する可変長引数関数の固定引数部分末尾の変数名
例えば可変長引数の関数func(a, b, v1, v2)のv1からが可変長ならば、va_start(ap, b)のように指定する。
type va_arg()が次に取り出す引数の型
return va_arg()は取り出した引数データを参照するポインタを返す。
可変長な引数をとる関数の引数を順番に読み出す。
va_start()は関数の可変長引数の開始を指定し初期化する。va_arg()は可変長引数引数の値を取り出す。va_end()は可変長引数解析の終了を宣言する。
int型の固定引数aとbの次から可変長引数が続く関数宣言は次の様になる。
func(int a, int b, ...)
可変長部分を「...」と表記する。この関数は、例えば次の様に呼び出す。
func(10, 20, "A", 3.24)
可変長部分「...」は0個以上。よって可変長引数なしでもかまわない。
func(10, 20)
va_arg()は、可変長区間の終了を自己検出する能力がないので、どこまで引数が存在するのかが検出できるように、他の固定引数を利用するなどの工夫をしなければならない。例えば、可変引数の個数を固定引数で指定する手段がある。
func(2, 'A', 2.4)
func(1, 'A')
末尾は必ずNULLや-1で終端するなどのルールをつける方法もある。
func(5, 2, 10, 8, -1)
func("AA", "BB", NULL)
またva_arg()は、引数の型を自動検出することもできない。そのためva_arg()の引数にはtypeにより型名を与えなければならない。可変長部分がどういう型の並びになっているかは、他の固定引数を使って知らせるか、特定の型で固定するなどの工夫が必要である。
#include <stdio.h>
#include <stdarg.h>

void list(int n, ...)
{
    va_list argp;

    va_start(argp, n);
    while (n > 0) {
        printf("[%s]\n", va_arg(argp, char*));
        n--;
    }
    va_end(argp);
    return;
}

int main(int argc, char *argv[])
{
    list(3, "AAA", "BBB", "CCC");
    return 0;
}
[AAA]
[BBB]
[CCC]
これらの関数はマクロである。
2024.07.28
ungetc ストリームに1文字戻す
stdio.h
int ungetc(int c, FILE *stream)
c ストリームに戻す1文字
stream ファイルストリーム
return 戻した文字
EOF: エラー
ファイル(入力ストリーム)へ文字を戻す。
直前にファイルから読み込んだ1文字をファイルストリームに戻して、またその文字を読みなおすことができる。
ungetctest.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    int c;

    c = fgetc(stdin);
    putchar(c);
    ungetc(c, stdin);
    c = fgetc(stdin);
    putchar(c);

    return 0;
}
$ echo A | ./ungetctest
AA
2024.07.28
vprintf 書式に従い文字列をファイルに書き込む(va_list指定)
stdarg.h
int vprintf(const char *format, va_list ap)
int vfprintf(FILE *stream, const char *format, va_list ap)
int vsprintf(char *str, const char *format, va_list ap)
int vsnprintf(char *str, size_t size, const char *format, va_list ap)
stream ファイルストリーム
str 格納先文字列バッファのポインタ
size 最大格納バイト数(終端NULLを含めて指定)
format 書式付出力文字列
ap 可変長引数を処理するための変数
return 出力文字数(終端NULLは含まない)
負数: エラー
文字列をformatの書式に従いファイルまたはバッファへ出力(表示)する。
va_start()とva_end()の区間で呼び出す。formatの書式の各値を出力する引数は、va_start()で設定したva_list型の可変長引数リストを指定する。
vprintf()は標準出力へ表示する。vfprintf()はstreamのファイルへ出力し、vsprintf()/vsnprintf()はバッファへ出力する。可変長引数をva_listで指定する以外は、printf()、fprintf()、sprintf()、snprintf()と同じである。
#include <stdio.h>
#include <stdarg.h>

void vlog(char *format, ...)
{
    va_list argp;
    va_start(argp, format);
    vprintf(format, argp);
    putchar('\n');
    va_end(argp);
}

int main(int argc, char *argv[])
{
    int     a = 10, b = 100;

    vlog("a = %d  b = %d", a, b);
    return 0;
}
a = 10  b = 100
vfprintftest.c
#include <stdio.h>
#include <stdarg.h>

void vlog(FILE *fp, char *format, ...)
{
    va_list argp;

    va_start(argp, format);
    vfprintf(fp, format, argp);
    va_end(argp);
}

int main(int argc, char *argv[])
{
    int a = 10, b = 100;
    FILE *fp;

    vlog(stdout,"a = %d  b = %d\n", a, b);
    fp = fopen("print.txt", "w");
    vlog(fp, "a = %d  b = %d", a, b);
    fclose(fp);

    return 0;
}
$ ./vfprintftest
a = 10  b = 100
$ cat print.txt
a = 10  b = 100
#include <stdio.h>
#include <stdarg.h>

void vlog(char *s, char *format, ...)
{
    va_list argp;

    va_start(argp, format);
    vsprintf(s, format, argp);
    va_end(argp);
}

int main(int argc, char *argv[])
{
    int a = 10, b = 100;
    char s[ 20 ];

    vlog(s, "a = %d  b = %d", a, b);
    puts(s);

    return 0;
}
a = 10  b = 100
#include <stdio.h>
#include <stdarg.h>

int vlog(char *s, int n, char *format, ...)
{
    va_list argp;
    int len;

    va_start(argp, format);
    len = vsnprintf(s, n, format, argp);
    va_end(argp);
    return len;
}

int main(int argc, char *argv[])
{
    int     a = 100, b = 1000;
    char    s[ 9 ];
    int     len;

    len = vlog(s, sizeof(s), "A%dB%d", a, b);
    printf("%s\nlen=%d\n", s, len);

    return 0;
}
A100B100
len=9
本来「A100B1000」と表示されるはずのところがサイズ制限で切り詰められている。lenが示す9とは、本来格納するはずだった「A100B1000」の終端NULLを除いたバイト数。strには「A100B100」+終端0の合計9バイトが格納される。
2024.07.28
sin cos tan 三角関数
math.h
double sin(double x)
double asin(double x)
double sinh(double x)
double cos(double x)
double acos(double x)
double cosh(double x)
double tan(double x)
double atan(double x)
double atan2(double y, double x)
double tanh(double x)
各種の三角関数。
sin() 正弦(サイン)
asin() 逆正弦(アークサイン)
sinh() 双曲線正弦(ハイパボリックサイン)
cos() 余弦(コサイン)
acos() 逆余弦(アークコサイン)
cosh() 双曲線余弦(ハイパボリックコサイン)
tan() 正接(タンジェント)
atan() 逆正接(アークタンジェント)xの逆正接
atan2() 逆正接(アークタンジェント)y/xの逆正接
tanh() 双曲線正接(ハイパボリックタンジェント)