見出し画像

回答してみました ~ C言語教室 第7回 - 動的なメモリ割り当て ~

こちらの課題を回答してみました。

早速。

回答

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

char* salloc(char* str)
{
    size_t l = strlen(str);
    char* _s = malloc(l+1);

    if (_s != NULL)
    {
        strncpy(_s, str, l);
        _s[l] = '\0';
    }

    return _s;
}

void sfree(char* _s)
{
    if (_s != NULL)
    {
        free(_s);
    }
}

ちょこっと解説

文字列関連の標準関数を使ってしまった。

「strlen」の結果をチェックしようか(0より大きいかどうか)と思ったけど、「+1」して「malloc」するので、まぁいいかと。文字列が空だったら、空の文字列のポインタを返すだけだし。あまり簡単に NULL を返すのもどうかと思うし。

「NULL」と「\0」使い分けがあってるのかどうか。

「sfree」は課題にはないのですが、私はこのように対になる関数を作ることが多いです。今回は特に、いちいち「NULL」チェックをしたくなかったし。「salloc」の仕様が変わっても概ね「salloc」「sfree」内で対応できるでしょうし。

テストプログラム 

int main()
{
    {
        char* s = "abc";
        char* _s;
        _s = salloc(s);
        printf("0x%016lx %s\n", (unsigned long)s, s);
        printf("0x%016lx %s\n", (unsigned long)_s, _s);
        printf("\n");
        sfree(_s);
    }

    {
        char* s = "";
        char* _s;
        _s = salloc(s);
        printf("0x%016lx %s\n", (unsigned long)s, s);
        printf("0x%016lx %s\n", (unsigned long)_s, _s);
        printf("\n");
        sfree(_s);
    }

    {
        char a = 0;
        char* s = &a;
        char* _s;
        _s = salloc(s);
        printf("0x%016lx %s\n", (unsigned long)s, s);
        printf("0x%016lx %s\n", (unsigned long)_s, _s);
        printf("\n");
        sfree(_s);
    }

    {
        char a[5] = {1, 2, 3, 0x34, 5};
        char* s = a;
        char* _s;
        _s = salloc(s);
        printf("0x%016lx %s\n", (unsigned long)s, s);
        printf("0x%016lx %s\n", (unsigned long)_s, _s);
        printf("\n");
        sfree(_s);
    }

    return 0;
}

テスト結果

~/c $ ./a.out
0x000000634aaf3631 abc
0xb40000772bd7d230 abc

0x000000634aaf3630
0xb40000772bd7d230

0x0000007fc73e92d7
0xb40000772bd7d230

0x0000007fc73e92b8 4
0xb40000772bd7d230 4

~/c $

徹底的にテストしたとは言い難いけど。
めっちゃ長い文字列とか、「malloc」に失敗するようなケースは挙げられていません。

「malloc」で失敗するのは難しいだろうから、テスト用の「malloc」でやるしかないのかも。

最後のケースはちょいいじめてみた。


補足

せっかくコメントいただいたので補足。

「strncpy」のコピー範囲

「strncpy」は NULL がコピーされないんですね。
だから、「_s[l] = '\0';」が必要です。
初めての方は間違えやすいかも?

「free」は NULL を保証

関数「free」では NULL が保証されているのだそうです。ですから関数「sfree」では NULL チェックは不要ですね。
ご指摘ありがとうございました。


この記事が気に入ったらサポートをしてみませんか?