2012-12-24 5 views
8

私のプログラムで文字列を1つずつ作成していますが、最後に単純な文字列を追加するときにstrcat()の組み合わせを使用していますが、私はsprintfの()などを使用しています:フォーマットされた文字列のためのstrcat()

int one = 1; 
sprintf(instruction + strlen(instruction), " number %d", one); 

が、それはこのためstrcatは()または何である好適な方法を使用してフォーマットされた文字列を連結することは可能でしょうか?

+0

十分なスペースがあることを確認してください。 – SLaks

答えて

12

あなたのソリューションが動作します。 strlenを呼び出すのは少し厄介です(特に文字列がかなり長くなった場合)。

char str[MAX_SIZE]; 
char *target = str; 

target += sprintf(target, "%s", str_value); 
target += sprintf(target, "somestuff %d", number); 
if (something) 
{ 
    target += sprintf(target, "%s", str_value2); 
} 
else 
{ 
    target += sprintf(target, "%08x", num2); 
} 

私はstrcatのは、はるかに効率的にsprintfよりもよく分からない()です:はsprintf()あなたが使用している長さを返しますが、[strcatのではないでしょう]ので、あなたが行うことができます一つのことは、このようなものですこのように使用された場合。

編集:

好ましい方法は何
+0

は私にとってはうまくいきません:(gdbで私はtarget + = ....と同様の行で見ています – Hooli

8

にはそれはできませんませんが、あなたはそれらの単純な文字列にsprintf()を使用してstrlen()たびに呼び出しを避けることができます:

len = 0; 
len += sprintf(buf+len, "%s", str);  
len += sprintf(buf+len, " number %d", one); 
+1

私の提案に似ています! –

+0

@MatsPetersson私は最初に答えた: – iabdalkader

+0

はい、私は長い例を書いた...;) –

0

、あなたが使用して喜んでいるかに依存し...小さい例を記述する必要があります。これらのすべての手動(および潜在的に危険な)文字列操作を行う代わりに、は、GLibまたはGLibのg_strdup_print関数のGStringデータ構造を使用します。問題の場合、GStringg_string_append_printfの機能を提供します。

+0

そして、私はsprintf(str + strlen(str)、fmt、args ...)とほぼ同じことをやっているでしょうか? –

+0

また、[http:// git。 gnome.org/browse/glib/tree/glib/gstring.c#n1154)メモリ割り当て/サイズ変更の答えは固定された文字列を仮定し、一度 'str_value2'が大きすぎると、あなたは釘付けになります。 – matthias

+0

それは本当です... –

0

必要に応じて独自のラッパーを作成します。

これへの呼び出しは次のようになります -

result = universal_concatenator(4,result,"numbers are %d %f\n",5,16.045); 
result = universal_concatenator(2,result,"tail_string"); 

は、あなたはsprintfの()やstrcatは()を使用する必要がある場合は、気にせの世話をするだろう一つの機能を定義することができます。これはあるに関数がどのように見えるか: -

/* you should pass the number of arguments 
* make sure the second argument is a pointer to the result always 
* if non formatted concatenation: 
*   call function with number_of_args = 2 
* else 
*   call function with number of args according to format 
*   that is, if five inputs to sprintf(), then 5. 
* 
* NOTE : Here you make an assumption that result has been allocated enough memory to 
*  hold your concatenated string. This assumption holds true for strcat() or 
*  sprintf() of your previous implementation 
*/ 

char* universal_concaternator(int number_of_args,...) 
{ 
    va_list args_list; 
    va_start(args_list,number_of_args); 
    int counter = number_of_args; 
    char *result = va_arg(args_list, char*); 
    char *format; 
    if(counter == 2) /* it is a non-formatted concatenation */ 
    { 
     result = strcat(result,va_arg(args_list,char*)); 
     va_end(args_list); 
     return result; 
    } 
    /* else part - here you perform formatted concatenation using sprintf*/ 
    format = va_arg(args_list,char*); 
    vsprintf(result + strlen(result),format,args_list); 
    va_end(args_list); 
    return result; 
} 

/* dont forget to include the header 
* <stdarg.h> #FOR-ANSI 
* or <varargs.h> #FOR-UNIX 
*/ 

それは第一に、それはそれは呼び出しを行い、そしてそれが簡単にあなたがするために作る必要があり、(strcatのかのsprintf)を呼び出す必要があり両者のどの、決定する必要がありますあなたが取り組んでいるものの実際の論理に集中してください! 上記のctrl + cコードとctrl + vをコードベースに追加するだけです。

注:長い文字列の場合は、マットの答えが良いです。しかし短い文字列長(< 250)の場合は、これが有効です。

+0

興味深い考え方ですが、入力にはデータを格納するために使用できるバッファの長さが含まれている必要があります。戻り値によって文字列に追加された文字の数が示されている場合には便利です。 –

+0

関数はそれを行うことができますあなたのためにいくつかの調整があります。私たちがメモリ境界を越えないようにするには、APIの内部で行うほうがいいですが、私は外部からそれを保証することを目指していました。コードをより簡単に、より速くします。それはデザインの選択です。 – wlan0

2

直接の質問に答えるには、確かにです。strcatを使用して書式設定された文字列を追加してください。あなただけの最初のフォーマットされた文字列を構築する必要があり、その後、あなたはそれを追加するstrcatを使用することができます。

#include <stdio.h> 
#include <string.h> 
int main(void) { 
    char s[100]; 
    char s1[20]; 
    char s2[30]; 
    int n = 42; 
    double x = 22.0/7.0; 

    strcpy(s, "n = "); 
    sprintf(s1, "%d", n); 
    strcat(s, s1); 

    strcat(s, ", x = "); 
    sprintf(s2, "%.6f", x); 
    strcat(s, s2); 

    puts(s); 
    return 0; 
} 

出力:

n = 42, x = 3.142857 

しかし、これは特に良い方法ではありません。

sprintfは、既存の文字列の最後にも同様に書き込みが行われます。例については、Mats's answerおよびmux's answerを参照してください。個々のフィールドを保持するために使用される個々の配列は、少なくともこの場合は必要ではありません。

このコードは文字列の最後を追跡しないため、パフォーマンスが低下する可能性があります。 strcat(s1, s2)は、最初にs1をスキャンして、終了を見つける必要があります。'\0'次にの内容をs2にコピーしてください。他の答えは、索引やポインタを進めて文字列の終わりを追跡し、再計算することなくこれを回避します。

また、コードはバッファオーバーランを回避するための努力をしていません。 strncat()はこれを行うことができますが、文字列を切り詰めるだけです。それは切り捨てられているとは言いません。 snprintf()は良い選択です。十分なスペースがある場合は、にはと書かれた文字数が返されます。これが指定したサイズを超えた場合、文字列は切り捨てられました。

/* other declarations as above */ 
size_t count; 
count = snprintf(s, sizeof s, "n = %d, x = %.6f", n, x); 
if (count > sizeof s) { 
    /* the string was truncated */ 
} 

と(一部は条件付きまたは繰り返し付加されている場合たとえば、)複数の文字列を追加するには、対象文字列の末尾を追跡するために他の回答のメソッドを使用することができます。

だから、strcat()の書式設定された文字列を追加することは可能です。それは良いアイデアではないようです。

関連する問題