variable-length-arguments in C [duplicate] - c

This question already has answers here:
Couldn't implement function with variable arguments
(1 answer)
Function with unknown number of parameters in C
(1 answer)
Closed 5 years ago.
I have learned that this code will print 10, 30, 60 in Terminal.
#include <stdio.h>
void add(int num, ...);
int main(int argc, char const *argv[])
{
int a=10, b=20, c=30;
add(1, a);
add(2, a, b);
add(3, a, b, c);
return 0;
}
void add(int num, ...)
{
int* p = NULL;
p = &num + 1;
if (num == 1)
printf("%d \n", p[0]);
else if (num == 2)
printf("%d \n", p[0] + p[1]);
else
printf("%d \n", p[0] + p[1] + p[2]);
}
But, it only print odd numbers... :(
I just want to print 10, 30, 60 within .
Where do you think I should fix?

You can't get variadic arguments just by taking the address of the last given parameter and adding to it. How function arguments are laid out on the stack (if a stack is used) is compiler and system dependent. That's why you're getting strange numbers.
The way to do this portably is to use a va_list as follows:
void add(int num, ...)
{
// the va_list used to retrieve the extra arguments
va_list args;
int i, sum = 0;
// use va_start to start processing arguments, passing in the last explicit argument
va_start(args, num);
for (i=0; i<num; i++) {
// extract the next argument with the given type
sum += va_arg(args, int);
}
// cleanup
va_end(args);
printf("%d \n", sum);
}
For more details, see the stdarg man page.

Related

why c language get same type and same address, but get different answer? [duplicate]

This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Scope for function parameter in C [closed]
(3 answers)
Closed 11 months ago.
this is my code:
#include<stdio.h>
int* toInt(int number);
int main(int argc, char *argv[]) {
int *b;
b = toInt(123);
printf("result %p \n", b);
printf("result %d \n", *b);
return 0;
}
int * toInt(int number)
{
int* tmp = &number;
printf("toInt %p \n", tmp);
printf("toInt %d \n", *tmp);
return tmp;
}
and this is get answer,
toInt 0x7ffeebb2215c
toInt 123
result 0x7ffeebb2215c
result 329262780
in this case, in function toInt and in main, it get same address: 0x7ffeebb2215c , and same type: int, but the value is different。
i dont know。 it works in golang

Why does this variadic C function not print the first argument?

I am trying to make a variadic function in C with stdarg.h, and I followed this tutorial and wrote the code exactly as he did: https://www.youtube.com/watch?v=S-ak715zIIE. I included the output in the code. I cannot figure out why the first argument is not printed, and also, why are there zeros printed at the end? I am beyond confused. Thanks!
#include <stdio.h>
#include <stdarg.h>
void printNums(int num, ...) {
va_list args;
va_start(args, num);
for (int i = 0; i < num; i++) {
int value = va_arg(args, int);
printf("%d: %d\n", i, value);
}
va_end(args);
}
int main() {
printNums(5, 2, 3, 4);
return 0;
}
/*
Output:
0: 2
1: 3
2: 4
3: 0
4: 0
*/
va_start's first argument is the last parameter that isn't variadic. So num holds the 5, and the rest hold the variadics:
#include <stdio.h>
#include <stdarg.h>
void printNums(int num, ...) {
va_list args;
va_start(args, num);
printf("%d: %d\n", 0, num);
for (int i = 1; i <= num; i++) {
int value = va_arg(args, int);
printf("%d: %d\n", i, value);
}
va_end(args);
}
int main() {
printNums(5, 2, 3, 4);
return 0;
}
0: 5
1: 2
2: 3
3: 4
4: 0
5: 0
also, why are there zeros printed at the end? I am beyond confused. Thanks!
Because of this line:
for (int i = 1; i <= num; i++) {
You pass the value 5 as num to printNums(). In the for loop you act as though it describes the number of variadic arguments to read, but it doesn't - you passed 3 variadics, not 5. The last 2 calls to va_start therefore yield undefined behavior, since you've read past the end of valid variadic arguments. It's just mere chance that you happen to get 0 here - it could be some other random value.
Note that there is no way with mere variadic macros to know how many arguments were passed. Nor is there a way to assert their type. You can assume their type and specify their length at runtime if you wish:
$ ./t3
0: 5
1: 2
2: 3
3: 4
#include <stdio.h>
#include <stdarg.h>
void printNums(int num, ...) {
va_list args;
va_start(args, num);
for (int i = 0; i < num; i++) {
int value = va_arg(args, int);
printf("%d: %d\n", i, value);
}
va_end(args);
}
int main() {
printNums(4, 5, 2, 3, 4);
return 0;
}
Variadic functions are primarily valuable when writing functions like printf, where unknown types and quantities of arguments are required (see the example from the man page) Using passing a list of known types would be more conveniently accomplished by passing an array and count int:
$ cat t.c
#include <stdio.h>
void printNums(int count, int* nums) {
for (int i = 0; i < count; i++) {
printf("%d: %d\n", i, nums[i]);
}
}
int main() {
int nums[] = {5,2,3,4};
printNums(4, nums);
return 0;
}
that just doesn't make a very good video about variadics :P

loop through (char *c, ...)

I'm new to C, and I need to loop through arguments of a routine:
void doSmth(char *c, ...) { //how to print all the elements here? }
Since I come from Java, this is quite new to me, and I have no idea how to do this in C?
Thanks in advance
Because your function declaration is like:
void doSmth(char *c, ...);
What you needs is called variable number of argument functions, you can read from : 9.9. Variable numbers of arguments a good and essay tutorial
Example code with function doSmth() its 4 steps, read comments:
//Step1: Need necessary header file
#include <stdarg.h>
void doSmth( char* c, ...){
va_list ap; // vlist variable
int n; // number
int i;
float f;
//print fix numbers of arguments
printf(" C: %s", c);
//Step2: To initialize `ap` using right-most argument that is `c`
va_start(ap, c);
//Step3: Now access vlist `ap` elements using va_arg()
n = va_arg(ap, int); //first value in my list gives number of ele in list
while(n--){
i = va_arg(ap, int);
f = (float)va_arg(ap, double); //notice type, and typecast
printf("\n %d %f \n", i, f);
}
//Step4: Now work done, we should reset pointer to NULL
va_end(ap);
}
int main(){
printf("call for 2");
doSmth("C-string", 2, 3, 6.7f, 5, 5.5f);
// ^ this is `n` like count in variable list
printf("\ncall for 3");
doSmth("CC-string", 3, -12, -12.7f,-14, -14.4f, -67, -0.67f);
// ^ this is `n` like count in variable list
return 1;
}
it run like:
:~$ ./a.out
call for 2 C: C-string
3 6.700000
5 5.500000
call for 3 C: CC-string
-12 -12.700000
-14 -14.400000
-67 -0.670000
In C the thing is actually is fixed number of arguments followed by variable numbers of arguments

Get variable arguments directly from stack

I'm playing with the stack and function's call parameters.
What I want to achieve here is to get the value of variable parameters directly using the stack.
It works (or seems to work) fine when I don't use variable parameters.
Here is what is working:
void test(int a, int b)
{
unsigned char *ptr;
int i;
ptr = (unsigned char*)&a;
for (i = 0; i < 4; i++)
{
printf("%d,", *ptr);
}
}
That works, I can retrieve the value of b;
The same code using
void test(int a, ...);
as function's prototype doesn't work.
I cant understand what's going on here.
Can you help me?
Thanks !
Edit:
Ok, then it seeems there is no stable and reliable way to do that kind of stuff on my own.
Lets say that in the callee function I know the data size (but not the type) of variable argument, is there a way to grab them ?
As long as you know or can determine the number of arguments, you can use the macros from <stdarg.h>:
#include <stdio.h>
#include <stdarg.h>
void test1(int n, ...)
{
va_list args;
va_start(args, n);
for (int i = 0; i < n; i++)
{
int j = va_arg(args, int);
printf("%d: %d\n", i, j);
}
va_end(args);
}
void test2(int a, ...)
{
va_list args;
int i = 0;
printf("%d: %d\n", i++, a);
va_start(args, a);
int j;
while ((j = va_arg(args, int)) > 0)
printf("%d: %d\n", i++, j);
va_end(args);
}
The difference is in how these two functions are called:
int main(void)
{
test1(4, 1, 3, 7, 9);
test2(1, 3, 7, 9, 0);
return(0);
}
The printf() family uses an alternative but equivalent technique; those functions scan the format string and determine the type of each argument (as well as the number of arguments) from the information in the format string. So, your main options are:
count - test1()
sentinel - test2()
format string - printf()
In functions with ... you can use va_* macro
void test(int a, ...) {
va_list ap;
va_start(ap, a);
// Your code
va_end(ap);
}

How can I pass any number of arguments in User define function in C?

How can I pass any number of arguments in User define function in C?what is the prototype of that function?It is similar to printf which can accept any number of arguments.
Look here for an example.
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
int maxof(int, ...) ;
void f(void);
main(){
f();
exit(EXIT SUCCESS);
}
int maxof(int n args, ...){
register int i;
int max, a;
va_list ap;
va_start(ap, n args);
max = va_arg(ap, int);
for(i = 2; i <= n_args; i++) {
if((a = va_arg(ap, int)) > max)
max = a;
}
va_end(ap);
return max;
}
void f(void) {
int i = 5;
int j[256];
j[42] = 24;
printf("%d\n",maxof(3, i, j[42], 0));
}
Such a function is calle variadic, but such functions are much less useful than they might at first seem. The wikipedia page on the topic is not bad, and has C code.
The basic problem with such functions is that the number of parameters cannot in fact be variable - they are must be fixed at compile time by a known parameter. This is obvious in printf:
printf( "%s %d", "Value is", 42 );
The number of % specifiers must match the number of actual values, and this is true for all other uses of variadic functions in C, in one form or another.

Resources