問題① 次のプログラムの実行結果はどうなるでしょうか?
#include <stdio.h>
#include <string.h>
int main(void)
{
int a[5];
(a, 0xff, sizeof(a));
memset
for (int i = 0; i < 5; ++i) {
("%u ", a[i]);
printf}
("\n");
printf}
配列 a を構成する各バイトに 0xff が書き込まれます。これはビットの並びでいえば「11111111」ということです。
配列 a の要素は int型で、ここでは 32ビットであるとします。すると、たとえば a[0] の状態は「11111111 11111111 11111111 11111111」となります。a[1]、a[2] など、他の要素も同様です。
printf関数で要素の値を出力するとき、“%u” 変換指定子を使っているので、巨大な正の数として出力されることになります。結果はこうです。
実行結果:
4294967295 4294967295 4294967295 4294967295 4294967295
問題② memcmp関数を自作してください。
本編で、memchr関数の自作を行いました。基本的な考え方は同じで、voidポインタを char型のポインタに変換し、1バイトずつの操作を行えばよいです。
また、文字列特化版の strcmp関数の自作を、第33章の練習問題で行いました。ここではできるだけ、strcmp関数のときに似せた形で実装した例を挙げておきます。
#include <stdio.h>
#include <string.h>
int my_memcmp(const void* s1, const void* s2, size_t n)
{
const char* p1 = s1; // 1バイトずつ操作するため char型のポインタを用意
const char* p2 = s2; // 1バイトずつ操作するため char型のポインタを用意
for (size_t i = 0; *p1 == *p2; ++i) {
// 比較する範囲が終わっても、*p1 == *p2 を満たし続けたのなら、
// 両範囲は一致している
if (i >= n) {
return 0;
}
// 1バイトずつ進める
++p1;
++p2;
}
// 途中で一致しなくなったなら、その位置で大小比較して、適切な戻り値を返す
return (*p1 < *p2) ? -1 : 1;
}
int main(void)
{
int a1[] = {0, 1, 2, 3, 4};
int a2[] = {0, 1, 2, 4, 8};
("%d\n", my_memcmp(a1, a2, sizeof(a1)));
printf
(a1, a2, sizeof(a1));
memcpy("%d\n", my_memcmp(a1, a2, sizeof(a1)));
printf
[0] = 100;
a1("%d\n", my_memcmp(a1, a2, sizeof(a1)));
printf}
実行結果:
-1
0
1
問題③ memcpy関数を自作してください。
たとえば、次のようになります。
#include <stdio.h>
#define SIZE_OF_ARRAY(arrary) (sizeof(array)/sizeof(array[0]))
void* my_memcpy(void* s1, const void* s2, size_t size);
int main(void)
{
int array[] = {0, 1, 2, 4, 8};
int result[5];
(result, array, sizeof(array));
my_memcpy
for (int i = 0; i < SIZE_OF_ARRAY(result); ++i) {
("%d\n", result[i]);
printf}
}
/*
メモリ上のデータをコピーする。
引数
s1: コピー先のメモリアドレス。
s2: コピー元のメモリアドレス。
size: コピーするデータの大きさ。
戻り値
s1 と同じメモリアドレス。
*/
void* my_memcpy(void* s1, const void* s2, size_t size)
{
char* dest = s1;
const char* src = s2;
for (size_t i = 0; i < size; ++i) {
*dest = *src;
++dest;
++src;
}
return s1;
}
実行結果:
0
1
2
4
8
これも、voidポインタを char型のポインタに型変換して、1バイトずつ処理を行います。
【上級】本物の標準ライブラリの memcpy関数は、大抵は高度な最適化が施されており、もはや、C言語のコードで書かれていないことが多いです。たとえば、CPU が用意している命令を直接呼び出すアセンブリのコードになっているなどします。
{
の直後と、}
の直前に空白を入れない)()
の前後の空白の空け方)(
の直後、)
の直前に空白を入れない)return 0;
を削除(C言語編全体でのコードの統一)第38章から練習問題⑬を移動してきて、練習問題③とした。
この章にあったものを第35章へ移動して統合。
章のタイトルを変更(「ポインタ④ 動的なメモリ割り当て①」->「ポインタ④(バイト単位の処理)」)
全面的に文章を見直し、修正を行った。
章のタイトルを変更(「動的なメモリ」->「動的なメモリ割り当て」)
「*演算子」を「間接演算子」に統一。
C言語編全体で表記を統一するため、「“%d”フォーマット」のような表現に「変換指定子」を使うように改めた。
calloc関数の実引数の順番が逆になっていたのを修正。
新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |