how to print variable number of arguments? (ANSI C) - c

I'm trying to compare the bits of variable number of arguments and print their value. but I'm getting garbage. what am I doing wrong?
My Code:
#include <stdio.h>
#include <stdarg.h>
void and_bits(unsigned int num, ...)
{
unsigned int i = 0;
/* result is 11111111 in binary*/
unsigned int result = 255;
va_list arglist;
va_start(arglist, num);
/* this loop takes each argument, and apply AND bitwise operator to the next argument*/
for (i = 0; i < num; i++)
{
/* bitwise AND operator */
result &= va_arg(arglist,unsigned int);
printf("%u, ",va_arg(arglist,unsigned int));
}
va_end(arglist);
printf("\nthe return value: base 10 = %u\t", result);
printf("base 16 = %x\n", result);
return;
}
int main(void)
{
and_bits(7,2,3);
return 0;
}
The Output:
3, 0, 0, 1987831328, 0, 3742925664, 3742924928,
the return value: base 10 = 0 base 16 = 0

So, you have two problems. The first is covered in comments, but essentially you're not calling and_bits correct. The first argument should be a count.
But you have a bigger problem, right here:
for (i = 0; i < num; i++)
{
/* bitwise AND operator */
result &= va_arg(arglist,unsigned int);
printf("%u, ",va_arg(arglist,unsigned int));
}
Every time you call va_arg(), you advance the argument pointer by one. So assuming you've called and_bits(3, 7, 2, 3), then on the first iteration of the loop:
You call va_arg(), which returns the value 7, and you set result to result & 7.
Then on the next line, you call va_arg(), which returns 2, so you print that out.
Then in the next iteration of the loop:
You call va_arg(), which returns 3, and set result to result & 3.
You call va_arg() again, but you've already consumed three arguments so now you're reading beyond the argument list and you get undefined results.
You're going to go through the loop one more time, and at this point all values returned by va_arg() will be invalid.
You should modify the loop so that it only calls va_arg() once:
#include <stdio.h>
#include <stdarg.h>
void and_bits(unsigned int num, ...)
{
unsigned int i = 0;
/* result is 11111111 in binary*/
unsigned int result = 255;
va_list arglist;
va_start(arglist, num);
/* this loop takes each argument, and apply AND bitwise operator to the next argument*/
for (i = 0; i < num; i++)
{
/* bitwise AND operator */
unsigned int val = va_arg(arglist,unsigned int);
result &= val;
printf("%u: val=%u, result=%u\n", i, val, result);
}
va_end(arglist);
printf("\nthe return value: base 10 = %u\t", result);
printf("base 16 = %x\n", result);
return;
}
int main(void)
{
and_bits(3, 7,2,3);
return 0;
}
Which produces as output:
0: val=7, result=7
1: val=2, result=2
2: val=3, result=2
the return value: base 10 = 2 base 16 = 2

Related

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

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.

Simple C function returns nonsense

I need to make simple function that converts binary number (string) to decimal number (long). When it returns result, it's nonsense. I've tried to return all others variables and it returned correct numbers. There is something wrong with my result variable.
#include "stdio.h"
#include "string.h"
#include "math.h"
long bintodec(const char *bin_num) {
long DIGIT, SUBTOTAL, RESULT = 0, I, LEN;
LEN = strlen(bin_num);
for(I = 0; I != LEN; I++) {
sscanf(&bin_num[I], "%li", &DIGIT);
SUBTOTAL = DIGIT * pow(2, LEN - I - 1);
RESULT = RESULT + SUBTOTAL;
}
return RESULT;
}
main() {
clrscr();
printf("%li", bintodec("101"));
getch();
}
sscanf is expecting a C string:
During the first iteration it receives "101" and 101 * 4 is 404
During the second iteration it receives 01 and 1 * 2 is 2
During the third iteration it receives 1 and 1 * 1 is 1
404 + 2 + 1 is 407 which must be the nonsense you are seeing
What you want is to convert each character:
DIGIT = bin_num[I] - '0';
You can convert string to long in one go, no need to iterate in loop. Changing your code like below can give you desired output
#include <stdio.h>
#include <string.h>
#include <math.h>
long bintodec(const char *bin_num)
{
long DIGIT, SUBTOTAL, RESULT = 0, I, LEN, REM;
LEN = strlen(bin_num);
sscanf(bin_num, "%li", &DIGIT);
printf("DIGIT = %li\n", DIGIT);
for (I = 0; I < LEN; I++)
{
REM = DIGIT%10;
RESULT += REM * pow(2, I);
DIGIT /= 10;
}
return RESULT;
}
int main() {
printf("%li", bintodec("101"));
}
Rather than debug your code, I'll present a more elegant solution. Consider:
long bintodec(const char *bin_num)
{
long sum = 0;
for (; *bin_num != '\0'; bin_num++) /* move pointer through string */
{
sum <<= 1; /* shift bits left (meaningless on first pass) */
sum |= (*bin_num == '1'); /* conditionally tack on new least significant bit */
}
return sum;
}
Some notes:
The key point is that the bits that encode integer type variables are identical to the binary sequence that you pass in as a string. Thus: bitwise operators. The only ones we need here are left bit-shift, which shifts each of the underlying bits one place to the left, and bitwise-or, which logically or's the bits of two numbers against one another. The equivalent representations render valid a pictorial understanding of the problem.
Rather than having to pass through the entire string to determine its length, and using that to inform the pow function, we can slot incoming bits in on the right.
Here's what's going on within the for loop:
1st pass:
sum <<= : 00000 /* more zero's contained in a long */
string: "10101"
ptr: ^
sum |= : 00001
2nd pass:
sum: 00010
string: "10101"
ptr: ^
sum: 00010
3rd pass:
sum: 00100
string: "10101"
ptr: ^
sum: 00101
... and so forth.
In general, rather than invoking
pow(2, arg)
you should leverage the bit-shift operator, which exactly accomplishes multiplication by some power of two. (Appending a zero is multiplication by 10 in base 10).

