前回と今回の記事では標準関数についてお話していきます。今回はよく使う標準関数を軽く触れていくような記事になっています。標準関数を使う際にはincludeしなければならないヘッダーファイルが決まっているので関数とセットで忘れないよう気をつけましょうね。
よく使われる関数にのみ焦点を当てているため、ここで紹介する関数が全てではないことは留意した上でご覧ください!
前回の復習
前回の記事ではファイルの読み書きについて勉強しました。標準関数の中でも特にややこしい部分なので先に取り上げる形にしましたが今回の記事にも簡単に載せているのでそこで復習してください。
FILE型のポインタ, fopen関数, fclose関数, fgetc関数, fputc関数, fgets関数, fputs関数あたりを自分で説明できれば文句なしです。頭の中で整理しておきましょう。(fread関数とfwrite関数も存在は知っておくと他人のコードに出てきた時に対処できます)
stdio.h
標準入出力(standard I/O)の略でstdioという名前のヘッダーファイルです。名前の通り入出力に関係する標準関数を使う際にインクルードしてあげる必要があります。
printf, scanf, puts, gets
標準入出力を行うための関数です。
関数 | 説明 |
---|---|
int printf(const char *, …) | 標準出力へ出力する |
int scanf(const char *, …) | 標準入力から入力する |
int puts(const char *) | 標準出力へ1行で出力する |
char *gets(char *) | 標準入力から1行分入力する(使用しないことが推奨されてる) |
#include <stdio.h>
int main() {
int a = 10, b;
char str[100];
printf("変数aの値は%dです\n", a);
puts("puts関数は最後に自動的に改行されます");
scanf("%d", &b);
gets(str); //実行してみると警告が出るかもしれません
printf("変数bの値は%dで、文字列strの値は%sです\n", b, str);
return 0;
}
実行結果
変数aの値は10です
puts関数は最後に自動的に改行されます
congrat //入力値
warning: this program uses gets(), which is unsafe.
変数bの値は1で、文字列strの値はcongratです
fopen, fclose, fputs, fgets, fprintf, fscanf
それぞれの関数の頭についているfはfileの意味です。ここで紹介するものはファイル操作に関係する標準関数になっています。
頭のfをとってみれば前の節でみた関数と同じものが4つあるので関連付けて覚えると効率よく身に着けることができると思います。
関数 | 説明 |
---|---|
FILE *fopen(const char *, const char *) | 1つ目の引数で指定されたファイルを2つ目で指定されたファイルモードで開く |
int fclose(FILE *) | 引数で指定されたファイルポインタで示されるファイルを閉じる |
int fprintf(FILE *, const char *, …) | ファイルへ出力する |
int fscanf(FILE *, const char *, …) | ファイルから入力する |
int fputs(const char *, FILE *) | 1つ目の引数で与えられた文字列を、2つ目の引数で指定したファイルポインタが示すファイルに出力する |
char *fgets(char *, int, FILE *) | 3つ目の引数で指定したファイルポインタが示すファイルから、1つ目で指定したchar型配列に入力する(2つ目の引数は最大文字列長) |
前回の記事で扱わなかったfprintfとfscanfのみサンプルコードを載せておきます。
残りの標準関数についてはファイルの読み書き【C言語講座 #16】を参照してください。
hello
#include <stdio.h>
int main() {
FILE *fp;
char msg[100];
fp = fopen("message.txt", "r+");
fscanf(fp, "%s", msg);
fprintf(fp, "メッセージは%sです\n", msg);
fclose(fp);
return 0;
}
実行結果
hello
メッセージはhelloです
sprintf, sscanf
それぞれの関数の頭についているsはstring(文字列)の意味です。ここで紹介するのは文字列からの入出力になります。
先程までの節と同様に頭のsをとってみれば同じような関数になりますね。
関数 | 説明 |
---|---|
int sprintf(char *, const char *, …) | 2つ目の引数のフォーマットに従って、文字列を1つ目の引数に出力する(代入する) |
int sscanf(const char *, const char *, …) | 2つ目の引数のフォーマットに従って、1つ目の引数の文字列から入力する |
#include <stdio.h>
int main() {
int a, b;
char arr[100];
char str[] = "10 30";
sscanf(str, "%d %d", &a, &b);
printf("変数aの値は%dで、変数bの値は%dです\n", a, b);
sprintf(arr, "%dと%dの和は%dです", a, b, a + b);
printf("%s\n", arr);
return 0;
}
実行結果
変数aの値は10で、変数bの値は30です
10と30の和は40です
stdlib.h
標準ライブラリ(standard library)の略でstdlibという名前のヘッダーファイルです。汎用性の高いものを集めたライブラリなので様々なものがあるのが特徴ですね。
malloc, calloc, free
これらはメモリ領域に対して処理を行う関数になります。mallocやcallocを用いてメモリ領域を確保し使い終わったらfree関数で領域を解除するように使います。
関数 | 説明 |
---|---|
void *calloc(size_t, size_t) | 2つ目の引数で指定したサイズ分のバイトを1つ目の引数で指定した個数分だけ確保する |
void *malloc(size_t) | 引数で指定したサイズの領域を確保する |
void free(void *) | 確保した領域を解放する |
#include <stdio.h>
#include <stdlib.h>
int main() {
int n = 3, sum = 0;
int *a;
a = (int *)calloc(n, sizeof(int));
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
sum += a[i];
}
printf("%d + %d + %d = %dです\n", a[0], a[1], a[2], sum);
free(a);
char *b;
b = (char *)malloc(n * sizeof(char)); //これでcallocと同じように使える
free(b);
return 0;
}
実行結果
15 62 34 //入力値
15 + 62 + 34 = 111です
srand, rand
この関数は乱数(random)を扱うために用意された関数になります。ただこの関数を使って得られる乱数列は確定的な計算によって得られるため疑似乱数と呼ばれています。そのため同じ値を渡すと同じ数列が生成されるので、乱数を扱うときはtime.hのtime関数を使って得られた値を引数に使うことが多いです。
関数 | 説明 |
---|---|
void srand(unsigned int) | 引数を用いて乱数表を作成する |
int rand(void) | 疑似乱数を返す(0 ~ RAND_MAXの値のいずれか。RAND_MAXはstdlib.hの中でdefineされているため確かめてみると良いだろう) |
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
int dice;
srand((unsigned int)time(NULL)); //乱数テーブルを生成
dice = rand() % 6 + 1;
printf("さいころの目は%dです\n", dice);
/*乱数テーブルさえ作ればrand()を呼び出すだけで何回でも疑似乱数が得られる*/
for(int i = 0; i < 5; i++) {
dice = rand() % 6 + 1;
}
printf("疑似乱数の最大値は%dです\n", RAND_MAX);
return 0;
}
実行結果
さいころの目は5です
疑似乱数の最大値は2147483647です //環境によっては異なる値になる可能性があります
atoi, atof, atol
これらの関数は文字列を数値に変換する際に使われる関数になります。atoiはASCII to integerの略、atolはASCII to long integerの略、atofはASCII to floating point numberの略となっています(atollとかもあります)。
ASCIIというのは文字コードのことでASCII規格の文字列を数値に変換することができます。
関数 | 説明 |
---|---|
int atoi(const char *) | 文字列をint型に変換する |
long atol(const char *) | 文字列をlong型に変換する |
double atof(const char *) | 文字列をdouble型に変換する |
#include <stdio.h>
#include <stdlib.h>
int main() {
char a[] = "123", b[] = "45";
printf("%s + %s = %dです\n", a, b, atoi(a) + atoi(b));
printf("%s + %s = %ldです\n", a, b, atol(a) + atol(b));
char c[] = "13.57", mix[] = "123abc";
printf("%f\n", atof(c));
printf("%d\n", atoi(mix));
return 0;
}
実行結果
123 + 45 = 168です
123 + 45 = 168です
13.570000
123
abs
絶対値を求めるための関数です。絶対値の関数だけmath.hじゃなくてstdlib.hに入ってるのも不思議ですが、おそらくchar同士の演算なんかをする際に使われることを想定してstdlibのヘッダーファイルに分類されたのでしょう。
関数 | 説明 |
---|---|
int abs(int) | 引数の絶対値を返す |
#include <stdio.h>
#include <stdlib.h>
int main() {
int a = -10, b;
b = abs(a);
printf("変数aの値は%dで、絶対値は%dです\n", a, b);
char ch = 'X';
int dif = abs('A' - 'a');
printf("%cの小文字は%cです\n", ch, ch + dif);
return 0;
}
実行結果
変数aの値は-10で、絶対値は10です
Xの小文字はxです
string.h
文字列(string)に関する標準関数を扱ったヘッダーファイルです。文字列の複製、連結、比較なんかをする関数が含まれています。
strcpy, strncpy, memcpy
ここで紹介するのは文字列のコピーを扱った関数になります。cpyはコピー(copy)のことを意味しています。strとmemは文字列とメモリの意味ですから何となくどんな関数なのかがわかりそうですね。
関数 | 説明 |
---|---|
char *strcpy(char *, const char *) | 2つ目の引数に指定した文字列を1つ目の引数に指定した文字列に複製する |
char *strncpy(char *, const char *, size_t) | 先頭から3つ目の引数で指定した文字数分だけ、2つ目の引数に指定した文字列を1つ目の引数に指定した文字列に複製する |
void *memcpy(void *, const void *, size_t) | 3つ目の引数で指定したサイズ分だけ、2つ目の引数に指定したメモリ領域を1つ目の引数に指定したメモリ領域に複製する |
#include <stdio.h>
#include <string.h>
int main() {
char a[100], b[100], c[100], original[] = "programming";
strcpy(a, original);
strncpy(b, original, 7); //"program"までしか複製されていないことに注意
b[7] = '\0'; //終端文字を追加する必要がある
memcpy(c, original, 12);
printf("%s\n", a);
printf("%s\n", b);
printf("%s\n", c);
return 0;
}
実行結果
programming
program
programming
strcat, strncat
ここで紹介するのは文字列の連結を扱った関数になります。catは連結(concatenate)のことを意味しています。(conから始まる英単語は山のようにあるのでcatが採用されたのかな)
関数 | 説明 |
---|---|
char *strcat(char *, const char *) | 2つ目の引数に指定した文字列を1つ目の引数に指定した文字列の後ろに連結する |
char *strncat(char *, const char *, size_t) | 3つ目の引数で指定した文字数分だけ2つ目の引数に指定した文字列を、1つ目の引数に指定した文字列の後ろに連結する |
#include <stdio.h>
#include <string.h>
int main() {
char a[100] = "abc", b[] = "DEFG"; //末尾に追加する関数のため片方の配列は追加分も考慮する必要がある
strcat(a, b);
printf("%s\n", a);
char c[100] = "123";
strncat(c, b, 2);
printf("%s\n", c);
return 0;
}
実行結果
abcDEFG
123DE
strcmp, memcmp
ここで紹介するのは文字列の連結を扱った関数になります。catは連結(concatenate)のことを意味しています。(conから始まる英単語は山のようにあるのでcatが採用されたのかな)
関数 | 説明 |
---|---|
int strcmp(const char *s1, const char *s2) | 1つ目と2つ目の引数で指定された文字列を比較する |
int memcmp(const void *, const void *, size_t) | 3つ目の引数で指定された分だけ、1つ目と2つ目のメモリ領域を比較する |
比較は辞書順に従う。
#include <stdio.h>
#include <string.h>
int main() {
char a[] = "abc", b[] = "abcd";
if(strcmp(a, b) < 0) {
printf("辞書順でaの方が先\n");
} else if(strcmp(a, b) > 0) {
printf("辞書順でbの方が先\n");
} else { //strcmp(a, b) == 0の場合
printf("aとbの文字列は同じ\n");
}
if(memcmp(a, b, 3) == 0) {
printf("aとbの最初の3バイトは同じ\n");
} else {
printf("aとbの最初の3バイトは違う\n");
}
return 0;
}
実行結果
辞書順でaの方が先
aとbの最初の3バイトは同じ
strlen
名前の通り文字列(string)の長さ(length)を得るための関数です。
関数 | 説明 |
---|---|
size_t strlen(const char *) | 引数に指定された文字列の長さを返す |
#include <stdio.h>
#include <string.h>
int main() {
char a[] = "abcdefg";
printf("文字列の長さは%ldです\n", strlen(a));
for(int i = 0; i < strlen(a); i++) {
if(a[i] == 'f') {
printf("文字列に\'f\'が含まれています\n");
}
}
return 0;
}
実行結果
文字列の長さは7です
文字列に'f'が含まれています
math.h
数学(math)に関するライブラリとなっている。数値計算を使う際にはお世話になるでしょう。
fabs
整数(int)のabsはstdlib.hに分類されていますが、小数(double型)の方はmath.hに分類されます。
関数 | 説明 |
---|---|
double fabs(double) | 引数に指定された小数の絶対値を返す |
#include <stdio.h>
#include <math.h>
int main() {
double a = -1.2345, res;
res = fabs(a);
printf("%lf\n", res);
return 0;
}
実行結果
1.234500
sin, cos, tan, asin, acos, atan, sinh, cosh, tanh
三角関数シリーズです。
関数 | 説明 |
---|---|
double sin(double) | sinを計算する |
double cos(double) | cosを計算する |
double tan(double) | tanを計算する |
double asin(double) | asinを計算する |
double acos(double) | acosを計算する |
double atan(double) | atanを計算する |
double sinh(double) | sinhを計算する |
double cosh(double) | coshを計算する |
double tanh(double) | tanhを計算する |
#include <stdio.h>
#include <math.h>
int main() {
double a = M_PI / 6.0; //M_PIは円周率, aは60°の時のラジアンとしてある
printf("sinの値は%lf、cosの値は%lf、tanの値は%lf\n", sin(a), cos(a), tan(a));
double b = 1.0;
printf("asinの値は%lf、acosの値は%lf、atanの値は%lf\n", asin(b), acos(b), atan(b));
double c = 0.0;
printf("sinhの値は%lf、coshの値は%lf、tanhの値は%lf\n", sinh(c), cosh(c), tanh(c));
return 0;
}
実行結果
sinの値は0.500000、cosの値は0.866025、tanの値は0.577350
asinの値は1.570796、acosの値は0.000000、atanの値は0.785398
sinhの値は0.000000、coshの値は1.000000、tanhの値は0.000000
log, log2, log10
対数に関する関数です。logは底がeの自然対数、log2は底が2の対数、log10は底が10の常用対数です。
関数 | 説明 |
---|---|
double log(double) | 自然対数を計算する |
double log2(double) | 底が2の対数を計算する |
double log10(double) | 常用対数を計算する |
#include <stdio.h>
#include <math.h>
int main() {
double a = M_E; //M_Eはネイピア数
printf("%lf\n", a);
printf("%lf\n", log(a));
double b = 8.0;
printf("%lf\n", log2(b));
double c = 100.0;
printf("%lf\n", log10(c));
return 0;
}
実行結果
2.718282
1.000000
3.000000
2.000000
exp, pow
やを求めることができる関数です。
関数 | 説明 |
---|---|
double exp(double) | 引数の値をとしたときのを計算する |
double pow(double, double) | 1つ目の引数の値を、2つ目の引数の値をとしたときのを計算する |
#include <stdio.h>
#include <math.h>
int main() {
double a = 3.2, b = 8.0;
printf("%lf\n", exp(b));
printf("%lf\n", pow(M_E, b)); //exp(b)と同じ
printf("%lf\n", pow(a, b));
return 0;
}
実行結果
2980.957987
2980.957987
10995.116278
sqrt, cbrt
平方根、立方根を求めるための関数です。
関数 | 説明 |
---|---|
double sqrt(double) | 引数の値の平方根を計算する |
double cbrt(double) | 引数の値の立方根を計算する |
#include <stdio.h>
#include <math.h>
int main() {
double a = 64.0;
printf("%lf\n", sqrt(a));
printf("%lf\n", cbrt(a));
return 0;
}
実行結果
8.000000
4.000000
hypot
知っておくと便利程度ですがこれを使うと簡単に斜辺が求まります。平方和の平方根を計算するのが定義ですがわかりやすく斜辺を求める関数と覚えておけば良いでしょう。
関数 | 説明 |
---|---|
double hypot(double, double) | 平方和の平方根を計算する |
#include <stdio.h>
#include <math.h>
int main() {
double a = 3.0, b = 4.0;
printf("%lf\n", hypot(a, b));
return 0;
}
実行結果
5.000000
time.h
時間(time)に関するヘッダーファイルです。
time
時刻の情報を取得できます。値はエポック秒になっているため場合によってはlocaltime関数などで整形する必要があります。
関数 | 説明 |
---|---|
time_t time(time_t *) | 時刻を返す |
#include <stdio.h>
#include <time.h>
int main() {
time_t a;
time(&a);
printf("%ld\n", a);
time_t b = time(NULL);
printf("%ld\n", b);
}
実行結果
1591259814
1591259814
difftime
2つの時刻の差(すなわち時間)を秒単位で求めることができる関数です。
関数 | 説明 |
---|---|
double difftime(time_t, time_t) | 2つの引数の時刻の差を返す |
#include <stdio.h>
#include <time.h>
int main() {
long temp = 0;
time_t a, b;
a = time(NULL);
/*適当な処理*/
for(int i = 0; i < 100000; i++) {
for(int j = 0; j < 10000; j++) {
temp++;
}
}
b = time(NULL);
printf("%lf\n", difftime(b, a));
return 0;
}
実行結果
2.000000
ctype.h
ぶっちゃけ個々の関数は知らなくてもif文で実装できますが、知っていると簡潔なコードが書けるようになるので余力があればここも覚えておきましょう。
isalnum, isalpha, isdigit, islower, isupper, isspace
isから始まるものは判定に使う関数です。
関数 | 説明 |
---|---|
int isalnum(int) | 引数がA-Zまたはa-zまたは0-9の時true(真)となり、それ以外の時はfalse(偽)となる |
int isalpha(int) | 引数がA-Zまたはa-zの時true(真)となり、それ以外の時はfalse(偽)となる |
int isdigit(int) | 0-9の時true(真)となり、それ以外の時はfalse(偽)となる |
int islower(int) | a-zの時true(真)となり、それ以外の時はfalse(偽)となる |
int isupper(int) | A-Zの時true(真)となり、それ以外の時はfalse(偽)となる |
isspace | 空白文字の時true(真)となり、それ以外の時はfalse(偽)となる |
#include <stdio.h>
#include <ctype.h>
int main() {
char a = 'a';
if(isalnum(a)) {
printf("変数aの値はアルファベットか数字です\n");
}
if(isalpha(a)) {
printf("変数aの値はアルファベットです\n");
}
if(isdigit(a)) {
printf("変数aの値は数字です\n");
}
if(islower(a)) {
printf("変数aの値は小文字のアルファベットです\n");
}
if(isupper(a)) {
printf("変数aの値は大文字のアルファベットです\n");
}
if(isspace(a)) {
printf("空白文字を検知しました\n");
}
return 0;
}
実行結果
変数aの値はアルファベットか数字です
変数aの値はアルファベットです
変数aの値は小文字のアルファベットです
tolower, toupper
小文字を大文字に、大文字を小文字に変換する関数です。
関数 | 説明 |
---|---|
int tolower(int) | 引数がA-Zの時アルファベットを小文字にする |
int toupper(int) | 引数がa-zの時アルファベットを小文字にする |
#include <stdio.h>
#include <ctype.h>
int main() {
char a = 'A', b = 'b', c = '+';
printf("%cにtolower関数を適用すると%cになる\n", a, tolower(a));
printf("%cにtoupper関数を適用すると%cになる\n", b, toupper(b));
printf("%cにtolower関数を適用しても%cのまま\n", c, tolower(c));
return 0;
}
実行結果
Aにtolower関数を適用するとaになる
bにtoupper関数を適用するとBになる
+にtolower関数を適用しても+のまま
まとめ
今回の記事ではよく使う標準関数と題して記事を書いたわけですが、作りたいものによって使うものが偏るのでこれで完璧とは言えません。ただここで紹介したものを知っておけばマニアックな関数や環境依存のライブラリを使ったコードでもない限り他人の書いたコードが読めるようになるでしょう。
最後まで記事を見ていただきありがとうございます。また別の記事でお会いできることを祈っております。