Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

C言語 strncpy関数を自作する [ 修正版 ]

修正版

変更点が多かったため、新たに書き直しました。
関数を引数として渡すテストコードの作り方は今後のテストコードを書くのが楽になる。

manで定義を確認

NAME
     strncpy -- copy strings
SYNOPSIS
     char *strncpy(char * dst, const char * src, size_t len);
DESCRIPTION
     The stpncpy() and strncpy() functions copy at most len characters from src into dst.
     If src is less than len characters long, the remainder of dst is filled with `\0' characters.  
     Otherwise, dst is not terminated.
     The source and destination strings should not overlap, as the behavior is undefined.
RETURN VALUES
     The strcpy() and strncpy() functions return dst.

文字型配列 *dst に文字列 *src を先頭から len 文字コピーします。
① src の長さが len 以上のときには len 文字をコピーします(このときに '\0' の自動付加は行わない)
② src の長さが len より少ない場合には残りの文字を '\0' で埋めます。
動作が定義されていないため、ソース文字列と宛先文字列は重複してはなりません。

テストコード

前記事で頂いたコメントを元に書き換えました

void test00(char *dst, size_t dst_len, const char *src, size_t len, const char *function_name, char *strncpy_func(char *, const char *, size_t))
{
    /* dstを配列のサイズ分、'*'で埋める */
    memset(dst, '*', dst_len);

    /* 渡された関数を実行 */
    char *p = strncpy_func(dst, src, len);

    printf("%s(%p, \"", function_name, (void *)dst);

    /* print不可の文字を判別して表示する */
    for (size_t i = 0; i < strlen(src); i++)
    {
        if (isprint(src[i]))
        {
            /* %cは単一の文字を書き込む。unsigned char の文字を書き込むことに使う */
            printf("%c", src[i]);
        }
        // print不可 かつ 改行コードなら、改行コードをprintする
        else if (src[i] == '\n')
        {
            printf("\\n");
        }
    }

    /* %zuはsize_t型の書式指定子 整数値が表示される */
    printf("\", %zu) = %p\n", len, p);

    /* 文字列の文字コード表示 */
    for (size_t i = 0; i < dst_len; i++)
    {
        printf("%03u ", (unsigned char)dst[i]);
    }

    /* printできる文字はそのまま表示、できない文字は'.'として表示 */
    for (size_t i = 0; i < dst_len; i++)
    {
        printf("%c", isprint(dst[i]) ? dst[i] : '.');
    }

    printf("\n");
}

void test0(const char *str, size_t src_len)
{
    char dst[20];

    /* オリジナルと自作関数を渡して比較 */
    test00(dst, sizeof(dst), str, src_len, "strncpy", strncpy);
    test00(dst, sizeof(dst), str, src_len, "ft_strncpy", ft_strncpy);
    printf("\n");
}

void test(const char *src)
{
    /* 0,1,5,19文字を指定して、コピーさせる */
    test0(src, 0);
    test0(src, 1);
    test0(src, 5);
    test0(src, 19);

    size_t src_len = strlen(src);

    /* 文字数に応じて、テストケースを作成する */
    if (src_len > 2)
        test0(src, src_len - 1);

    if (src_len > 1)
        test0(src, src_len);

    if (src_len < 20)
        test0(src, src_len + 1);
}

int main()
{
    test("");
    test(",.;:;");
    test("hello world");
    test("12345");
    test("\n");
    test("\0");
    test("12fj3j4f");
    test("aaa\0aaa");
    return 0;
}

コード

char *ft_strncpy(char *dst, const char *src, size_t len)
{
    size_t i;

    i = 0;
    while (i < len && src[i])
    {
        dst[i] = src[i];
        i++;
    }
    while (i < len)
    {
        dst[i] = '\0';
        i++;
    }

    return dst;
}
keitean
初心者です。毎日勉強! @42tokyo
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away