How does this foo function works? - c

This C program will take the value stored in the variable a and print them one by one.
#include <stdio.h>
void foo(int n, int sum)
{
int k = 0, j = 0;
if (n == 0)
return;
k = n % 10;
j = n / 10;
sum = sum + k;
foo (j, sum);
printf ("%d, ", k);
}
int main ()
{
int a = 2048, sum = 0;
foo (a, sum);
printf("\n");
return 0;
}
Output:
2, 0, 4, 8,
When the function foo executes:
1) For the first time: n = 2048, k = 8, j = 204, sum = 8
2) For the second time: n = 204, k = 4, j = 20, sum = 12
3) For the third time: n = 20, k = 0, j = 2, sum = 12
4) For the fourth time: n = 2, k = 2, j = 0, sum = 14
If I replace the line (present in the foo function):
printf ("%d, ", k);
with this:
printf ("%d | %d, ", k, sum);
Output:
2 | 14, 0 | 12, 4 | 12, 8 | 8,
Can someone please explain how this program works:
1) How it's printing value stored in a?
2) And in this order: 2, 0, 4, 8, ?
3) Why is the value of sum is changing when we're printing values of k?
4) What would happen when n become 0?

You are calling the function foo on a.
That is the order since you are printing AFTER you are processing the rest of the number. Try moving the call to printf before the call to foo in foo and see if you get anything different.
sum is changing because you are doing sum = sum + k and passing it to all the future calls.
When n eventually becomes 0 due to repeated divisions, the last call to foo starts returning and following them all the previous calls start returning after printing the digit they had extracted using n % 10

Related

Optimal Selection for minimum total sum

