Transferred from:
Http://blog.chinaunix.net/space.php? Uid = 22566367 & Do = Blog & id = 382046
Recently, I encountered an indefinite parameter problem in C language. In fact, for the problem of variable parameters in C language, only three functions are needed. The header file of these three functions is <stdarg. h>. In fact, the following three functions are a macro definition (macro ).
The three functions are:
Void va_start (va_list AP, last );
Type va_arg (va_list AP, type );
Void va_end (va_list AP );
To perform other operations, check the man manual.
Before explaining the three functions, Let's first look at a variable va_list. What is the type of this variable? By checking the kernel source code and keeping track of it, we can find that its type is void.
For the va_start (va_list AP, last) function, this function is used to initialize the AP (va_list type) pointer. The processing parameters will be processed from the AP by default. Last is generally the first parameter in the char * parameter list.
For the va_arg (va_list AP, type) function, it is to move the AP pointer backward according to the type, and then retrieve the parameter referred to by the AP pointer.
Va_end (va_list AP) is usually used together with va_start (va_list AP, last) to deal with the aftermath.
Here is a question: when we take the parameter, how can we determine that the parameter we want to take is complete? In the beginning, I thought so. I used the va_arg return value to make a judgment. I used the data to check the materials. It seems that my conjecture is correct. When I wrote the program for testing, I found that it was not like this:
# Include <stdio. h>
# Include <stdarg. h>
Int sum (const int ,...);
Int main (void)
{
Printf ("the result is: % d/N", sum (10, 9, 8 ));
Return 0;
}
Int sum (const int first ,...)
{
Va_list argp;
Int sum = 0;
Int TMP;
Va_start (argp, first );
Sum + = first;
Printf ("% d/N", first );
While (TMP = va_arg (argp, INT ))! = 0 ){
Printf ("% d/N", TMP );
Sum + = TMP;
}
Va_end (argp );
Return sum;
}
The running result of this program is:
10
9
8
6676468
134513824
The result is: 141190319
This result indicates that it is wrong to determine whether the parameter is obtained through the return value of va_arg.
Will it be determined by the value of argp? Let's perform a test:
# Include <stdio. h>
# Include <stdarg. h>
Int sum (const int ,...);
Int main (void)
{
Printf ("the result is: % d/N", sum (10, 9, 8 ));
Return 0;
}
Int sum (const int first ,...)
{
Va_list argp;
Int sum = 0;
Int TMP;
Va_start (argp, first );
Sum + = first;
Printf ("% d/N", first );
While (argp ){
TMP = va_arg (argp, INT );
Printf ("% d/N", TMP );
Sum + = TMP;
}
Va_end (argp );
Return sum;
}
The execution result of this program was unexpected and a segment error occurred.
As for how to modify the program to retrieve the variable parameters, I still did not find a solution. Later, I thought of the printf () function. I checked its source code, mainly calling the vsprintf () function. As for why the vsprintf () function is called, I think it may be to facilitate function calls like fprintf (), which also improves the function utilization. Main Code of the printf () function:
328 va_start (ARGs, FMT );
329 n = vsprintf (sprint_buf, FMT, argS );
330 va_end (ARGs );
I continued to check the vsprintf () function and found that, in this function, it seems to determine the number of subsequent parameters by judging the number of "%" in the string. When I think of this, I conclude that when I want to call a function such as an indefinite parameter, I need to point out the number of parameters, but indirectly. For example, the most familiar printf () function indicates the number of parameters in the first parameter through "%", isn't it?
Here, I thought about why the example in the man manual was as follows:
# Include <stdio. h>
# Include <stdarg. h>
Void
Foo (char * FMT ,...)
{
Va_list AP;
Int D;
Char C, * s;
Va_start (AP, FMT );
While (* FMT)
Switch (* FMT ++ ){
Case's ':/* string */
S = va_arg (AP, char *);
Printf ("string % s/n", S );
Break;
Case 'D':/* int */
D = va_arg (AP, INT );
Printf ("int % d/N", d );
Break;
Case 'C':/* char */
/* Need a cast here since va_arg only
Takes fully promoted types */
C = (char) va_arg (AP, INT );
Printf ("char % C/N", C );
Break;
}
Va_end (AP );
}
In this case, isn't it read only after the first parameter is specified? In fact, I think it is indirect to tell the number of parameters.
Through the above analysis, a simple indefinite parameter application is made below.
Problem description: given some strings, find their longest start string.
The experiment code is as follows:
# Include <stdio. h>
# Include <stdlib. h>
# Include <string. h>
# Include <stdarg. h>
Void fun (char * FMT ,...);
Int main ()
{
Fun ("Sss", "fanabcd", "fanfanfanfan", "fanyyyyyyyyyyyy"); // SSS indicates the number of indefinite Parameters
Return 0;
}
Void fun (char * FMT ,...)
{
Va_list argp;
Char * STR, Res [20] = {0 };
Int I;
Va_start (argp, FMT );
If (* FMt ='s '){
STR = va_arg (argp, char *);
Strcpy (Res, STR );
}
FMT ++;
While (* FMT ){
If (* FMT ++ ='s '){
STR = va_arg (argp, char *);
I = 0;
While (RES [I]! = '/0 '){
If (RES [I]! = STR [I]) {
Res [I] = 0;
Break;
}
I ++;
}
}
}
Va_end (argp );
Printf ("the result is: % s/n", Res );
}
The execution result of the program is:
The result is: Fan
By doing so, the variable parameters in the C language are simply applied.