プログラムで文字列を1つずつ作成していて、現在、単純な文字列を最後に追加するときにstrcat()を組み合わせて使用していますが、フォーマットされた文字列を追加するときは、sprintf()を使用しています。
int one = 1;
sprintf(instruction + strlen(instruction), " number %d", one);
strcat()を使用してフォーマットされた文字列を連結することは可能ですか、またはこれに推奨されるメソッドは何ですか?
プログラムで文字列を1つずつ作成していて、現在、単純な文字列を最後に追加するときにstrcat()を組み合わせて使用していますが、フォーマットされた文字列を追加するときは、sprintf()を使用しています。
int one = 1;
sprintf(instruction + strlen(instruction), " number %d", one);
strcat()を使用してフォーマットされた文字列を連結することは可能ですか、またはこれに推奨されるメソッドは何ですか?
あなたの解決策はうまくいくでしょう。strlenの呼び出しは少し厄介です(特に文字列が非常に長くなる場合)。sprintf()は、使用した長さを返します[strcatは返しません]。したがって、実行できることの1つは次のようなものです。
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()
呼び出すのを避けることができます。strlen()
len = 0;
len += sprintf(buf+len, "%s", str);
len += sprintf(buf+len, " number %d", one);
直接の質問に答えるために、確かに、フォーマットされた文字列を追加するために使用することが可能です。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の回答とmuxの回答を参照してください。少なくともこの場合、個々のフィールドを保持するために使用される個々の配列は必要ありません。
また、このコードは文字列の終わりを追跡しないため、パフォーマンスが低下する可能性があります。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()
です。それは良い考えではないでしょう。
推奨される方法は、何を使用するかによって異なります。これらすべての手動の(そして潜在的に危険な)文字列操作を行う代わりに、GLibGString
またはGLibのg_strdup_print
関数からのデータ構造を使用します。あなたの問題のために、 g_string_append_printf関数をGString
提供します。
必要に応じて独自のラッパーを作成します。
これへの呼び出しは次のようになります:-
result = universal_concatenator(4,result,"numbers are %d %f\n",5,16.045);
result = universal_concatenator(2,result,"tail_string");
sprintf()またはstrcat()を使用する必要がある場合は、心配する必要のある1つの関数を定義できます。これは関数がどのように見えるかです:-
/* 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
*/
最初に、2つのうちどちらを呼び出すか(strcatまたはsprintf)を決定し、次に呼び出しを行う必要があります。これにより、作業中の実際のロジックに集中しやすくなります。上記のctrl+cコードと、コードベースへのctrl+vだけです。
注:マットの答えは、長い文字列の良い代替手段です。ただし、文字列の長さが短い(<250)場合は、これで十分です。