Finding frequency of an integer in an array and calculating x to the nth power

I am trying to solve two different C problems and would like some help and advice in order to better understand how C works and if I'm on the right track with these.
First problem is: To write a function that counts the number of times the value (x) appears among the first (n) elements of an array and returns that count as the frequency of x in theArray. So, an example would be if the array being passed contained the values {5, 7, 23, 8, 23, 67, 23}. And n was 7 and x was 23, then it would return a value of 3 since 23 occurs 3 times within the first 7 elements of the array.
Here is what I have so far:
#include <stdio.h>
#define SIZE 20 /* just for example - function should work with array of any size */
int frequency (int theArray[], int n, int x)
{
int i;
int count = 0;
for (i = 0; i < n; i++)
{
if (theArray[i] == x)
{
count = count++;
}
}
return (count);
}
int main(void)
{
/* hard code n and x just as examples */
int n = 12; /* look through first 12 items of array */
int x = 5; /* value to find */
int numberFrequency;
long int theArray[SIZE] = {5,2,3,4,5,6,1,2,10,5,10,12,6,8,7};
numberFrequency = frequency (theArray[SIZE], n, x);
printf ("%i", numberFrequency);
return 0;
}
Currently I'm getting a run time error message and believe it has something to do with the for loop function.
Second problem is: Write a function that raises an integer to a positive integer power. Have the function return a long int, which represents the results of calculating x to the nth power. Do not use the C pow library function and do not use recursion!
My code so far:
#include <stdio.h>
int x_to_the_n (int x, int n)
{
int i;
long int result = 1;
if (n == 0)
{
return(result);
}
else
{
for (i = 0; i < n ; ++i)
{
/* equation here - How can I make (x*x*x*x*x*x,etc...? */
result = x*(n*x);
}
}
return (result);
}
int main(void)
{
int x =4;
int n =5;
long int result;
result = x_to_the_n (x, n);
printf ("%i", result);
return 0;
}
I can't use recursion so that is out of the question. So, I thought the next best thing would be a for loop. But I'm a little stuck in how I would go about making a for loop do (xxx*x....) based on value of (n). Any help and advice would be appreciated!
In the first problem you give an element after the array as a parameter to your function.
You define a long int array, and pass it into a function expecting an int array.
long int theArray[SIZE] = {5,2,3,4,5,6,1,2,10,5,10,12,6,8,7};
should be
int theArray[SIZE] = {5,2,3,4,5,6,1,2,10,5,10,12,6,8,7};
Instead of this:
numberFrequency = frequency (theArray[SIZE], n, x);
try this:
numberFrequency = frequency (theArray, n, x);
And replace:
count = count++;
with:
count++;

Unexpected behaviour from sorting functions

