13

我在我的程序中逐个构建一个字符串,当我在末尾添加一个简单的字符串时,我目前正在使用 strcat() 的混合,但是当我添加格式化的字符串时,我正在使用 sprintf() 例如:

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

是否可以使用 strcat() 连接格式化的字符串,或者什么是首选方法?

4

5 回答 5

17

您的解决方案将起作用。调用 strlen 有点尴尬(特别是如果字符串变得很长)。sprintf() 将返回您使用的长度 [strcat 不会],所以您可以做的一件事是这样的:

 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() 更有效。

编辑:应该写更小的例子......

于 2012-12-24T15:25:06.607 回答
9

不,这是不可能的,但您可以sprintf()在那些简单的字符串上使用并避免strlen()每次都调用:

len = 0;
len += sprintf(buf+len, "%s", str);    
len += sprintf(buf+len, " number %d", one);
于 2012-12-24T15:23:52.933 回答
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 的答案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(). 这不太可能是一个好主意。

于 2012-12-24T17:44:04.190 回答
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),应该这样做。

于 2012-12-24T16:23:12.017 回答
0

首选方法是什么,取决于您愿意使用什么。将使用GStringGLib 或 GLibg_strdup_print函数中的数据结构,而不是执行所有这些手动(并且可能是危险的)字符串操作。对于您的问题,GString提供g_string_append_printf函数。

于 2012-12-24T15:37:40.230 回答