[C言語] 文字列のコピー ポインタ変数の加算

自製str_copy関数のwhile文をポインタ変数の加算で書くと高速化できました。

以下のコードをそれぞれ走らせ処理時間を測ったところ、リストのインデックス加算に比べて1.5倍の速さになります。

strcpy関数はポインタ変数の加算になっているようです。

#include <stdio.h>

char *str_copy(char *d, const char *s)
{
	char *t = d;

	while (*d++ = *s++)
		;
	return t;
}

int main(void)
{
	char str[128] = "ABC";
	char tmp[128] = "DEF";

	printf("str = \"%s\"\n", str);

	str_copy(str, tmp);

	puts("コピーしました。");
	printf("str = \"%s\"\n", str);

	return 0;
}
#include <stdio.h>

char *str_copy(char *d, const char *s)
{
	int i=0;

	while (d[i] = s[i])
		i++;
	return d;
}

int main(void)
{
	char str[128] = "ABC";
	char tmp[128] = "DEF";

	printf("str = \"%s\"\n", str);

	str_copy(str, tmp);

	puts("コピーしました。");
	printf("str = \"%s\"\n", str);

	return 0;
}
import subprocess,time,datetime

start = time.time()

proc = subprocess.run("list1106_mac2", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
print(proc.stdout.decode('UTF-8'))

# 処理時間算出
process_time = time.time() - start
td = datetime.timedelta(seconds = process_time)
dt_now = datetime.datetime.now()

print('ポインタ加算 処理終了 ' + str(td) + ' ' + str(dt_now))

start2 = time.time()

proc = subprocess.run("list1106a_mac2", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
print(proc.stdout.decode('UTF-8'))

# 処理時間算出
process_time2 = time.time() - start2
td2 = datetime.timedelta(seconds = process_time2)
dt_now2 = datetime.datetime.now()

print('インデックス加算 処理終了 ' + str(td2) + ' ' + str(dt_now2))
--------------------------------------------------

出力
--------------------------------------------------
str = "ABC"
コピーしました。
str = "DEF"
ポインタ加算 処理終了 0:00:00.007981 2021-07-20 14:05:55.569973

str = "ABC"
コピーしました。
str = "DEF"
インデックス加算 処理終了 0:00:00.012111 2021-07-20 14:05:55.582141

[C言語] ポインタ渡し

ここまで学んだ段階で昨年読み進めていた新明解・入門編に再び目を通しました。

やはり10章 ポインタの説明が難解だったのと、最初の間違い例の解決法としてポインタ渡しを使っているところで戸惑いました。

Pythonユーザーからすれば、関数内で新たな変数が生成しているのに戻り値になっていない、戻り値に相当するはずの変数のポインタが引数になっている、あたりで混乱します。まあC言語が元祖ですからこちらが認識を改める他ないです。

この仕組みを利用すれば、関数の戻り値は引数にポインタ変数を入れることで何個でも設定できます。Pythonでは戻り値が複数の場合はタプルになっており、そこから各要素を取り出す手間がかかります。C言語にはそれがないのでかなり便利です。

教本の内容については、前にも書きましたがポインタの説明に男性名が値(身長)で女性名がポインタという例えを用いるのは分かりにくすぎていかがなものかと思います。

教本のコード例を私でも理解できるように書き改めました。sum_diff関数の第3引数と第4引数はアスタリスクをintに寄せてポインタ変数として表記する方が分かりやすいです。

ただアスタリスクが前に来ると2つ以上同じ行で宣言できなくなります。2つ目以降がint型になります。

int* a,b ではaはポインタ変数になるが、bは整数の変数になる。
int *a,*b が文法的には正しい。

理屈では前につけるべきだと思いますが、仕様上後ろに付ける方が実装する上でトラブルになりにくいです。

以前の記事で先に宣言した変数のアドレスがなぜ後ろの方なのか理由が分からないと書きました。それは後の変数を若い方に割り当てることでメモリからあふれるのを防ぐためではないかと考えています。本当のところを知りたいです。

#include <stdio.h>

void sum_diff(int n1, int n2, int* sum, int* diff)
{
	*sum  = n1 + n2;
	*diff = (n1 > n2) ? n1 - n2 : n2 - n1;
}

int main(void)
{
	int na, nb;
	int wa = 0, sa = 0;

	puts("二つの整数を入力してください。");
	printf("整数A:");   scanf("%d", &na);
	printf("整数B:");   scanf("%d", &nb);

	sum_diff(na, nb, &wa, &sa);

	printf("和は%dで差は%dです。\n", wa, sa);

	printf("naのアドレス %p\n",&na);
	printf("nbのアドレス %p\n",&nb);
	printf("waのアドレス %p\n",&wa);
	printf("saのアドレス %p\n",&sa);

	return 0;
}
--------------------------------------------------

出力
--------------------------------------------------
二つの整数を入力してください。
整数A:20
整数B:10
和は30で差は10です。
naのアドレス 0x7ffeecf685fc
nbのアドレス 0x7ffeecf685f8
waのアドレス 0x7ffeecf685f4
saのアドレス 0x7ffeecf685f0