#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
int main(int argc, char * argv[])
{
char *arr[] = { "ab", "cd", "ef" };
char **ptr, **p, *str;
int num = 3;
int size = 0;
ptr = calloc(num, 4);
p = ptr;
for (; num > 0; num--)
size += strlen(*(p++) = arr[num - 1]);
str = calloc(1, ++size);
sprintf(str, "%s%s%s", ptr[0], ptr[1], ptr[2]);
printf("%s\n", str);
return 0;
}
输出:"efcdab"
符合预期。
现在,如果sprintf
的参数计数是预先确定的并且已知,那么这一切都很好并且合适。然而,如果参数计数是可变的(ptr[any]
),我想要实现的是构建字符串的一种优雅方式。
第一个问题:需要传递给sprintf
的第二个参数是const char *format
第二个:第三个参数是传递参数的实际数量,以便根据提供的format
构建字符串。
我怎样才能实现以下目标:
sprintf(str, "...", ...)
基本上,如果函数接收4个(或更多)char指针,我想构建一个完整的字符串(当前,在上面提供的代码中,只有3个),该怎么办?这意味着,第二个参数必须(至少)以"%s%s%s%s"
的形式,然后是ptr[0], ptr[1], ptr[2], ptr[3]
的参数列表。
首先如何对sprintf
(或vsprintf
)进行这样的“组合”调用?事情会更容易,如果我可以提供一个完整的指针数组(** ptr)作为第三个参数,而不是..但这似乎不可行?至少,不是sprintf
会理解它的方式,所以它似乎......因为它需要一些特殊形式的format
。
想法/建议?
答案 0 :(得分:1)
karlphillip对strcat
的建议似乎确实是解决方案。或者更确切地说,你更希望使用类似strncat
的东西(不过如果你正在使用支持它的C库,我建议使用strlcat
,我认为这是strncat
。比sprintf(str, "%s%s%s", ptr[0], ptr[1], ptr[2]);
更好。
所以,而不是int i;
for (i = 0; i < any; i++)
strncat(str, arr[i], size - strlen(str) - 1);
,你可以这样做:
strlcat(str, arr[i], size);
(或strlcat
;关于{{1}}的好处是,如果目标缓冲区太小,它的返回值将指示重新分配需要多少字节,但它不是标准的C函数,很多系统都不支持它。)
答案 1 :(得分:0)
在没有操纵缓冲区的情况下,没有其他方法可以在 C 中执行此操作。
然而,您可以切换到 C ++ 并使用精彩的std::string
来让您的生活更轻松。
答案 2 :(得分:0)
您的第一个问题由以下方式处理:const char *
用于该功能,而不是您。把你自己的字符串放在一起 - 这个签名只意味着该函数不会改变它。
你的第二个问题是:传入你自己的va_list。你怎么得到的?让你自己的varargs功能:
char *assemble_strings(int count, ...)
{
va_list data_list;
va_list len_list;
int size;
char *arg;
char *formatstr;
char *str;
int i;
va_start(len_list, count);
for (i = 0, size = 0; i < count; i++)
{
arg = va_arg(len_list, char *);
size += strlen(arg);
}
va_end(len_list);
formatstr = malloc(2*count + 1);
formatstr[2*count] = 0;
for (i = 0; i < count; i++)
{
formatstr[2*i] = '%';
formatstr[2*i+1] = 's';
}
str = malloc(size + 1);
va_start(data_list, count);
vsprintf(str, formatstr, data_list);
va_end(data_list);
free(formatstr);
return(str);
}
当然,你需要一些方法来终止varargs,如果字符串列表完全在varargs中,那么将它传递给vsprintf要容易得多 - 因为标准C需要至少一个常规参数。
答案 3 :(得分:0)
我将用于最终副本到str的循环类似于:
for(i=0, p=str; i < num; i++)
p += sprintf(p, "%s", ptr[i]);
或
for(i=0, p=str; i < num; i++)
p += strlen(strcpy(p, ptr[i]));
而不是在一次调用sprintf时尝试处理可变数量的参数。