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

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

Related

Is there another way to represent fscanf's 3rd argument in this code?

I am having a bit of difficulty understanding the arguments for fscanf. The first two are self-explanatory. The first argument is the point file. It gets the content from this file. The second argument is the type of content in the file. In this case it's int so there is usage of %d. Now, the third argument, I am having difficulty discerning and it would help to have it done in some other way, so I can better understand what this 3rd argument is all about.
#include <stdio.h>
#include <string.h>
int main(void);
void getCode(char a[]);
int getMessage(int a[]);
void sortMessage(int a[], int b);
void decodeMessage(char a[], int b[], int c);
int main(void) {
// declare file names
char string[53];
int integers[27];
int msgSize;
// int codeSize = 52;
// Open files & there content
getCode(string);
msgSize = getMessage(integers);
sortMessage(integers, msgSize);
decodeMessage(string, integers, msgSize);
}
void getCode(char string[]) {
// get content from code file & print it
FILE *C = fopen("codefile.txt", "r");
while (fgets(string, 55, C)) {
printf("%s\n", string);
}
}
getMessage(int integers[]) {
// Get content from message file & return it
FILE *M;
M = fopen("msgfile.txt", "r");
int counter = 0;
/* Read one number at a time from the file and store it */
while (!feof(M)) {
fscanf(M, "%d", (integers + counter));
counter++;
}
/* Close the file */
// fclose(M);
return (counter);
}
The third, and subsequent parameters if used, are pointers to the destinations of the parsed values. The better way to write that is &arrayname[index] because it more clearly indicates you are using a type size array index as a pointer. Note that newlines are just like any other whitespace.
Try this yourself
Single Example :
#include <stdio.h>
void main()
{
int count=3;
int ints[3];
printf("Give me %d:\n",count);
for (int i=0;i<count;i++)
scanf("%d",&ints[i]);
printf("You said:\n");
for (int i=0;i<count;i++)
printf("%d\n",ints[i]);
}
Result:
Give me 3:
12
23
34
You said:
12
23
34
Multiple Example: (which could allow you to mix types, or fork into more arrays).
#include <stdio.h>
void main ()
{
int count = 6;
int ints[6];
printf ("Give me %d :\n", count);
for (int i = 0; i < count; )
{
int got;
got= scanf ("%d %d %d", &ints[i], &ints[i + 1], &ints[i + 2]);
i+= got;
}
printf ("You said:\n");
for (int i = 0; i < count; i ++)
printf ("%d\n", ints[i]);
}
Result:
Give me 6 :
1 2 3
4
5 6
You said:
1
2
3
4
5
6

C variable arguments in unsigned char?

I read this page to know how to use variable arguments:
https://www.tutorialspoint.com/cprogramming/c_variable_arguments.htm
All right, integer result is ok.
But when I replace its type to unsigned char, everything goes wrong:
#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;
}
void foo(unsigned char arg_count,int num,...) {
va_list valist;
int i;
/* initialize valist for num number of arguments */
va_start(valist, num);
/* access all the arguments assigned to valist */
for (i = 0; i < arg_count; i++) {
printf("%02x,",va_arg(valist, int));
}
/* clean memory reserved for valist */
va_end(valist);
}
void bar(int num,...) {
va_list valist;
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++) {
printf("%02x,",va_arg(valist, int));
}
/* clean memory reserved for valist */
va_end(valist);
}
int main() {
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));
foo(3,'a','b','c');
printf("\n");
bar('a','b','c');
}
Result as following:
Compiling the source code....
$gcc main.c -o demo -lm -pthread -lgmp -lreadline 2>&1
Executing the program....
$demo
Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000
62,63,400aab,
62,63,00,0a,c0a4700,4009e0,b0ef50a,01,64f5ead8,40000,400934,00,440c7120,400540,64f5ead0,00,00,83cc7120,be487120,00,00,00,bea8d73,be96d10,b6b9950,00,00,00,400540,64f5ead0,40056a,64f5eac8,c0c0180,01,64f5f3d3,00,64f5f3d8,64f5f473,64f5f48d,64f5f4a9,64f5f4b2,64f5f4c8,64f5f4e5,64f5f50d,64f5f796,64f5f7af,64f5f7d9,64f5f7f8,64f5f802,64f5f80a,64f5f823,64f5f83b,64f5f850,64f5f876,64f5f87e,64f5f898,64f5f8d0,64f5f8db,64f5f8e3,64f5f946,64f5f972,64f5f998,64f5fa2d,64f5fa63,64f5fa79,64f5ff2f,64f5ffc9,00,21,64fdb000,10,bfebfbff,06,1000,11,64,03,400040,04,38,05,09,07,be98000,08,00,09,400540,0b,30,0c,30,0d,30,0e,30,17,
Everything was the same with the int version, but why result is different?
Replace:
va_start(valist, num);
with
va_start(valist, arg_count);
in foo and change its prototype to:
void foo(unsigned char arg_count, ...)
You're declaring 3 arguments but starting the va_list 2 from the end.
Also, change this
bar('a','b','c');
to:
bar(3, 'a','b','c');
in main. You have omitted the num argument.
Maybe I don't understand what it is that you are trying to do with your code, but aren't you just sending 'a', which typically will be the character code 97, as the number of arguments to the function bar? So it tries to print 97 arguments.
va_start(valist, num) initializes valist to start with the argument after num. In both function calls, to foo and bar, 'a' is in the position of num, so the first value from va_arg will be 'b', which is 98 decimal, or 62 hexadecimal.

