我正在尝试使用va_list&它将宏与vsprintf((关联,以创建具有可变数量说明符的格式字符串。以下是我编写的一个示例程序,其中说明符的数量只能通过NUM_ARG宏更改:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#define MAXBUF 4096
#define SPECIFIER "(%s)"
#define NUM_ARG 5
char *strmaker(int num_args, ...)
{
char form[MAXBUF] = { [0] = ' ' };
char *prnt = (char *) malloc(sizeof(char) * MAXBUF);
va_list strings;
for (int i = 0; i < num_args; ++i)
strcat(form, SPECIFIER);
va_start(strings, num_args);
vsprintf(prnt, form, strings);
va_end(strings);
return prnt;
}
int main(int argc, char *argv[])
{
if (argc != (NUM_ARG + 1))
return -1;
char *s = strmaker(NUM_ARG, argv[1], argv[2], argv[3], argv[4], argv[5]);
printf("%sn", s);
free(s);
return 0;
}
然而,这并不是我想要实现的。如何使用可变数量的参数来实现这一点?如何将可变数量的字符串传递给函数并用于初始化va_list?
据我所知,这是不可能的。如果你不那么热衷于使用变差函数,可以重新定义函数。以下代码适合您的需要;遍历数组中的每个项,并使用snprintf
追加到字符串中。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXBUF 4096
#define SPECIFIER "(%s)"
char *strmaker(int num_args, char** strings)
{
char *prnt = (char *) malloc(sizeof(char) * MAXBUF);
int cur = 0;
/* Append the strings to the prnt buffer */
for (int i = 0; i < num_args; i++) {
int p_return = snprintf(prnt + cur, MAXBUF - cur, SPECIFIER, strings[i]); // If no error, return the number characters printed excluding nul (man page)
if (p_return >= MAXBUF - cur) // If buffer overflows (man page)
return prnt;
cur = cur + p_return; // Update the index location.
}
return prnt;
}
int main(int argc, char *argv[])
{
if (argc <= 1)
return -1;
char *s = strmaker(argc - 1, argv + 1);
printf("%sn", s);
free(s);
return 0;
}
终端会话:
$ ./a.out 1 2 3
(1)(2)(3)
$ ./a.out 1 2 3 4 5 6 7
(1)(2)(3)(4)(5)(6)(7)
$ ./a.out Hello, This is stackoverflow, Bye
(Hello,)(This)(is)(stackoverflow,)(Bye)
简短的回答是:你不能。
然而,您可以通过使用字符串数组(可能是动态分配的(来解决它。然后,您基本上可以使用与现在相同的技术,但可以对数组进行迭代。
也许是这样的:
char *strmaker(size_t count, char *strings[])
{
// First get the length of all strings in the array
size_t result_length = 0;
for (size_t i = 0; i < count; ++i)
{
// +1 for space between the strings
// And for the last string adds space for the string null-terminator
result_length += strlen(strings[i]) + 1;
}
// Now allocate the string (using calloc to initialize memory to zero, same as the string null-terminator)
char *result = calloc(1, result_length);
// And not concatenate all strings in the array into one large string
for (size_t i = 0; i < count; ++i)
{
strcat(result, strings[i]);
if (i != count - 1)
{
strcat(result, " "); // Add space, except after last string
}
}
// Return the resulting string
return string;
}
int main(int argc, char *argv[])
{
// Create an array for all arguments
char **arguments = malloc(sizeof(char *) * argc - 1);
for (int a = 1; a < argc)
{
arguments[a - 1] = argv[a];
}
// Now create the single string
char *result = strmaker(argc - 1, arguments);
// ... and print it
printf("%sn", result);
// Finally clean up after us
free(result);
free(arguments);
}
对于argv
中的命令行参数,您实际上不需要创建一个新的数组来容纳它们,但它展示了如何创建一个字符串数组来传递给strmaker
。您可以使用所需的任何字符串,而不是命令行参数。