I'm writing a simple variadic function that adds together a series of ints and returns the sum. I'm having a bit of trouble understanding how it works and my code doesn't seem to work though I feel I'm in the right direction with my code. (Posted below) The specifications of this function are that it takes at least one param and the last param is always a zero (as seen called in the main). I was also told, based upon my machine, that I wouldn't necessarily get the output I'm looking for which, as you could imagine, further complicates my situation. Some assistance with correcting my Sum() function would be greatly appreciated.
EDIT:
This is supposed to be done w/o the use of stdarg.h header and thus no va_arg functions.
int Sum(int a, ... ) {
int sum = 0, *addy = &a;
while (*addy) {
sum += *addy;
addy += sizeof(a);
}
return sum;
}
int main() {
printf("%d %d %d %d\n", Sum(0), Sum(3, 5, 6, 7, 0),
Sum(7, 2, 42, 3, 5, -4, 0), Sum(-1, 9, 12, 123, -213, 42, 7, 2, 0));
}
//Expected output: 0 21 55 -19
//My output: 0 32770 32770 32776
When you add a number to an int pointer (as in addy += sizeof(a)) the number you add is automatically multiplied by the size of whatever type the pointer is declared as (in this case int). To fix this, just use
addy += 1;
instead. However, I would recommend using variadic macros instead of this method, they are clearer and less error prone.
for variable arguments, you have to use va_start and va_end functions, hope useful..
http://www.gnu.org/software/libc/manual/html_node/Variadic-Example.html#Variadic-Example
Can you please check this
int Sum(int a, ... ) {
int sum = 0, *addy = &a;
while (*addy) {
sum += *addy;
addy ++;
}
return sum;
}
int main() {
printf("%d %d %d %d\n", Sum(0), Sum(3, 5, 6, 7, 0),
Sum(7, 2, 42, 3, 5, -4, 0), Sum(-1, 9, 12, 123, -213, 42, 7, 2, 0));
}
Point to remember is for pointer operations: the number you are adding to the pointer will be multiplied by the size of the type that the pointer is pointing to. So incrementing the pointer addy is enough for geting the next element.
#include <stdarg.h>
#include <stdio.h>
int
add_em_up (int count,...)
{
va_list ap;
int i, sum;
va_start (ap, count); /* Initialize the argument list. */
sum = 0;
for (i = 0; i < count; i++)
sum += va_arg (ap, int); /* Get the next argument value. */
va_end (ap); /* Clean up. */
return sum;
}
int
main (void)
{
/* This call prints 16. */
printf ("%d\n", add_em_up (3, 5, 5, 6));
/* This call prints 55. */
printf ("%d\n", add_em_up (10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
return 0;
}
Related
I almost understood this function, but I wondered when I looked at the example. Why does the For statement loop until i is less than count?
int
add_em_up (int count,...)
{
va_list ap;
int i, sum;
va_start (ap, count); /* Initialize the argument list. */
sum = 0;
for (i = 0; i < count; i++)
sum += va_arg (ap, int); /* Get the next argument value. */
va_end (ap); /* Clean up. */
return sum;
}
int
main (void)
{
/* This call prints 16. */
printf ("%d\n", add_em_up (3, 5, 5, 6));
/* This call prints 55. */
printf ("%d\n", add_em_up (10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
return 0;
}
I try to understand the concept by looking at various explanations, but it's not easy. I understand that the first parameter is the first argument of the list. It's the first parameter, so why do we have to loop around in here? But WHY? I want to know why! Help me plz!
Why does the For statement loop until i is less than count?
It doesn't - it loops while i is less than count.
Okay, this is such an easy question that experts like you must have been confused. I am implementing printf. For example, the following features are implemented:
int printf(const char *str, ...) //funtion
printf("my name : %s \n my age : %d \n", "baby coder", 1);
const char : "my name : %s \n my age : %d \n"
Parameters : baby coder, 1
That's why spin the loop until less 'i' than the number of str...!
I seem to be having a problem understanding where the issue is in the qsort implementation by K&R (C Programming Language second edition).
void qsort_1(int v[], int left, int right)
{
int i, last;
void swap(int v[], int i, int j);
if (left >= right)
return;
swap(v, left, (left + right)/2);
last = left;
for (i = left + 1; i <= right; i++)
if (v[i] < v[left])
swap(v, ++last, i);
swap(v, left, last);
qsort_1(v, left, last-1);
qsort_1(v, last+1, right);
}
This is their version, I only renamed it to qsort_1 so that I could use the built in one at the same time.
int arr_len = 9;
int main() {
int a[] = { 5, 5, 4, 6, 3, 7, 8, 13, 17 };
int b[] = { 5, 5, 4, 6, 3, 7, 8, 13, 17 };
print_a(a, arr_len); // print first array
print_a(b, arr_len); // print second array
putchar('\n'); // space
qsort(b, arr_len, sizeof(int), cmpfunc); // sort second array with standard qsort
qsort_1(a, 0, arr_len); // sort first array with K&R qsort
print_a(a, arr_len); // print first array
print_a(b, arr_len); // print second array
return 0;
}
print_a is a mini function for displaying an array, just one for loop.
qsort is the official standard implementation.
The output I get is:
gcc -O2 -lm -o qsort qsort.c
5 5 4 6 3 7 8 13 17
5 5 4 6 3 7 8 13 17
0 3 4 5 5 6 7 8 13
3 4 5 5 6 7 8 13 17
There seems to be a leading 0 and the last element is removed in the K&R qsort everytime. ...Help
void print_a(int a[], int len) {
for (int i = 0; i < len; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
int cmpfunc (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
If needed, here are the cmpfunc and print_a.
Tried googling the problem but no one seemed to have the same issue.
EDIT:
The code changed in the main function:
int main() {
int a[] = { 5 , 5 ,4 ,6 ,3 ,7 ,8, 13, 17 };
int b[] = { 5 , 5 ,4 ,6 ,3 ,7 ,8, 13, 17 };
print_a(a, arr_len);
print_a(b, arr_len);
putchar('\n');
qsort(b, arr_len, sizeof(int), cmpfunc);
qsort_1(a, 0, **arr_len - 1**);
print_a(a, arr_len);
print_a(b, arr_len);
return 0;
}
When in doubt, look at the code you wrote.
We can assume for a moment that K&R knew what they were doing.
We can further assume that the authors of qsort in the standard library knew what they were doing as well.
Therefore, the first places we should look at what you authored. So what did you really author. The print function, the qsort comparator, and basically everything in main. A quick review reveals:
print_a is certainly ok, provided the base address and length are valid (and they are in this usage case), so that's out.
The qsort comparator seems correct, since (a) it works, and (b) it has nothing to do with questionable output from a totally unrelated function, qsort_1. So that's out.
That leaves only main. Within that function we have:
int main()
{
int a[] = { 5, 5, 4, 6, 3, 7, 8, 13, 17 };
int b[] = { 5, 5, 4, 6, 3, 7, 8, 13, 17 };
print_a(a, arr_len); // print first array
print_a(b, arr_len); // print second array
putchar('\n'); // space
qsort(b, arr_len, sizeof(int), cmpfunc); // sort second array with standard qsort
qsort_1(a, 0, arr_len); // sort first array with K&R qsort
print_a(a, arr_len); // print first array
print_a(b, arr_len); // print second array
return 0;
}
From this:
The array declarations are certainly ok.
The print_a calls check out ok (base address and length are valid).
The call to qsort is unrelated, and obviously ok.
That leave only one line of code in this entire program that could be the culprit:
qsort_1(a, 0, arr_len); // sort first array with K&R qsort
Checking the algorithm, the K&R function expects:
The array base address (ok)
The first index in the partition to sort, in this case 0. (ok)
The last index in the partition to sort. Um...
That's the problem. arr_len is not the last index. It is the length of the sequence. Since arrays in C are 0-index based, the last index is therefore arr_len-1, not arr_len.
Fix that:
qsort_1(a, 0, arr_len-1);
And the code will work as-expected.
I would like to make a function that can take a variable number of parameters at once to do something like this:
void function(char *args[]){ ... }
int main(){
function("a","b","c");
}
You are looking for Variadic functions.
Check this example:
#include <stdio.h>
#include <stdarg.h>
double average(int num, ...) {
va_list valist;
double sum = 0.0;
int i;
/* initialize valist for num number of arguments */
va_start(valist, num);
/* access all the arguments assigned to valist */
for (i = 0; i < num; i++) {
sum += va_arg(valist, int);
}
/* clean memory reserved for valist */
va_end(valist);
return sum/num;
}
int main(void) {
printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2, 3, 4, 5));
printf("Average of 5, 10, 15 = %f\n", average(3, 5, 10, 15));
}
Output:
Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000
Read more in Variadic Functions in C and the Reference.
Tip: Think twice before using Variadic functions. As #user694733 commented, they have no compile time type safety or protection against invalid number of arguments. They can usually be avoided with better program design.
For example, I'd like to access the 6th argument, which has a value of 6:
int myfun(int count, ...)
{
va_list ap;
int 6th_arg;
va_start(ap, count);
// 6th_arg = va_arg(ap*sizeof(int)*5, int);
va_end(ap);
return 6th_arg; // return 6
}
int main()
{
printf("%d\n", myfun(10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
}
The va_arg macro always gets the next argument in the list.
If you want to read the 6th argument, you first need to read the 5 that come before it.
I'm reading about how to pass optional arguments to function. But I'm unable to understand those. When I see examples, they are confusing and a bit complex. So I just started with a very simple program with what I have understood up to now.
The below program just prints the variables.
void print(int x, ...)
{
va_list ap;
int i = 4; // I know I'm passing only 4 opt variables.
int num;
va_start(ap, x);
while(i--) { // How to know how many variables came in real time?
num = va_arg(ap, int);
printf("%d\n", num);
}
va_end(ap);
return;
}
int main()
{
print(1,2,3,4,5);
return 0;
}
I don't know above program is right or not. But it's working. When I change the i value to 5 printing garbage. How to know how many arguments I got (like argc in main)?
There is no way of knowing how many arguments are passed from inside a variable-argument function, that's why functions such as printf are using special format strings that tells the function how many arguments to expect.
Another way is of course to pass the number of "extra" arguments as the first argument, like
print(4, 1, 2, 3, 4);
Or to have a special value that can't be in the list as last argument, like
print(1, 2, 3, 4, -1);
You also have to take note that the last non-va argument you pass to the function (the argument named num in your case) is not included in the va_list, so in your case with the shown code with 4 as hardcoded number of arguments you will still print garbage, as you pass 1 for the num argument and then three va_list arguments.
Also take care because you use num as both argument and a local variable name.
You can take a look to NARGS macro
Adapted to your code:
#include <stdio.h>
#include <stdarg.h>
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define print(...) fnprint(NARGS(__VA_ARGS__), __VA_ARGS__)
void fnprint(int n, ...)
{
va_list ap;
int num;
va_start(ap, n);
while (n--) {
num = va_arg(ap, int);
printf("%d\n", num);
}
va_end(ap);
return;
}
int main(void)
{
print(1, 2, 3, 4, 5);
return 0;
}
EDIT:
If you want to use the same name for macro and function, use () to stop the preprocessor from expanding the function definition:
#define print(...) print(NARGS(__VA_ARGS__), __VA_ARGS__)
void (print)(int n, ...) /* Note () around the function name */
{
...
EDIT 2: Another (ugly) method (but without restriction in the number of args) using compound literals (std 99) and sizeof:
#include <stdio.h>
#include <stdarg.h>
#define print(...) print(sizeof((int []) {__VA_ARGS__}) / sizeof(int), __VA_ARGS__)
void (print)(int n, ...)
{
va_list ap;
int num;
va_start(ap, n);
while (n--) {
num = va_arg(ap, int);
printf("%d\n", num);
}
va_end(ap);
return;
}
int main(void)
{
print(1, 2, 3, 4, 5);
return 0;
}
print is expanded to:
print(sizeof((int []) {1, 2, 3, 4, 5}) / sizeof(int), 1, 2, 3, 4, 5);
But constructions like print(1, 2, 3, a_var++, 4, 5); or print(1, 2, some_func_returning_int(), 4, 5); evaluates a_var++ and some_func_returning_int() two times, thats a big problem.
Another ugly way for both int and strings:
#include <stdio.h>
#include <stdarg.h>
#define print(...) fnprint("{" # __VA_ARGS__ )
fnprint(char *b) {
int count = 0, i;
if (b[1] != '\0') {
for (i =2; b[i]; i++) {
if (b[i] == ',')
count++;
}
count++;
}
printf("\ncount is %i\n", count);
}
int main(void)
{
print();
print("1", "2");
print(1, 2, 3, 4, 5);
return 0;
}