This is a problem from competitive programmer's handbook:
We are given the prices of k
products over n days, and we want to buy each product exactly once. However,
we are allowed to buy at most one product in a day. What is the minimum total
price?
Day
0
1
2
3
4
5
6
7
Product 0
6
9
5
2
8
9
1
6
Product 1
8
2
6
2
7
5
7
2
Product 2
5
3
9
7
3
5
1
4
The Optimal Selection is:
product 0 on day 3 at price 2,
product 1 on day 1 at price 2,
product 2 on days 6 at price 1.
which gives us the total of 5.
The solution:
We either do not buy any product on day d or buy a product x
that belongs to set S. In the latter case, we remove x from set S and add the price of x to the total price.
Here's the code from book:
#include <stdio.h>
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
int main()
{
int price[3][8] = {{ 6, 9, 5, 2, 8, 9, 1, 6 },
{ 8, 2, 6, 2, 7, 5, 7, 2 },
{ 5, 3, 9, 7, 3, 5, 1, 4 }};
int n = 8, k = 3;
int total[1<<10][10];
//Buy all products on day 0
for (int x = 0; x < k; x++) {
total[1<<x][0] = price[x][0];
}
for (int d = 1; d < n; d++) {
for (int s = 0; s < (1<<k); s++) {
total[s][d] = total[s][d-1];
for (int x = 0; x < k; x++) {
if (s & (1<<x)) {
total[s][d] = min(total[s][d], total[s ^ (1<<x)][d-1] + price[x][d]);
break;
}
}
}
}
//Output
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
printf("%d", total[i][j]);
}
printf("\n");
}
}
The problem restricts us to buy only one product a day but the code seems to not address that issue at all (also, we buy all products on first day which is fine). The output is just the minimum for each product available by that day [1,2,1]. What am I doing wrong here?
After quite a bit of time in the debugger I was able to make the algo from the book work. Suffice to say the snippet provided in the book is completely broken.
Most major edits:
we will only update a more complex sum if we are updating it from an adjacent sum, that is, we do not update a sum at 111 from the sum of 001 or 010. We use __builtin_popcount to find the difference between the current set index and the one we are tryign to update from.
we will only update higher order sets if enough days has passed for prior sets to be filled.
I hope that I didn't make a mistake here(again). If I did, feel free to correct me. I did try to verify multiple inputs this time and this seems to be working.
Note that I am using multiple local variables that are completely unnecessary. I just wanted some clarity and readability.
This is essentially the same algorithm as in the book, but with a set of restrictions necessary for it to function correctly. Without those restrictions it adds up completely incompatible stuff or adds up at the wrong time and ends up not working.
The algo does address that you can only buy 1 item a day in the sol[xorIndex][dayIndex-1] + currentPrice part. The sol part being accessed was filled on previous days with items excluding the one we are adding.
int optimalSelection(int products, int days, int prices[products][days]){
int sol[1<<products][days];
memset(sol, 0, sizeof(sol));
for (int x = 0; x < products; x++) {
sol[1<<x][0] = prices[x][0];
}
for (int dayIndex = 1; dayIndex < days; dayIndex++) {
int allPossibleSetsCount = 1<<products;
for (int setIndex = 0; setIndex < allPossibleSetsCount; setIndex++) {
int currentMin = sol[setIndex][dayIndex-1];
for (int productIndex = 0; productIndex < products; productIndex++) {
if (setIndex&(1<<productIndex)) {
// this is the index of the set WITHOUT current product
int xorIndex = setIndex^(1<<productIndex);
if(__builtin_popcount(xorIndex) > dayIndex)
continue;
if (__builtin_popcount(setIndex ^ xorIndex) == 1){
// minimum for the prior day for the set excluding this product
int previousMin = sol[xorIndex][dayIndex-1];
// current price of the product
int currentPrice = prices[productIndex][dayIndex];
sol[setIndex][dayIndex] = currentMin == 0 ? previousMin + currentPrice : std::min(previousMin + currentPrice, currentMin);
currentMin = sol[setIndex][dayIndex];
}
}
}
}
}
return sol[(1<<products)-1][days-1];
}
The posted algorithm has a time and space complexity of n.k.2k which seems very expensive and likely to cause a stack overflow for moderately large sets.
Furthermore, the output is not very informative and the constraint at most one product per day does not seem enforceable.
Here is an alternative approach using recursion, with similar time complexity nk but a much smaller memory footprint:
#include <stdio.h>
enum { N = 8, K = 3 };
struct optim {
const int (*price)[N];
int bestsol[K];
int bestprice;
};
void test(struct optim *p, int i, int set, int price, int *sol) {
if (i >= K) {
if (p->bestprice > price) {
p->bestprice = price;
for (int j = 0; j < K; j++) {
p->bestsol[j] = sol[j];
}
}
} else {
for (int d = 0; d < N; d++) {
if (set & (1 << d)) {
continue; // constaint: only 1 product per day
}
sol[i] = d;
test(p, i + 1, set | (1 << d), price + p->price[i][d], sol);
}
}
}
int main() {
int price[K][N] = { { 6, 9, 5, 2, 8, 9, 1, 6 },
{ 8, 2, 6, 2, 7, 5, 7, 2 },
{ 5, 3, 9, 7, 3, 5, 1, 4 } };
struct optim data = { price, { 0, 1, 2 }, price[0][0] + price[1][1] + price[2][2] };
int sol[K];
test(&data, 0, 0, 0, sol);
printf("price: %d, days: [", data.bestprice);
for (int i = 0; i < K; i++) {
printf(" %d", data.bestsol[i]);
}
printf(" ]\n");
return 0;
}
Output: price: 5, days: [ 3 1 6 ]
Turns out the solution that was provided in the book was incomplete. For the program to return the correct result, all subsets of first day have to be populated but in the book only the subsets containing single element that were mapped to powers of two i.e., the indices 1,2,4,etc of total[][] were populated which left the other subsets to have value of 0. This made each of the subsequent day calculation to take minimum value which is 0.
code in line 14 to 16
for (int x = 0; x < k; x++) {
total[1<<x][0] = price[x][0];
}
must be replaced with:
for (int s = 0; s < (1 << k); s++) {
for (int x = 0; x < k; x++) {
if (s & (1 << x)) {
total[s][0] = price[x][0];
}
}
}
Minimum Total Sum for each day will be the set that contains all the elements i.e. total[(1<<k)-1][index of day].
With all the changes the working code is:
#include <stdio.h>
#ifndef min
#define min(a, b)((a) < (b) ? (a) : (b))
#endif
int main()
{
int price[3][8] = {
{ 6, 9, 5, 2, 8, 9, 1, 6 },
{ 8, 2, 6, 2, 7, 5, 7, 2 },
{ 5, 3, 9, 7, 3, 5, 1, 4 }
};
int n = 8, k = 3;
//Changed to scale with input
int total[1 << k][n];
//Buy all products on day 0
//Changes here
for (int s = 0; s < (1 << k); s++)
{
for (int x = 0; x < k; x++)
{
if (s &(1 << x))
{
total[s][0] = price[x][0];
}
}
}
for (int d = 1; d < n; d++)
{
for (int s = 0; s < (1 << k); s++)
{
total[s][d] = total[s][d - 1];
for (int x = 0; x < k; x++)
{
if (s &(1 << x))
{
total[s][d] = min(total[s][d], total[s ^ (1 << x)][d - 1] + price[x][d]);
break;
}
}
}
}
//Output
//Changes here
printf("%d", total[(1 << k) - 1][n - 1]);
}