As a homework, I've written this program that is supposed to sort a console input using qsort_r (this is the one thing I can't change, we're required to use qsort_r). We were supposed to implement three different sorting functions; compVal sorts the inputs normally by value, compOnes orders the inputs by the amount of 1s their bit value contains, and compBitSeq orders them by the longest bit sequence (and the sorting is supposed to work both ways, hence the direction variable).
The normal sorting function works fine. I can't get compOnes and compBitSeq to work, though. I've tried out the auxiliary functions countOnes and bitSequence on their own; they seem to work just fine and do what I expect them to. The program as a whole, however, gives me a segmentation error when I try to tun it.
Since I'm not super secure with pointers yet, I cannot really pinpoint what is wrong here. I do assume that there might be a problem in passing a function to a function and that I'm not passing all the values correctly, but I'm not sure how else to do this? I have tried putting everything in one function, which is very unelegant since I have to do the same loop to find both acount and bcount, but that also didn't work. qsort_r is also cutting down my flexibility here since I have to stick to the data types that the function requires.
I've now got rid of the segmentation fault, interchanging the function strcomp with memcmp did the trick! Now I do get an output, but it's not as desired and I can't get behind what's wrong here. I've tried out my countOnes and bitSeq functions with a couple of values and the output tells me that the values that are being determined are right (I commented that in my code so I know what order it should be in). But the sorting seems to be totally random (well it probably isn't, but I really can't tell what it sorts by... and I do feel like the output is different every time, even with the same numbers, especially if I enter them in a different order), even for the totally normal sorting sequence.
If this helps, I now modified my functions so the print what numbers they are comparing, and... it's some negative numbers:
number a: -41, number b: -39, order: -2
number a: -34, number b: -31, order: -3
number a: -36, number b: -34, order: -2
number a: -41, number b: -36, order: -5
number a: -39, number b: -36, order: -3
3, 15, 7, 97, 32
(obviously, the numbers came out as they went in, since the values all give a negative result...)
Where do they come from? Apparently I passed something wrong but I can't tell what...? Maybe some of the data types got jumbled up, but I can't find out which and where. I tried to change around some things, but that didn't help.
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int compVal (const void *a, const void *b, void *direction) {
int order = memcmp(a, b, sizeof(char)) * *(int *) direction;
printf("number a: %d, number b: %d, order: %d\n", *(char *)a, *(char *)b, order);
if (order > 0) {
return 1;
} else if (order < 0) {
return -1;
} else {
return 0;
}
}
int countOnes (char number) {
int counter = 0;
for (int i = 0; i < (8 * sizeof(char)); i++) {
if (number & 1) {
counter += 1;
}
number = number >> 1;
}
return counter;
}
int bitSequence (char number) {
int bit = number & 1;
number = number >> 1;
int current = 1, max = 1;
for (int i = 1; i < (8 * sizeof(char)); i++) {
if ((number & 1) == bit) {
current += 1;
if (current > max) {
max = current;
}
} else {
current = 1;
}
bit = number & 1;
number = number >> 1;
}
return max;
}
int compOnes (const void *a, const void *b, void *direction) {
char achar = *(char *) a, bchar = *(char *) b;
char acount = countOnes(achar);
char bcount = countOnes(bchar);
//return memcmp(&acount, &bcount, sizeof(char)) * *(int *) direction;
printf("ones a: %d, ones b: %d\n", acount, bcount);
return compVal(&acount, &bcount, &direction);
}
int compBitSeq (const void *a, const void *b, void *direction) {
char achar = *(char *) a, bchar = *(char *) b;
char aseq = bitSequence(achar);
char bseq = bitSequence(bchar);
//return memcmp(&aseq, &bseq, sizeof(char)) * *(int *) direction;
printf("sequence a: %d, sequence b: %d\n", aseq, bseq);
return compVal(&aseq, &bseq, &direction);
}
int main (int argc, char* argv[]) {
if (argc < 3) {
printf("At least 2 values needed for sorting\n");
return EXIT_FAILURE;
}
int direction = 1;
qsort_r(&argv[1], argc - 1, sizeof(char *), compVal, &direction); // 3, 7, 15, 32, 97
//qsort_r(&argv[1], argc - 1, sizeof(char *), compOnes, &direction); // 32, 3, (7, 97), 15
//qsort_r(&argv[1], argc - 1, sizeof(char *), compBitSeq, &direction); // (97, 15), (7, 32), 3
//char test1 = countOnes(3), test2 = countOnes(7), test3 = countOnes(15), test4 = countOnes(32), test5 = countOnes(97);
//printf("%d, %d, %d, %d, %d\n", test1, test2, test3, test4, test5); // 2, 3, 4, 1, 3
//test1 = bitSequence(3), test2 = bitSequence(7), test3 = bitSequence(15), test4 = bitSequence(32), test5 = bitSequence(97);
//printf("%d, %d, %d, %d, %d\n", test1, test2, test3, test4, test5); // 6, 5, 4, 5, 4
for (int i = 1; i < argc; i++) {
if (i == argc -1) {
printf("%s\n", argv[i]);
} else {
printf("%s, ", argv[i]);
}
}
return EXIT_SUCCESS;
}
You are passing a pointer to int to strcmp(), that invokes undefined behavior because strcmp() expects a nul terminated sequence of bytes which an integer is not.
Try with
memcmp(a, b, sizeof(int));
Also sizeof(char) is always 1, whereas CHAR_BIT is not necessarily 8 so this
for (int i = 1; i < 8 * sizeof(char); i++)
can be
for (int i = 1 ; i < CHAR_BIT ; i++)
instead.

Resources