2012-05-03 6 views
2

strncpyの文字数を考慮して、よりクリーンで効率的な方法があるかどうか疑問に思っています。私はそれを過ぎているように感じる。より効率的にCでstrncpyでn個の文字をコピー

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; 
} 
+0

ありがとうございました。すべての回答は素晴らしいです! –

答えて

6

をコピーします。 - トッドC.によってstrlcpy and strlcat - consistent, safe, string copy and concatenationペーパーを参照してください

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; 
} 
+0

あなたは '%。* s" 'を意味することを願っています... –

+0

@ IgnacioVazquez-Abrams:再読み込みし、スピード(sprintfの弱点)に重点を置いて考えると、代わりに 'memcpy'を使うようにしました。しかし、はい、私はそこに '.'を入れようとしていました... –

+0

あなたのバージョンは素敵でエレガントです。私はそれを+1しようとしていますが、なぜあなたはそれぞれのステップをとてもうまくやるのか説明していないと思います。 –

0

次の方法で、コードの量を減らすことができます:ずっとあなたがさらにstrncpy()をスピードアップするために行うことができますがありません

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

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

して、代わりに sizeof(string)を使用して strlen()を避ける:あなたが使用して時間を減らすことができます。

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

+0

あなたは 'スピードアップしたいときはstrncpyの代わりにmemcpy()を使うことができます;すでにstrlen()を行っているので、すべてのバイトコピーでNULLをチェックするためのstrncpyのオーバーヘッドは必要ありません。 –

0

strncpy()は、NULにヒットしたら自動的に停止します。チェックなしでmaxを渡すだけで十分です。

+0

@ std''OrgnlDave:あなたは**その次の行を見ました**はNULを追加しました。 ? –

+0

私の悪い。あなたのコメントの意思を誤読 –

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); 
+1

あなたが割り当てるメモリをゼロにしたい場合は、calloc()を使用してください。しかし、このソリューションでは効率的ではありません。さらに、strlen()をすでに行っていて、すべてのバイトでNULLをチェックする必要がないので、memcpyは高速です。 –

3

まず、strncpyをするために、「いいえヌル文字が暗黙のうちに目的地の最後に追加されていないので、先にのみ、NULLで終了する場合はCの長さソースの文字列がnum未満です。 "

memcpy()は、strncpy()がすべてのコピーで各バイトを0にチェックするために使用します。文字列の長さをすでに知っているので、memcpy()はより速くそれを行います。

まず、私は全然このためstrncpyを使用することはありません、文字列の長さを計算し、次に割り当てるために何を決定し、

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 
+0

'malloc'から返されるメモリをゼロにするべきではありませんか? – Asha

+0

@Asha calloc() –

+0

@Ashaを呼び出すことで0にすることができます。それはゼロにする理由はありません。 –

0

基本的には1996年に導入されたstrlcpyを再発明している:私はあなたが何をしようとして理解し、少なくともあれば、私はおそらくこのような何かをしたいですミラーとテオ・デ・ラート。 glibcの管理者が "恐ろしく非効率的なBSDのクラップ"と呼ばれ、他のすべてのオペレーティングシステムで採用されても今日まで戦ったのはrefused to be added to glibcだったからです.Damien Millerの論文(第4部:正しいAPI)。

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

しかし、私の考えはhttp://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/strlcpy.c?rev=1.11でのOpenBSDからstrlcpyソースではなくの長さを確認せずに基づいていますが、ここで元の文字列の長さを使用していないあなたの場合、最も効率的であるものに戻ってあなたの質問に行きますエンディング潜在的に非常に長いが、まだ適切であることも、元の文字列、「\ 0」:上

/* 
* ANSI C version of strlcpy 
* Based on the NetBSD strlcpy man page. 
* 
* Nathan Myers <[email protected]>, 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; 
} 

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にのバージョンがあります私はより効率的だと思う私はソース文字列に依存します。非常に長いソース文字列の場合、strlenは時間がかかるかもしれません。元の長さを知る必要がなければ、最初の例がより速くなるかもしれません。

すべてはあなたのデータに依存しているので、実際のデータをプロファイリングするだけで見つけることができます。

関連する問題