Getting arguments from the stack in c - c

I just started to learn c and I was trying to create a function that gets it's arguments from the stack when I know all the arguments are from the same type, but it worked only for int.
This is what I did:
void Test1(double first_arg, ...)
{
double *a = &first_arg;
printf("arg[0]: %f\narg[1]: %f \narg[2]: %f\n", a[0], a[1], a[2]);
}
void Test2(int first_arg, ...)
{
int *a = &first_arg;
printf("arg[0]: %d\narg[1]: %d \narg[2]: %d\n", a[0], a[1], a[2]);
}
int main()
{
printf("Test1:\n");
Test1(1.0, 2.0, 3.0);
printf("\nTest2:\n");
Test2(1, 2, 3);
return 0;
}
Console:
Test1:
arg[0]: 1.000000
arg[1]: 0.000000
arg[2]: 0.000000
Test2:
arg[0]: 1
arg[1]: 2
arg[2]: 3
What am I missing here? And what should I do to fix this.

The way arguments are passed to a function are implementation dependent. To read variable arguments in a portable way, you need to use the stdarg family of functions.
#include <stdio.h>
#include <stdarg.h>
void Test1(double first_arg, ...)
{
printf("arg[0]=%f\n", first_arg);
va_list ap;
va_start(ap, first_arg);
double arg1 = va_arg(ap, double);
printf("arg[1]=%f\n", arg1);
double arg2 = va_arg(ap, double);
printf("arg[2]=%f\n", arg2);
va_end(ap);
}
int main()
{
printf("Test1:\n");
Test1(1.0, 2.0, 3.0);
return 0;
}

Related

error: passing 'float [4]' to parameter of incompatible type 'float'

I have to create a function called print_array that takes two parameters: a float array and an integer (denoting the length of the array). The function should print the entire array of floats to a precision of two decimals. E.g.,
float a[] = {1.555, 3, 1.645, 178};
print_array(a, 4);
It should give:
1.55, 3.00, 1.64, 178.00
My code goes as follows (a bit messy):
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
int times_two(int a);
void print_int(int a);
int half(int a);
void print_float(float a);
void max(float a);
float average(float a);
void print_array(float a, int b);
int main (void)
{
int z = get_int("First Value for exercise 3? ");
int g = get_int("Second Value for exercise 3? ");
int max_value_1 = get_int("First Value (max) for exercise 4? ");
int max_value_2 = get_int("Second Value (max for exercise 4? ");
int x = 2;
int y = half(x);
float q = average(z + g);
print_int(y);
print_float(2.7444);
print_float(q);
if(max_value_1 > max_value_2 || max_value_1 == max_value_2)
{
max(max_value_1);
}
else
{
max(max_value_2);
}
float a[] = {1.555, 3, 1.645, 178};
print_array(a, 4);
}
float average(float a)
{
return a / 2;
}
int times_two(int a)
{
return a * 2;
}
int half(int a)
{
return a / 2;
}
void print_int(int a)
{
printf("Value Exercise 1 = %i\n", a);
}
void print_float(float a)
{
printf("Value Exercise 2/3 = %.2f\n", a);
}
void max(float a)
{
printf("Value Exercise 4 = %.2f\n", a);
}
void print_array(float a, int b)
{
printf("Value Exercise 4 = %.2f\n", a);
}
For some other reason I get this error and really don't know how to fix them as I am new to ''functions'':
functions.c:37:17: error: passing 'float [4]' to parameter of incompatible type 'float'
print_array(a, 4);
^
functions.c:13:24: note: passing argument to parameter 'a' here
void print_array(float a, int b);
^
1 error generated.
void print_array(float a, int b);
This line says that print_array's first parameter is a float.
float a[] = {1.555, 3, 1.645, 178};
print_array(a, 4);
This line passes an array as the first parameter to print_array. This is inconsistent with the line shown previously that says the first parameter is a float.
This is precisely what the error is telling you.
Your first step in fixing this would be to change this:
void print_array(float a, int b);
To something like:
void print_array(float a[], int b);
or
void print_array(float *a, int b);

Code using variadic arguments not giving the expected output

I have the following example code
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
void myprint(char *inizio, ...);
int main(void)
{
myprint("Inizio", 2, 3.0, 4, 5.0, 'c');
return(0);
}
void myprint(char *inizio, ...)
{
va_list argPoint;
int pi;
char pc;
double pd;
va_start(argPoint, inizio);
pi=va_arg(argPoint,int);
printf("Int = %d\n", pi);
pi=va_arg(argPoint,int);
printf("Int = %d\n", pi);
pd=va_arg(argPoint,double);
printf("Int = %f\n", pd);
/* need a cast here since va_arg only takes fully promoted types
pc=va_arg(argPoint,char); */
pc=(char)va_arg(argPoint,int);
printf("Int = %c\n", pc);
pd=va_arg(argPoint,double);
printf("Int = %f\n", pd);
pi=va_arg(argPoint,int);
printf("Int = %d\n", pi);
va_start(argPoint, inizio);
pi=va_arg(argPoint,int);
printf("Int = %d\n", pi);
va_end(argPoint);
}
I am getting the following output:
Int = 2
Int = 0
Int = 0.000000
Int =
Int = 0.000000
Int = 117
Int = 2
The answer according to my handout should be:
Int = 2
Int = 4
Int = 3.000000
Int = c
Int = 5.000000
Int = 1235099264
Int = 2
Why is it not working? I am using Codeblocks by the way, just in case.
Additionally what does the comment " need a cast here since va_arg only takes fully promoted types pc=va_arg(argPoint,char); " means? va_arg(argPoint,char) is supposed to return a char, I don't see why they do pc=(char)va_arg(argPoint,int) instead, the (char) seems redundant.

variable-length-arguments in C [duplicate]

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.

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);
}

Resources