Function to count the sum of an array

Right, this is (the last) assignment for my C introduction web class.
The assignment presents the main program, does not explain anything about it and tells you to write a function to print and sum the array in it.
However I don't really understand what is going on in the main program.
Translated for your convenience;
Source code:
#include <stdio.h>
#include <stlib.h>
void print_count(int *, int);
int main(int argc, char *argv[]) {
int x, sum = 0, size = 0, array[5];
if (argc == 6) {
/* Program name and parameters received from command line */
for (x = 0; x < argc - 1; x++) {
array[x] = atoi(argv[x + 1]);
}
print_count(array, size);
} else {
printf("Error\n");
}
return 0;
}
Now I am completely clueless as to how to start writing the program requested and what variables to call/how to write the function.
Edit3: completed exercise
void print_count(int *array, int size) {
int i;
int sum = 0;
printf("Elements: ");
for (i = 0; i <= size; i++) {
printf("%d ", (array[i]);
sum = sum += array[i]);
}
printf("\nSum = %d ", sum);
return 0;
}
I would like to understand what is going on in the main program and preferably come to an answer on how to actually write the function by myself.
This:
array[5] = atoi(argv[x+1]);
is clearly wrong, it always tries to assign to array[5] which is out of bounds. It should be:
array[x] = atoi(argv[x + 1]);
This converts the x + 1:th argument from string format into an integer, and stores that in array[x]. If you're not familiar with the standard function atoi(), just read the manual page.
So if you start the program like this:
./myprogram 1 2 3 4 5
That has 6 arguments (the first is the name itself), and will end up with array containing the numbers one through five.
Then in the summing function, the first line should be something like:
void print_count(int *array, int size)
so that you give names to the arguments, which makes them usable in the function. Not providing names is an error, I think.
And it doesn't need to "interact" with main() more than it already does; main() calls print_count(), passing it a pointer to the first element of array and the length of the array, that's all that's needed to compute the sum.
Your print_count function has a few issues:
The loop runs one step too far: i should vary between 0 and size-1 included. The standard idiom for this loop is:
for (i = 0; i < size; i++) {
...
Incrementing sum is simply done with:
sum += array[i];
There is an extra ( on the first printf line.
You should print a newline after the output.
Returning 0 from a void function is invalid.
Here is a corrected version:
void print_count(int *array, int size) {
int i;
int sum = 0;
printf("Elements: ");
for (i = 0; i < size; i++) {
printf("%d ", array[i]);
sum += array[i]);
}
printf("\nSum = %d\n", sum);
}
the following proposed code:
cleanly compiles.
explains what is being accomplished at each step of the 'main()' function.
properly outputs error messages to 'stderr'.
implements the typical method to announce an error in the number of command line parameters.
Now the proposed code with explanatory comments:
#include <stdio.h> // printf(), fprintf()
#include <stdlib.h> // atoi(), exit(), EXIT_FAILURE
void print_count(int *, int);
int main(int argc, char *argv[])
{
if (argc != 6)
{
fprintf( stderr, "USAGE: %s int1 int2 int3 int4 int5\n", argv[0] );
exit( EXIT_FAILURE );
}
// implied else, correct number of arguments
// only declare variables when they are needed
int array[5];
// place each command line parameter into 'array',
// except program name
// I.E. skip the program name in argv[0]
for( int i = 1; i < argc; i++ )
{
// array[] index starts at 0, but loop counter starts at 1
array[i-1] = atoi(argv[i]);
} // end for( each value pointed at by argv[], except program name )
// print sum of command line parameters to stdout
int size = argc-1; // number of command line parameters after program name
print_count(array, size);
return 0;
} // end function: main

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