先頭へ戻る

ポインタ④(バイト単位の処理) 解答ページ | Programming Place Plus C言語編 第34章

Programming Place Plus トップページ -- C言語編 -- 第34章

先頭へ戻る

問題①

問題① 次のプログラムの実行結果はどうなるでしょうか?

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

int main(void)
{
    int a[5];
    
    memset( a, 0xff, sizeof(a) );
    
    for( int i = 0; i < 5; ++i ){
        printf( "%u ", a[i] );
    }
    printf( "\n" );
    
    return 0;
}


配列 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関数の自作を行いました。基本的な考え方は同じで、汎用ポインタを 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 };

    printf( "%d\n", my_memcmp(a1, a2, sizeof(a1)) );

    memcpy(a1, a2, sizeof(a1));
    printf( "%d\n", my_memcmp(a1, a2, sizeof(a1)) );

    a1[0] = 100;
    printf( "%d\n", my_memcmp(a1, a2, sizeof(a1)) );
    
    return 0;
}

実行結果:

-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];

    my_memcpy( result, array, sizeof(array) );

    for( int i = 0; i < SIZE_OF_ARRAY(result); ++i ){
        printf( "%d\n", result[i] );
    }

    return 0;
}

/*
    メモリ上のデータをコピーする。
    引数
        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

これも、汎用ポインタを char型のポインタに型変換して、1バイトずつ処理を行います。

本物の標準ライブラリの memcpy関数は、大抵は高度な最適化が施されており、もはや、C言語のコードで書かれていないことが多いです。たとえば、CPU が用意している命令を直接呼び出すアセンブリのコードになっているなどします。


参考リンク


------------------------------------------------------------------------

更新履歴

'2018/6/1 第38章から練習問題⑬を移動してきて、練習問題③とした。

'2018/5/29 この章にあったものを第35章へ移動して統合。

'2018/5/14 章のタイトルを変更(「ポインタ④ 動的なメモリ割り当て①」->「ポインタ④(バイト単位の処理)」)

≪さらに古い更新履歴を展開する≫



第34章のメインページへ

C言語編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
Twitter でツイート Twitter をフォロー LINE で送る
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー