Strcat() для форматированных строк

Я строю строку по частям в своей программе, и в настоящее время я использую сочетание strcat(), когда я добавляю простую строку в конец, но когда я добавляю форматированную строку, я использую sprintf ( ) например:

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

Можно ли объединить форматированную строку с помощью strcat() или какой из них является предпочтительным?

Ответ 1

Ваше решение будет работать. Вызов 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(), когда используется таким образом.

Изменить: следует писать меньшие примеры...

Ответ 2

Нет, это невозможно, но вы можете использовать sprintf() для этих простых строк и не вызывать strlen() каждый раз:

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

Ответ 3

Чтобы ответить на прямой вопрос, конечно, можно использовать 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 работает так же хорошо, как запись в конец существующей строки. Для примера см. Ответы на маты и mux 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(). Это вряд ли будет хорошей идеей.

Ответ 4

Какой предпочтительный метод, зависит от того, что вы готовы использовать. Вместо выполнения всех этих ручных (и потенциально опасных) строковых операций я использовал бы структуру данных GString из функции GLib или GLib g_strdup_print. Для вашей проблемы GString предоставляет функцию g_string_append_printf.

Ответ 5

Напишите свою собственную упаковку для своих нужд.

Призыв к этому будет выглядеть так: -

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 в базу кода.

Примечание. Ответ Matt является хорошей альтернативой длинным строкам. Но для коротких строк (< 250) это должно быть сделано.

Ответ 6

Все может быть проще

void strfcat(char *src, char *fmt, ...)
{
    char buf[2048];
    va_list args;

    va_start(args, fmt);
    vsprintf(buf, fmt, args);
    va_end(args);

    strcat(src, buf);
}

Используйте это как strcat().

strfcat(dst, "%d:%s:%c\n", 4,"bla",'c');
strfcat(dst, "%d:%d:%c\n", 4,13,'s');