gpt4 book ai didi

c - 如何使函数使用不确定数量的参数和va_list组合参数?

转载 作者:行者123 更新时间:2023-11-30 16:52:52 35 4
gpt4 key购买 nike

我想用这个原型制作一个函数:

char *combine(const char *string, ...)


结合了命令行中给出的参数,并将结果返回到 main

我的功能目前看起来像这样:

char *combine(const char *mj, ...)
{
va_list pl;
va_start(pl, mj);

while(mj != NULL) {
printf("%s",mj);
mj = va_arg(pl, char *);
}

va_end(pl);
return pl;
}


例如,如果用户使用以下命令运行此程序:

./a.out one two three four five six seven


输出应为:

Parameter: onetwothreefourfivesixseven (length of parameter: 27)


现在,如果我用它运行程序,则输出大部分是随机元素,并且该参数只是空的。

有什么问题,我需要修复什么才能显示正确的内容?

该程序需要使用以下 main代码:

int main(int argc, char *argv[]) {
int i = 0;
char *mj = malloc(1);

mj[0] = '\0';
for(i = 1; (i+3) <= argc; i += 3)
{
char *tmp = mj;
mj = combine(tmp, argv[i], argv[i+1], argv[i+2], NULL);
free(tmp);
}
if((i+2) == argc)
{
char *tmp = mj;
mj = combine(mj, argv[i], argv[i+1], NULL);
free(tmp);
}
else if((i+1) == argc)
{
char *tmp = mj;
mj = combine(mj, argv[i], NULL);
free(tmp);
}
printf("Parameter: %s (length: %lu)\n", mj, (unsigned long)strlen(mj));
free(mj);
return 0;
}

最佳答案

va_list视为不透明的类型,例如“别在乎它到底是什么”。 “功能” va_start()va_arg()va_end()实际上不是功能,而是宏。再说一遍,它们的真正含义和工作原理一开始并不那么重要。 (“不要理会窗帘后面的那个人!”)您现在所需要知道的就是如何使用它们。

假设您正在编写自己的函数:

char *combine(const char *mj, ...)


有一个参数 const char *mj,然后……可能还有其他一些。那么,如果这些参数没有标识符,甚至不知道有多少个参数,该如何引用呢?这就是 va_list的用途。可以将其视为可以在该参数列表中滚动并以某种方式告诉您下一个参数是什么的光标。

首先,您必须使用 va_start进行设置:

va_start(pl, mj);


这意味着使用 va_list pl作为最后一个已知的显式参数来设置 mj

第一次将 va_arg()pl一起使用时,它将为您提供 mj之后的第一个参数。您还需要在 va_arg()中指定下一个参数的预期类型,因此在您的情况下,调用将为 va_arg(pl, char *)。每次使用 va_arg()时,它都会前进此“光标”,以便对 va_arg()的下一次调用将为您提供下一个参数。因此,每次使用 va_arg()时,都应该使用此值来做某事,因为您不会再得到它。 (除非,也许您从头开始。)

那么,您如何知道自己是否在列表的末尾?好吧,您只需要知道某种方式。 va_arg()不会告诉您您在列表的末尾,如果您继续使用它,它将很乐意走到末尾。通常,您将使用最后一个已知的参数(在您的情况下为 mj)以某种方式指定有多少个参数,或者您可以在参数列表中查找一些前哨值。

确定完成后,请务必使用

va_end(pl);


此后, va_list pl无效,不应再次引用。 (除非您想从另一个 va_start()重新开始。)



一个说明如何使用此方法的示例是经典的 printf(),它使用可变参数。从 man pages,我们知道 printf()被声明为

int printf(const char *format, ...);


考虑例如函数调用

printf("The value of %s is %ld\n", lbl, x);


在内部, printf()将使用某些 va_list,我们称其为 vlformat是最后一个已知的参数,因此将在 va_start(vl, format)中使用。 printf()将解析此 format字符串,找到 %s并期望接下来有一个 char *参数。然后它将调用 va_arg(vl, char *),以某种方式使用此值,并继续解析 format字符串。然后,它找到 %ld并期望一些 long int,因此它将调用 va_arg(vl, long int)并在打印时使用该值。进一步解析 format之后,它到达格式字符串的结尾,然后停止,最终使用 va_end(vl)。 (如果您要注意的话,也许现在您可以弄清为什么在 printf格式字符串中始终使用正确的长度修饰符和转换说明符很重要的原因。)



这就是使用 va_list的方法。现在回到您的代码:请记住, va_start(pl, mj);不会为 mj分配任何内容,因为您可能会想到。它仅使用 va_list pl作为最后一个已知的显式参数来设置 mj。出于某种原因,您也正在重新分配 mj(该部分没有意义)。您甚至根本不想连接任何字符串。看来您只是在尝试打印它们。从某个大小的动态分配的缓冲区开始,将字符串一个接一个地追加到它,然后根据需要重新分配。 (这并不难,但是在您初次使用时似乎并不容易。如何实现它超出了此问题的范围。)

va_list不会“组合”任何东西,它只会一次为您提供函数的参数(这更像是将东西分开了)。您必须自己进行合并, va_list只是如何发挥作用。

关于c - 如何使函数使用不确定数量的参数和va_list组合参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41088130/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com