Loop through odd numbers and 2

Is it possible in C to have a fast for/while loop that loops through the odd numbers and 2? Without using arrays.
So I'd like it to loop through {1, 2, 3, 5, 7, 9, ..}
Of course. Here is a pretty straight forward way.
for(int i=1; i<N; i++) {
if(i>3) i++;
// Code
}
A bit more hackish variant:
for(int i=1; i<N; i+=1+(i>2)) {
// Code
}
But I think in this case that the most readable variant would be something like:
// Code for 1 and 2
// Then code for 3,5,7 ...
for(int i=3; i<N; i+=2) {
// Code
}
Another option
for(int i=1;;++i) // you didn't specify a limit
{
switch(i)
{
default:
if(!(i&1))continue;
case 1:
case 2:
DoSomething(i):
}
}
Another alternative which does use an array but only a small one that is a constant size of two elements no matter how many numbers in the sequence would be:
{
int i;
int iray[] = {1, 2};
int n = 15;
for (i = 1; i < n; i += iray[i > 2]) {
printf (" i = %d \n", i);
// code
}
}
which produces:
i = 1
i = 2
i = 3
i = 5
i = 7
i = 9
i = 11
i = 13
Extending this alternative to other sequences
And this alternative can be extended to other sequences where there is a change of a similar nature. For instance if the desired sequence was
1, 2, 3, 5, 8, 11, ..
Which involves several changes in the sequence. Beginning at 1 an increment of 1 is used followed by a first increment change beginning at 3 where an increment of 2 is used followed by a second change in the sequence beginning at 5 where an increment of 3 is used, you can make the following modification.
{
int i;
int iray[] = {1, 2, 3}; // increment changes
int n = 15;
// calculate the increment based on the current value of i
for (i = 1; i < n; i += iray[(i > 2) + (i > 3)]) {
printf (" i = %d \n", i);
// code
}
return 0;
}
which would produce:
i = 1
i = 2
i = 3
i = 5
i = 8
i = 11
i = 14
#include <stdio.h>
int main()
{
for(unsigned x = 0; x < 10; x++)
printf("%u%s element - %u\n",x + 1, !x ? "st" : x == 1 ? "nd" : x == 2 ? "rd" : "th", !x + x * 2 - (x >= 2));
return 0;
}
no jumps calculating in the !x + x * 2 - (x >= 2) so no pipeline flushes.

Trying to write a program that counts the amount of even numbers in an array and returns the value

