用可变数量的参数构建一个字符串

时间:2011-06-17 13:56:44

标签: c arrays string pointers printf

#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

想法/建议?

4 个答案:

答案 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时尝试处理可变数量的参数。