4

文字の量をstrncpy考慮して、次のことを行うためのよりクリーンで効率的な方法があるかどうか疑問に思っています。maxやり過ぎ感がある。

int main(void)
{

        char *string = "hello world foo!";
        int max = 5;

        char *str = malloc (max + 1);
        if (str == NULL)
                return 1;
        if (string) {
                int len = strlen (string);
                if (len > max) {
                        strncpy (str, string, max);
                        str[max] = '\0';
                } else {
                        strncpy (str, string, len);
                        str[len] = '\0';
                }
                printf("%s\n", str);
        }
        return 0;
}
4

6 に答える 6

7

私はこれにはまったく使用strncpyしません。少なくとも、あなたがやろうとしていることを理解していれば、おそらく次のようなことをするでしょう。

char *duplicate(char *input, size_t max_len) {
    // compute the size of the result -- the lesser of the specified maximum
    // and the length of the input string. 
    size_t len = min(max_len, strlen(input));

    // allocate space for the result (including NUL terminator).
    char *buffer = malloc(len+1);

    if (buffer) {
        // if the allocation succeeded, copy the specified number of 
        // characters to the destination.
        memcpy(buffer, input, len);
        // and NUL terminate the result.
        buffer[len] = '\0';
    }
    // if we copied the string, return it; otherwise, return the null pointer 
    // to indicate failure.
    return buffer;
}
于 2012-05-03T04:35:57.147 に答える
3

まず、strncpyの場合、「宛先の末尾にnull文字が暗黙的に追加されないため、送信元のC文字列の長さがnum未満の場合にのみ、宛先はnullで終了します。」

strncpy()はすべてのコピーで各バイトの0をチェックするため、memcpy()を使用します。文字列の長さはすでにわかっていますが、memcpy()の方が高速です。

最初に文字列の長さを計算し、次に何を割り当ててコピーするかを決定します

int max = 5;               // No more than 5 characters

int len = strlen(string);  // Get length of string
int to_allocate = (len > max ? max : len); // If len > max, it'll return max. If len <= max, it'll return len. So the variable will be bounded within 0...max, whichever is smaller

char *str = malloc(to_allocate + 1); // Only allocate as much as we need to
if (!str) { // handle bad allocation here }

memcpy(str,string,to_allocate); // We don't need any if's, just do the copy. memcpy is faster, since we already have done strlen() we don't need strncpy's overhead

str[to_allocate] = 0; // Make sure there's a null terminator
于 2012-05-03T04:34:17.280 に答える
2

基本的にstrlcpy、1996 年に導入された を再発明しています。strlcpy と strlcat を参照してください。Todd C. Miller と Theo de Raadt による、一貫性のある安全な文字列のコピーと連結に関する論文です。glibc への追加が拒否されたため、聞いたことがないかもしれません。これは、glibc のメンテナーによって「恐ろしく非効率な BSD のがらくた」と呼ばれ、他のすべてのオペレーティング システムで採用されたときでさえ、今日まで戦っています。Damien Miller によるSecure Portabilityの論文を参照してください。 (パート 4: 適切な API の選択)。

Linux で strlcpy を使用するには、libbsdプロジェクト (Debian、Ubuntu、およびその他のディストリビューションにパッケージ化されています) を使用するか、Web で簡単に見つけられるソース コード (たとえば、この回答の 2 つのリンク) をコピーするだけです。

しかし、ここでソース文字列の長さを使用していない場合に最も効率的なものについての質問に戻ると、http://cvsweb.openbsd.org/cgi-binstrlcpyのOpenBSD のソースに基づく私の考えです。 /cvsweb/src/lib/libc/string/strlcpy.c?rev=1.11ただし、元の文字列の長さをチェックしていないため、非常に長くなる可能性がありますが、適切な '\0' で終わる可能性があります。

char *d = str;            // the destination in your example
const char *s = string;   // the source in your example
size_t n = max;           // the max length in your example

/* Copy as many bytes as will fit */
if (n != 0) {
    while (--n != 0) {
        if ((*d++ = *s++) == '\0')
            break;
    }
}

/* Not enough room in dst, add NUL */
if (n == 0) {
    if (max != 0)
        *d = '\0';      /* NUL-terminate dst */
}

これは、 memcpy を使用するhttp://cantrip.org/strlcpy.cの strlcpy のバージョンです。

/*
 * ANSI C version of strlcpy
 * Based on the NetBSD strlcpy man page.
 *
 * Nathan Myers <ncm-nospam@cantrip.org>, 2003/06/03
 * Placed in the public domain.
 */

#include <stdlib.h>  /* for size_t */

size_t
strlcpy(char *dst, const char *src, size_t size)
{
    const size_t len = strlen(src);
    if (size != 0) {
        memcpy(dst, src, (len > size - 1) ? size - 1 : len);
        dst[size - 1] = 0;
    }
    return len;
}

どちらがより効率的かは、ソース文字列に依存すると思います。非常に長いソース文字列の場合、strlen に時間がかかる場合があり、元の長さを知る必要がない場合は、最初の例の方が速いかもしれません。

それはすべてデータに依存するため、実際のデータをプロファイリングすることが唯一の方法です。

于 2016-06-26T06:10:49.397 に答える
0

これで十分だと思います。

char *str = malloc(max+1);
if(! str)
return 1;

int len = strlen(string);  
memset(str, 0, max+1);
int copy = len > max ? max : len;
strncpy(str, string, copy);
于 2012-05-03T04:33:49.783 に答える
0

次の方法でコードの量を減らすことができます。

int main(void)
{
    char *string = "hello world foo!";
    int max = 5;

    char *str = malloc(max + 1);
    if (str == NULL)
        return 1;
    if (string) {
        int len = strlen(string);
        if (len > max)
            len = max;
        strncpy(str, string, len);
        str[len] = '\0';
        printf("%s\n", str);
    }
    return 0;
}

さらに高速化するためにできることはあまりありませんstrncpy() 。以下を使用して時間を短縮できます。

char string[] = "hello world foo!";

strlen()代わりに使用して回避しsizeof(string)ます。

最大サイズが大きく、コピーする文字列が小さい場合strncpy()、ターゲット文字列の未使用の各位置に null を書き込むという事実により、実際に速度が低下する可能性があることに注意してください。

于 2012-05-03T04:31:43.503 に答える
0

strncpy()NUL に達すると自動的に停止します。maxチェックせずに合格するだけで十分です。

于 2012-05-03T04:31:45.157 に答える