I am trying to make a program that will count the number of even numbers in the provided arrays. When I run the program now, it will return the amount of numbers in the array, but not the amount of even numbers. For some reason my count_even function doesn't work. Can anyone help?
#include <stdio.h>
int main()
{
int data_array_1[] = { 1, 3, 5, 7, 9, 11 };
int data_array_2[] = { 2, -4, 6, -8, 10, -12, 14, -16 };
int data_array_3[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
int data_array_4[] = { 6, 2, 4, 5, 1, -9 };
int data_array_5[] = { 1, 3, 9, 23, 5, -2, 4 };
int result_1 = count_even(data_array_1, 6);
printf("data_array_1 has %d even numbers.\n", result_1);
int result_2 = count_even(data_array_2, 8);
printf("data_array_2 has %d even numbers.\n", result_2);
int result_3 = count_even(data_array_3, 11);
printf("data_array_3 has %d even numbers.\n", result_3);
int result_4 = count_even(data_array_4, 6);
printf("data_array_4 has %d even numbers.\n", result_4);
int result_5 = count_even(data_array_5, 7);
printf("data_array_5 has %d even numbers.\n", result_5);
return 0;
}
int count_even(int* data_array, int size)
{
int even_num = 0;
for (int i = 0; i == size; i++)
{
if (data_array[size] % 2 == 0)
{
even_num++;
}
}
return even_num;
}
The condition in your for loop is wrong.
The correct condition should say "as long as the index is smaller than size", but yours say "as long as the index equal to to size".
The condition should be i < size.
As for the result, it seems like it should return 0 (for the non-working code), not size.
Also, you are using size as an index, when you should use i.
In your count_even function, you are using the size attribute as the array index, when it should be i
int count_even(int* data_array, int size)
{
int even_num = 0
for(int i = 0; i <= size, ++i)
{
if(data_array[i] % 2 == 0)
{
even_num++;
}
}
return even_num;
}
these two lines are the root of the problems in the code:
for (int i = 0; i == size; i++)
{
if (data_array[size] % 2 == 0)
the for() statement, should be:
for (int i = 0; i < size; i++)
so the loop exits when reaching the end of the array
the if() statement is always looking at the same entry beyond the end of the array, This is undefined behaviour
The if() statement should be:
if (data_array[i] % 2 == 0)
However, the modulo operator & is not a good choice for negative numbers
a better choice would be:
if ( !(data_array[i] & 1 ) )

shifting a sequence of numbers in C?

I have a question about some trying to wrap around a sequence of numbers that I'm trying to shift in the C programming language. The first value that is found in the sequence of numbers I calculate via a loop gets thrown out in the end. Here is what the code looks like right now:
numbers[d] = numbers[x];
for (d = y-1; d >=0; d --){
numbers[d] = numbers[(d - 1) % y];
printf(" numbers[d] = %d \n", numbers[d]);
}
Here are the numbers[x] I calculated from my previous loop:
1, 17, 3, 15, 14, 6, 12, 8, 10
Here is what the numbers[d] currently looks like:
17, 3, 15, 14, 6, 12, 8, 10, 10
...and here is what it should look like:
17, 3, 15, 14, 6, 12, 8, 10, 1
It seems like it doesn't wrap the 1 around to the end. Is there a conditional that I am missing in my loop? Thanks!
Let's analyze your for loop, minus the printf statement.
for (d = y-1; d >=0; d --){
numbers[d] = numbers[(d - 1) % y];
}
Before you start the loop, you have the following values in numbers.
1, 17, 3, 15, 14, 6, 12, 8, 10
The value of y is 9.
In the first iteration of the loop, d = 8. (d-1)%y = 7. You replace the value of number[8] by number[7]. The array becomes:
1, 17, 3, 15, 14, 6, 12, 8, 8
In the next iteration of the loop, d = 7. (d-1)%y = 6. You replace the value of number[7] by number[6]. The array becomes:
1, 17, 3, 15, 14, 6, 12, 12, 8
When you reach the iteration where d=1, (d-1)%y = 0. You replace the value of number[1] by number[0]. The array becomes:
1, 1, 17, 3, 15, 14, 6, 12, 8
In the next iteration, d=0, (d-1)%y = -1. The statement
numbers[d] = numbers[(d - 1) % y];
is equivalent to
numbers[0] = numbers[-1];
This certainly leads to undefined behavior but it doesn't explain the other numbers in your output. Maybe the output that you posted corresponds to a different block of code.
I think the answer by #JonathanLeffler gives a solution to your algorithmic problem. I won't repeat that here.
Code
#include <stdio.h>
static const int debug = 0;
static void dump_array(const char *tag, int n, const int array[n])
{
printf("%s (%d)", tag, n);
for (int i = 0; i < n; i++)
printf("%3d", array[i]);
putchar('\n');
}
static void rot1u(int n, int numbers[n])
{
int v = numbers[n-1];
for (int d = n - 1; d >= 0; d--)
{
numbers[d] = numbers[(n + d - 1) % n];
if (debug)
printf(" numbers[%d] = %d\n", d, numbers[d]);
}
numbers[0] = v;
dump_array("Up After: ", n, numbers);
}
static void rot1d(int n, int numbers[n])
{
int v = numbers[0];
for (int d = 0; d < n; d++)
{
numbers[d] = numbers[(d + 1) % n];
if (debug)
printf(" numbers[%d] = %d\n", d, numbers[d]);
}
numbers[n-1] = v;
dump_array("Dn After: ", n, numbers);
}
int main(void)
{
int numbers[] = { 1, 17, 3, 15, 14, 6, 12, 8, 10 };
enum { N_NUMBERS = sizeof(numbers) / sizeof(numbers[0]) };
dump_array("-- Before:", N_NUMBERS, numbers);
rot1u(N_NUMBERS, numbers);
rot1d(N_NUMBERS, numbers);
rot1d(N_NUMBERS, numbers);
rot1d(N_NUMBERS, numbers);
rot1u(N_NUMBERS, numbers);
rot1u(N_NUMBERS, numbers);
return 0;
}
Example output
-- Before: (9) 1 17 3 15 14 6 12 8 10
Up After: (9) 10 1 17 3 15 14 6 12 8
Dn After: (9) 1 17 3 15 14 6 12 8 10
Dn After: (9) 17 3 15 14 6 12 8 10 1
Dn After: (9) 3 15 14 6 12 8 10 1 17
Up After: (9) 17 3 15 14 6 12 8 10 1
Up After: (9) 1 17 3 15 14 6 12 8 10
You need to save the element(s) which should be rotated to the the other side before the loop, and only put it into its proper place (theem into their proper places) afterwards.
#include <stdio.h>
#include <time.h>
#define METHOD 2
#define MAX_SKIERS 20
int starting_lineup[MAX_SKIERS+1];
int main(void)
{
int i, num_skiers = 20;
srand(time(NULL));
int pos1, pos2, temp;
for (i = 0; i <= num_skiers; i++)
starting_lineup[i] = i;
for (i = 0; i < num_skiers*2; i++) {
// Generate two random positions
pos1 = rand() % num_skiers + 1;
pos2 = rand() % num_skiers + 1;
// Swap the skiers at the two positions
temp = starting_lineup[pos1];
starting_lineup[pos1] = starting_lineup[pos2];
starting_lineup[pos2] = temp;
}
printf("The starting lineup (first to last):\n");
for (i = 1; i <= num_skiers; i++)
printf("%s%d", (i == 1 ? "" : ", "), starting_lineup[i]);
putchar('\n');
return 0;
}

How can I average a subset of an array and store the result in another array?

I have a C array fftArray[64] that contains values that I want averaged and placed into another array frequencyBar[8]. Getting the average of the entire array would be easy enough using a for statement.
int average, sum = 0;
for (i = 0; i < 64; i++)
{
sum += fftArray[i];
}
average = sum/64;
But I just can't seem to figure out how to get the average from fftArray[0] through fftArray[8] and store this in frequencyBar[0], the average of fftArray[9] through fftArray[16] and store this in frequencyBar[1], etc. Can anyone help me out with this? Thanks
This looks like a homework assignment, so, rather than give you the outright answer, I'd rather just point you in the right direction...
use a nested loop (one inside the other). One loop cycles 0-7, the other one 0 - 63. Use the smaller one to populate your sliced averages.
or better yet use the % operator to see when you've gone through 8 elements and do an average of your total, then reset the total for the next set. Then you'll have learned how to use the % operator too! :)
[EDIT]
ok, if not homework then something like this... I haven't written C in 5 years, so treat this as pseudo code:
//assuming you have a fftArray[64] with data, as per your question
int i,sum,avCounter,total;
int averages[8];
for(i=0 , avCounter=0, total=0 ; i<64; ){
total += fftArray[i];
if(++i % 8 == 0){ //%gives you the remainder which will be 0 every 8th cycle
averages[avCounter++] = total / 8
total = 0; //reset for next cycle
}
}
I think this will work better than a nested loop... but I'm not sure since % is division which is more processor heavy than addition... however... I doubt anyone would notice :)
int i, j;
for (i = 0; i < 8; i++) {
int sum = 0;
for (j = 0; j < 8; j++) {
sum += fftArray[ 8*i + j ];
}
frequencyBar[i] = sum / 8;
}
Bonus exercise: Optimize this code for speed on your chosen platform.
TF,
DISCLAIMER: This code is just off the top of my head... it hasn't even been compiled, let alone tested.
// returns the average of array[first..last] inclusive.
int average(int[] array, int first, int last) {
int sum = 0;
for (i = first; i <= last; i++)
sum += array[i];
return sum / (last - first + 1); // not sure about the +1
}
Then what you'd do is loop through the indexes of your frequencyBar array [0..7], setting frequencyBar[i] = average(array, first, last);... the tricky bit is calculating the first and last indexes... try i*8 and (i+1)*8 respectively... that may not be exactly right, but it'll be close ;-)
Cheers. Keith.
EDIT: Bored... waiting for my test results to come back. No news is good news, right? ;-)
It turns out that passing the length is a fair bit simpler than passing the last index.
#include <stdio.h>
int sum(int array[], int first, int length) {
int sum = 0;
for (int i = first; i < first+length; i++)
sum += array[i];
return sum;
}
double average(int array[], int first, int length) {
double total = sum(array, first, length);
#ifdef DEBUG
printf("DEBUG: [%2d..%2d] %d", first, first+length-1, array[first]);
for (int i = first+1; i < first+length; i++)
printf(" + %d", array[i]);
printf(" = %d / %d = %f\n", (int)total, length, total/length);
#endif
return total / length;
}
int main(int argc, char* argv[]) {
int array[] = { // average
1, 2, 3, 4, 5, 1, 2, 3, // 2.625
4, 5, 1, 2, 3, 4, 5, 1, // 3.125
2, 3, 4, 5, 1, 2, 3, 4, // 3
5, 1, 2, 3, 4, 5, 1, 2, // 2.875
3, 4, 5, 1, 2, 3, 4, 5, // 3.375
1, 2, 3, 4, 5, 1, 2, 3, // 2.625
4, 5, 1, 2, 3, 4, 5, 1, // 3.125
2, 3, 4, 5, 1, 2, 3, 4 // 3
};
double frequency[8];
for (int i = 0; i < 8; i++)
frequency[i] = average(array, i*8, 8);
for (int i = 0; i < 8; i++)
printf("%f ", frequency[i]);
printf("\n");
}
Watch your sum doesn't wrap around if fftArray has large value in!

Resources