I want to calculate the number of integers excluding repeats line by line from the file.
The output I desire is:
Duplicates : 9
Duplicates : 4
Duplicates : 5
Duplicates : 5
Duplicates : 1
Duplicates : 1
Duplicates : 8
For further explanation of the concept:
Take the second line of the file:
1 2 3 4 5 6 5 4 5
At this line there is a 1 so increment the counter because 1 was found first.
Next comes a 2, 2 is not 1 so increment the counter. Next comes a 3, 3 is not a 2 so increment the counter. Next comes a 4, 4 is not a 3 so increment the counter. Next comes a 5, 5 is not a 4 so increment the counter. Next comes a 6, 6 is not a 5 so increment the counter. Next comes a 5, 5 is not a 6 so increment the counter. Next comes a 4, 4 is not a 5 so increment the counter. Next comes a 5, 5 is not a 4 so increment the counter. The number of integers excluding repeats is 9.
Another example:
Take a look a line 8 of the file:
34 34 34 34 34
At this line there is a 34 so increment the counter. Next comes a 34, 34 is 34 so do not increment the counter. Next comes 34, 34 is 34 so do not increment the counter. Next comes a 34, 34 is 34 so do not increment the counter. Next comes a 34, 34 is 34 so do not increment the counter. The number of integers excluding repeats is 1.
EDIT:
I took the suggestion of a user on here and looked at a few link related to adjacent strings and integers. The output is almost completely correct now when compared to the desired output that I listed above. I will only put the pertain code below:
Output:
check1:1
check1:1
check1:2
Duplicates : 6 (Wrong value)
check1:2
Duplicates : 5 (Wrong value)
Duplicates : 5
Duplicates : 5
check1:0
check1:0
check1:0
check1:0
Duplicates : 1
Duplicates : 1
check1:0
check1:0
check1:2
check1:3
check1:3
check1:3
check1:4
check1:5
check1:5
check1:5
check1:5
check1:6
check1:6
Duplicates : 7 (Wrong value)
From the output it appears that whenever a test case goes through the if statement if(array[check] == ch), the output is incorrect.
I have been staring at the loops in this function for a long and I am still stumped.
Any suggestions as to why that loop is leading to incorrect values? Thank you.
Your logic is too complicated, this simple logic should do it
Count the first value
Start a loop from the second value to the last
Subtract the current value from the previous, if the result is 0 then it's the same value, do not add to the counter otherwise add to the counter.
I wrote a program to show you how
numbers.txt
1 2 3 4 5 6 5 4 5
14 62 48 14
1 3 5 7 9
123 456 789 1234 5678
34 34 34 34 34
1
1 2 2 2 2 2 3 3 4 4 4 4 5 5 6 7 7 7 1 1
program.c
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
FILE *file;
char line[100];
file = fopen("numbers.txt", "r");
if (file == NULL)
return -1;
while (fgets(line, sizeof(line), file) != NULL)
{
char *start;
int array[100];
int count;
int value;
int step;
count = 0;
start = line;
while (sscanf(start, "%d%n", array + count, &step) == 1)
{
start += step;
count += 1;
}
fprintf(stderr, "%d ", array[0]);
value = 1;
for (int i = 1 ; i < count ; ++i)
{
value += (array[i] - array[i - 1]) ? 1 : 0;
fprintf(stderr, "%d ", array[i]);
}
fprintf(stderr, " -- %d\n", value);
}
fclose(file);
return 0;
}
You simply need to check the current value to previous value of the array and check if they are equal or not something like this ::
int ans = 1;
for (int i = 1 ; i < n ; i++) { //n is the number of elements in array
if (a[i] != a[i - 1]) {
ans++;
}
}
printf("%d", ans);
I do not exactly understand why you use so many check in your code. What I do in this code is that I check my current element in the array (starting from 1) and compare it with previous element, so if they are not equal you have a unique element in your array (sequentially), and hence I increment the ans which is the number of unique elements sequentially.
Here I start with ans = 1 because I assume that there will be at least 1 element in your array and that will be unique in any case.
I don't know what you are using that much code for.
But for what i understand you want to do, it a simple loop like this:
#include <stdio.h>
int main() {
int array[] = {1,3,5,7,9};
int count = 1;
int i = 0;
for(i=1; i<(sizeof(array)/sizeof(array[0])); i++) { //sizeof(array)/sizeof(array[0]) calculates the length of the array
if(array[i]!=array[i-1]) {
count++;
}
}
printf("%d", count);
}
Related
How do I make my code have an output like this:
Enter your number: 4
1 1 1 2
2 2 2 3
3 3 3 4
4 4 4 5
I can't seem to figure out how to make it so the last digit prints the next value iteration.
#include <stdio.h>
int main(){
int num;
int i = 1;
printf("Enter your number: ");
scanf("%d", &num);
for(i = 1; i<=num; i++){
for(int j = 0; j<num; ++j)
{
printf("%d ",i);
}
printf("\n");
}
Doing this using nested loops are simple and doesn't require any kind of special calculations, if-statements or other more or less fancy stuff. Just keep it simple.
Your task is:
for each row:
print "rowindex+1 and a space" n-1 times
print "rowindex+2 and a newline" 1 time
"for each row" is one simple loop.
"n-1 times" is another (nested) simple loop.
So keep it simple... just two ordinary for-loops like:
#include <stdio.h>
int main()
{
int n = 4;
for (int i = 0; i < n; i++) // for each row
{
for (int j = 0; j < n-1; j++) // n-1 times
{
printf("%d ", i + 1);
}
printf("%d\n", i + 2); // 1 time
}
return 0;
}
Here is something kind of from out in the left field, and off topic, leaving behind not only the requirements of the homework, but the C language. However, we will find our way back.
We can solve this problem (sort of) using text processing at the Unix prompt:
We can treat the smallest square
12
23
as an initial seed kernel, which is fed through a little command pipeline to produce a square of the next size (up to a single digit limitation):
We define this function:
next()
{
sed -e 's/\(.\).$/\1&/' | awk '1; END { print $0 | "tr \"[1-9]\" \"[2-8]\"" }'
}
Then:
$ next
12
23
[Ctrl-D][Enter]
112
223
334
Now, copy the 3x3 square and paste it into next:
$ next
112
223
334
[Ctrl-D][Enter]
1112
2223
3334
4445
Now, several steps in one go, by piping through multiple instances of next:
$ next | next | next | next | next
12
23
[Ctrl-D][Enter]
1111112
2222223
3333334
4444445
5555556
6666667
7777778
The text processing rule is:
For each line of input, repeat the second-to-last character. E.g ABC becomes ABBC, or 1112 becomes 11112. This is easily done with sed.
Add a new line at the end which is a copy of the last line, with each digit replaced by its successor. E.g. if the last line is 3334, make it 4445. The tr utility helps here
To connect this to the homework problem: a C program could be written which works in a similar way, starting with an array which holds the 1 2 2 3 square, and grows it. The requirement for nested loops would be satisfied because there would be an outer loop iterating on the number of "next" operations, and then an inner loop performing the edits on the array: replicating the next-to-last column, and adding the new row at the bottom.
#include <stdio.h>
#include <stdlib.h>
#define DIM 25
int main(int argc, char **argv)
{
if (argc != 2) {
fputs("wrong usage\n", stderr);
return EXIT_FAILURE;
}
int n = atoi(argv[1]);
if (n <= 2 || n > DIM) {
fputs("invalid n\n", stderr);
return EXIT_FAILURE;
}
int array[DIM][DIM] = {
{ 1, 2 },
{ 2, 3 }
};
/* Grow square from size 2 to size n */
for (int s = 2; s < n; s++) {
for (int r = 0; r < s; r++) {
array[r][s] = array[r][s-1];
array[r][s-1] = array[r][s-2];
}
for (int c = 0; c <= s; c++) {
array[s][c] = array[s-1][c] + 1;
}
}
/* Dump it */
for (int r = 0; r < n; r++) {
for (int c = 0; c < n; c++)
printf("%3d ", array[r][c]);
putchar('\n');
}
return 0;
}
#include<stdio.h>
int main(){
int n;
printf("Enter the number: ");
scanf("%d",&n);
for(int i =1; i<=n; i++){
for(int j=1;j<=n;j++) {
if(j==n)
printf("%d\t",i+1);
else
printf("%d\t",i);
}
printf("\n");
}
return 0;}
Nested loops will drive you crazy, trying figure out their boundaries.
While I usually oppose adding more variables, in this case it seems justified to keep track of things simply.
#include <stdio.h>
int main() {
int n = 4, val = 1, cnt1 = 1, cnt2 = 0;
for( int i = 1; i < n*n+1; i++ ) { // notice the 'square' calculation
printf( "%d ", val );
if( ++cnt1 == n ) // tired of this digit? start the next digit
cnt1 = 0, val++;
if( ++cnt2 == n ) // enough columns output? start the next line
cnt2 = 0, putchar( '\n' );
}
return 0;
}
1 1 1 2
2 2 2 3
3 3 3 4
4 4 4 5
A single example of desired output is hard to go by, especially when the code doesn't help... Anyway, here's the output when 'n' = 5.
1 1 1 1 2
2 2 2 2 3
3 3 3 3 4
4 4 4 4 5
5 5 5 5 6
All of these kinds of assignments are to try to get you to recognize a pattern.
The pattern you are given
1 1 1 2
2 2 2 3
3 3 3 4
4 4 4 5
is very close to
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
which is an easy nested loop. Write a solution to the easier pattern. Once you have that you can then you can fix it.
Hint: Notice that the only thing that changes is the last item of the inner loop.
Edit
This totally breaks the spirit of the assignment, and if you, dear student, ever try to submit something like this your professor will... probably not care, but also know full well that you didn’t do it. If I were your professor you’d lose marks, even if I knew you weren’t cheating and had written something this awesome yourself.
Single loop. Stuff added to pretty print numbers wider than one digit (except the very last). Maths, yo.
#include <stdio.h>
#include <math.h>
void print_off_by_one_square( int n )
{
int width = (int)log10( n ) + 1;
for (int k = 0; k++ < n*n ;)
printf( "%*d%c", width, (k+n)/n, (k%n) ? ' ' : '\n' );
}
int main(void)
{
int n;
printf( "n? " );
fflush( stdout );
if ((scanf( "%d", &n ) != 1) || (n < 0))
fprintf( stderr, "%s\n", "Not cool, man, not cool at all." );
else
print_off_by_one_square( n );
return 0;
}
The way it works is pretty simple, actually, but I’ll leave it as an exercise for the reader to figure out on his or her own.
Here is a different concept. Some of the answers are based on the idea that we first think about
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
and then tweak the logic for the item in the last line.
But we can regard it like this also:
We have a tape which goes like this:
1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4
and we are blindly cutting the tape into four-element pieces to form a 4x4 square. Suppose someone deletes the first item from the tape, and then adds 5:
1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5
Now, if we cut that tape blindly by the same process, we will get the required output:
1 1 1 2
2 2 2 3
3 3 3 4
4 4 4 5
Suppose we have a linear index through the tape, a position p starting at 0.
In the unshifted tape, item p is calculated using p / 4 + 1, right?
In the shifted tape, this is just (p + 1) / 4 + 1. Of course we substitute the square size for 4.
Thus:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc != 2) {
fputs("wrong usage\n", stderr);
return EXIT_FAILURE;
}
int n = atoi(argv[1]);
int m = n * n;
if (n <= 0) {
fputs("invalid n\n", stderr);
return EXIT_FAILURE;
}
for (int p = 0; p < m; p++) {
printf("%3d ", (p + 1) / n + 1);
if (p % n == n - 1)
putchar('\n');
}
return 0;
}
$ ./square 2
1 2
2 3
$ ./square 3
1 1 2
2 2 3
3 3 4
$ ./square 4
1 1 1 2
2 2 2 3
3 3 3 4
4 4 4 5
I'm trying to write a program that uses the Luhn algorithm to verify security codes. The program needs to:
read security codes from a file and enter them into an array
use one function to read the security codes
use another function to verify them
to verify them, the digits in the odd position will be summed together. The digits in the even positions will be multiplied by two; once they're multiplied by two, if the number is less than ten, it is added to a sum of the evens; if it's more than ten, the sum of the digits of the number are added to the sum of the evens. So, if the number in the second position in the array is 8, it's multiplied by 2 to get 16, then 1 + 6 = 7 is added to the sum of the evens. There's more to verifying the codes, but this is the part I'm working on right now.
The problems I have: I don't think my function for scanning the codes from the file is correct. Each of the codes in the file has 20 digits so when I was declaring the array variable I did: int sc[20]. However, there's more than one 20 digit security code, and I'm not sure how to fix that.
And second: I'm not sure how to approach the second part of summing the evens (the part where if the number multiplied by two is greater than ten, it's digits are added to the sum of the evens).
This is the first few lines from the file (the entire file is very long so I'm just listing the first few lines):
0 7 6 1 1 6 6 2 6 8 5 1 5 5 7 7 7 8 0 2
2 5 1 6 2 1 8 2 4 3 0 9 1 9 1 1 3 1 3 8
1 3 3 4 5 4 5 2 8 6 1 8 9 3 7 6 2 2 0 5
And this is my code so far:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
ReadSecurityCode(FILE* codes, int sc[]);
int main(void) {
int sc[20], i;
FILE* codes;
codes = fopen("SecurityCodes.txt", "r");
while (fscanf(codes, "%c\n", &sc) != EOF) {
ReadSecurityCode(codes, sc[20]);
}
fclose(codes);
return(0);
}
int ReadSecurityCode(FILE* codes, int sc[]) {
int i;
for (i = 0; i < 20; i++) {
fscanf(codes, "%d", &sc[i]);
}
return(sc[20]);
}
int isCodeValid(int sc[]) {
int i, sumodds = 0, sumevens = 0, sumtotal;
for (i = 1; i < 20; i = i + 2) {
sumodds = sumodds + sc[i];
}
for (i = 0; i < 20; i = i + 2) {
sc[i] = sc[i] * 2;
if (sc[i] < 10) {
sumevens = sumevens + sc[i];
}
else {
}
}
return(sumtotal);
}
The easiest option is to read and validate each line as you go. In the code you posted, this means calling isCodeValid() in while loop where you read the records:
while (fscanf(codes, "%c\n", &sc) != EOF) {
ReadSecurityCode(codes, sc);
isCodeValid(sc);
}
Consider using a char instead of int to store each digit (i.e. char sc[20]).
Not sure why ReadSecurityCode returns the first element, but scanf() can fail, so you might want to return an error code instead and check it. Also, I suggest that you use ReadSecurityCode() to read a line including the newline.
You probably also want to do something based the return value of isCodeValid(). The is-naming suggest you are returning a boolean but you are returning a sum.
With the above suggestions it would be:
while (!ReadSecurityCode(codes, sc)) {
if (!isCodeValid(sc)) {
printf("%s is invalid\n", sc);
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have an array with randomly generated numbers in it, and I need to find and store the numbers that are present at least x times. (I can easily find x, that is not important. It will be a set amount). The array will have around 100-200 elements.
I know I will have to use a loop, but I'm not sure how to structure the body of it. I'm relatively new to C programming, so this may be fairly trivial. Any help is appreciated.
I implemented two solutions, one in C and one in C++.
First solution in C:
It is simple:
Input array of numbers. Either it is inputed from console (when input = 1) or generated automatically by random generator (set constant input = 0 in first lines of main()). Input/generation is done by first loop. If generated automatically/randomly then set constants n (number of elements) and x (minimal allowed count) at first lines of main() function.
Sort them in ascending order by built-in function qsort. I provided compare() function for qsort to compare in ascending order.
Iterate through sorted array. On the way compute number c of consecutive equal numbers. If c >= x then it means we have at least x of consecutive equal numbers, it means this number occured at least x times, hence we output such number as matching our criteria.
Try it online!
#include <stdlib.h>
#include <stdio.h>
static int compare(void const * sa, void const * sb) {
int a = *(int*)sa, b = *(int*)sb;
return a < b ? -1 : a == b ? 0 : 1;
}
int main() {
// "n" - total number of integers, "x" - minimum count to find
// "input" - if 1 then read from console input array, else if 0 generate random
int const n = 50, x = 3, input = 1;
// Example of input: n = 50, x = 3, a = 3 6 17 15 13 15 6 12 9 1 2 7 10 19 3 6 0 6 12 16 11 8 7 9 2 10 2 3 7 15 9 2 2 18 9 7 13 16 11 2 9 13 1 19 4 17 18 4 15 10
// and output for this example: 2: 6 times, 3: 3 times, 6: 4 times, 7: 4 times, 9: 5 times, 10: 3 times, 13: 3 times, 15: 4 times,
if (input) {
printf("Input n and x: ");
scanf("%d %d", &n, &x);
printf("Input array: ");
} else
srand(0); // You may init this with some randomness
int * a = (int*)malloc(sizeof(int) * n); // Allocate memory for empty array
for (int i = 0; i < n; ++i) {
if (input)
scanf("%d", &a[i]);
else {
a[i] = rand() % 20; // Init numbers with random, you may input your numbers
printf("%d ", a[i]); // Print generated numbers
}
}
if (!input)
printf("\n");
qsort(a, n, sizeof(int), compare);
int c = 1;
for (int i = 1; i <= n; ++i) {
if (i == n || a[i] != a[i - 1]) {
if (c >= x)
printf("%d: %d times, ", a[i - 1], c);
c = 1;
} else
++c;
}
free(a);
return 0;
}
Input:
50 3
3 6 17 15 13 15 6 12 9 1 2 7 10 19 3 6 0 6 12 16 11 8 7 9 2 10 2 3 7 15 9 2 2 18 9 7 13 16 11 2 9 13 1 19 4 17 18 4 15 10
Second solution in C++:
Use std::map to count number of occurances of each number, by iterating (in a loop) over input array and incrementing by 1 count of current nummber inside map, then iterate (in a second loop) through this map and output those numbers that occur at least x times.
Also I used std::map specifically to have nice sorted output of numbers, if you don't need sorted order and need more speed then use std::unordered_map instead of std::map exactly same way (also do #include <unordered_map> instead of <map>).
Full code is below:
Try it online!
#include <iostream>
#include <cstdlib>
#include <vector>
#include <map>
using namespace std;
int main() {
size_t const n = 50; // How many numbers
size_t const x = 3; // At least this many times
srand(0); // Use this if only deterministic randoms are needed
vector<int> a(n); // Numbers
for (size_t i = 0; i < a.size(); ++i) {
a[i] = rand() % 20; // Some random numbers
cout << a[i] << " "; // Output our input numbers
}
cout << endl;
map<int, size_t> cnt;
// Count number of occurances
for (auto x: a)
++cnt[x];
// Output numbers that occur at least "x" times
for (auto const & p: cnt)
if (p.second >= x)
cout << p.first << ": " << p.second << " times, ";
return 0;
}
Output:
3 6 17 15 13 15 6 12 9 1 2 7 10 19 3 6 0 6 12 16 11 8 7 9 2 10 2 3 7 15 9 2 2 18 9 7 13 16 11 2 9 13 1 19 4 17 18 4 15 10
2: 6 times, 3: 3 times, 6: 4 times, 7: 4 times, 9: 5 times, 10: 3 times, 13: 3 times, 15: 4 times,
I've been working tirelessly on this assignment, it's already past due and I cannot for the life of me find a solution. We are behind on lecture and the professor still decided it was okay for us to do homework that we haven't even covered yet.
So this is the main function I've been having problems with. The goal is to read an input file full of integers:
12 15 7 1 19
18 16 15 2 8
5 4 16 7 1
19 4 16 15 3
13 9 12 4 6
9 2 19 13 15
18 20 17 17 4
3 12 2 18 18
10 14 1 14 1
7 10 18 17 18 30
After it reads the file, it's suppose to input the occurrences of each value into an array. So in index 1, there would be however many 1's there are. index 2, there would be however many 2's and so on up until 20. Index 0 will hold the total amount of integers the file contains. The loop continues to scan until it reaches the integer 30.
The length I have set to 999 because the file will never be the same, so it will be kind of random and you'll never know the length. So once it counts through up until 30, I use 'amount' as a counter and then initialize length to equal amount.
For more instruction, this is part of the directions for this function specifically that was given by the professor:
createVArray: This is a void function that takes three parameters: a FILE * and an integer array and an integer indicating the length of the array. Your function should read numbers from the file, one at a time, using the information collected to update the array. The first index of the array will be used to store the total number of votes read while each subsequent index will store the number of votes for that t-shirt logo option. Your function should continue reading the file until the number 30 is encountered.
int array2[999], array[21]; //Global dec
void createVArray(int amount, int length){
int counter, i, j, m;
length = 999;
amount = 0;
for(counter = 1; counter < length; counter++){
fscanf(votesFileptr, "%d", &array[counter]);
if(array[counter] == 30){
for (i = 1, j = 0; i < amount, j < amount; i++, j++){
array2[j] = array[i];
}
break;
}
for(m = 0; m < length; m++){
if (array[m] > 0){
printf("Occurs %d\n", array[m]);
}
}
amount++;
}
length = amount;
array[0] = amount;
for(i = 0; i < 21; i++){
printf("%d\n", array[i]);
}
}
let's start simple
createVArray: This is a void function that takes three parameters: a FILE * and an integer array and an integer indicating the length of the array
void createVArray(FILE* input, int counts[], const int length )
Your function should read numbers from the file, one at a time, using the information collected to update the array
fscanf(input, "%i", &number)
The first index of the array will be used to store the total number of votes read while each subsequent index will store the number of votes for that t-shirt logo option
++counts[0];
++counts[numbers];
Your function should continue reading the file until the number 30 is encountered
if( number == 30 ) return; // or break if you want to
Appart from some loops, additional tests and check you should have the pieces to write your function already
and if you are really desperate : http://pastebin.com/bfNTKVHq
bonus : https://godbolt.org/g/F9GYI0
I'm bored. From the spec you posted, I think your prof wants something like this:
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
void createVArray(FILE * fin, int *a, int len){
int i;
assert(len>29);
while(1){
if(fscanf(fin,"%d",&i) !=1){
perror("fscanf error");
exit(1);
}
if(i>=30)
return;
a[0]+=1;
a[i]+=1;
}
}
int main(){
int a[30];
memset(a,0,sizeof(a));
FILE *fin=fopen("test.txt","r");
createVArray(fin,a,30);
for(int i=0; i<30; ++i){
printf("a[%d]=%d\n",i,a[i]);
}
return 0;
}
test.txt:
12 15 7 1 19 18 16 15 2 8 5 4 16 7 1 19 4 16 15 3 13 9 12 4 6 9 2
19 13 15 18 20 17 17 4 3 12 2 18 18 10 14 1 14 1 7 10 18 17 18 30
output:
a[0]=50
a[1]=4
a[2]=3
a[3]=2
a[4]=4
a[5]=1
a[6]=1
a[7]=3
a[8]=1
a[9]=2
a[10]=2
a[11]=0
a[12]=3
a[13]=2
a[14]=2
a[15]=4
a[16]=3
a[17]=3
a[18]=6
a[19]=3
a[20]=1
a[21]=0
a[22]=0
a[23]=0
a[24]=0
a[25]=0
a[26]=0
a[27]=0
a[28]=0
a[29]=0
The problem presents the classic problem of accounting for the number of occurrences within a range. Any time you are presented with this type problem, you will capture the number of occurrences within an array having at least one element for each number in the range. (in your case +1 since you are storing the total votes in the first element.
The next part is to loop over all values reading all values between 1-20 representing votes cast for the corresponding tshirt design. So if you read 13 you need to increment array[13] to note that 1 vote has been recorded for tshirt 13 design. Since you are reading numbers within the range of your array, all you need to do is insure you start with an array initialized to all 0's. When each number is read, you simply increment the value at that index by one. e.g. you read 12 to increment the vote count for tshirt 12 it is simply array[12]++; (or you could do array[12] = array[12] + 1; or array[12] += 1;, they all do the same thing)
During this time you are also keeping a running total of all votes, so every time your read a valid vote from the file, simply do total++; (or total = total + 1; or total += 1;)
Putting it together, you could do something similar to the following, e.g.
#include <stdio.h>
#include <stdlib.h>
#define ARSZ 21 /* array size 0-total, 1-20 shirt votes */
void createVArray (int *a, int n, FILE *fp);
int main (int argc, char **argv) {
int array[ARSZ] = {0};
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
createVArray (array, ARSZ, fp); /* read values from fp */
if (fp != stdin) fclose (fp); /* close file if not stdin */
printf ("\n '%d' votes recorded.\n\n", *array);
for (int i = 1; i < ARSZ; i++)
printf (" tshirt[%2d] : %2d\n", i, array[i]);
return 0;
}
/* read integer values from 'fp' incrementing values in range `array`
* for each value read and returning the total values considered in
* array[0].
*/
void createVArray (int *a, int n, FILE *fp)
{
if (!a || !fp) { /* validate array and FILE stream */
fprintf (stderr, "error: invalid parameter in list.\n");
return;
}
if (!n) { *a = 0; return; } /* validate length */
int tmp = 0, total = 0; /* read into tmp, increment total */
while (fscanf (fp, " %d", &tmp) == 1) { /* validate int read */
if (tmp == 30) break; /* if 30, bail */
if (0 < tmp && tmp <= 20) /* if vote increment */
total++, a[tmp]++; /* total and value at a[tmp] */
}
a[0] = total; /* set first element to hold total votes */
}
Input File
$ cat dat/votes.dat
12 15 7 1 19
18 16 15 2 8
5 4 16 7 1
19 4 16 15 3
13 9 12 4 6
9 2 19 13 15
18 20 17 17 4
3 12 2 18 18
10 14 1 14 1
7 10 18 17 18 30
Example Use/Output
$ ./bin/tshirtvote <dat/votes.dat
'50' votes recorded.
tshirt[ 1] : 4
tshirt[ 2] : 3
tshirt[ 3] : 2
tshirt[ 4] : 4
tshirt[ 5] : 1
tshirt[ 6] : 1
tshirt[ 7] : 3
tshirt[ 8] : 1
tshirt[ 9] : 2
tshirt[10] : 2
tshirt[11] : 0
tshirt[12] : 3
tshirt[13] : 2
tshirt[14] : 2
tshirt[15] : 4
tshirt[16] : 3
tshirt[17] : 3
tshirt[18] : 6
tshirt[19] : 3
tshirt[20] : 1
Easy to see, tshirt design 18 is the big winner with 6 votes out of a total of 50 cast.
I'm writing a program that is to take a number between 1-10 and display all possible ways of arranging the numbers.
Ex
input: 3
output:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
Whenever I input 9 or 10, the program gives a segmentation fault and dumps the core. I believe the issue is my recursive algorithm is being called too many times. Could someone help point out how I could limit the amount of recursive calls necessary? Here is my current code:
void rearange(int numbers[11], int index, int num, int fact) {
int temp = numbers[index];
numbers[index] = numbers[index-1];
numbers[index-1] = temp;
int i;
for (i = 1; i <= num; ++i) // print the current sequence
{
printf("%d ", numbers[i]);
}
printf("\n");
fact--; // decrement how many sequences remain
index--; // decrement our index in the array
if (index == 1) // if we're at the beginning of the array
index = num; // reset index to end of the array
if (fact > 0) // If we have more sequences remaining
rearange(numbers, index, num, fact); // Do it all again! :D
}
int main() {
int num, i; // our number and a counter
printf("Enter a number less than 10: ");
scanf("%d", &num); // get the number from the user
int numbers[11]; // create an array of appropriate size
// fill array
for (i = 1; i <= num; i++) { // fill the array from 1 to num
numbers[i] = i;
}
int fact = 1; // calculate the factorial to determine
for (i = 1; i <= num; ++i) // how many possible sequences
{
fact = fact * i;
}
rearange(numbers, num, num, fact); // begin rearranging by recursion
return 0;
}
9! (362880) and 10! (3628800) are huge numbers that overflow the call stack when you do as many recursive calls. Because all the local variables and formal parameters have to be stored. You either you have to increase the stack size or convert the recursion into iteration.
On linux, you can do:
ulimit -s unlimited
to set the stack size to unlimited. The default is usually 8MB.
Calculating permutations can be done iteratively, but even if you do it recursively there is no need to have a gigantic stack (like answers suggesting to increase your system stack say). In fact you only need a tiny amount of your stack. Consider this:
0 1 <- this needs **2** stackframes
1 0 and an for-loop of size 2 in each stackframe
0 1 2 <- this needs **3** stackframes
0 2 1 and an for-loop of size 3 in each stackframe
1 0 2
1 2 0
2 1 0
2 0 1
Permuting 9 elements takes 9 stackframes and a for-loop through 9 elements in each stackframe.
EDIT: I have taken the liberty to add a recursion-counter to your rearrange-function, it now prints like this:
Enter a number less than 10: 4
depth 1 1 2 4 3
depth 2 1 4 2 3
depth 3 4 1 2 3
depth 4 4 1 3 2
depth 5 4 3 1 2
depth 6 3 4 1 2
depth 7 3 4 2 1
depth 8 3 2 4 1
depth 9 2 3 4 1
depth 10 2 3 1 4
depth 11 2 1 3 4
depth 12 1 2 3 4
depth 13 1 2 4 3
depth 14 1 4 2 3
depth 15 4 1 2 3
depth 16 4 1 3 2 which is obviously wrong even if you do it recursively.
depth 17 4 3 1 2
depth 18 3 4 1 2
depth 19 3 4 2 1
depth 20 3 2 4 1
depth 21 2 3 4 1
depth 22 2 3 1 4
depth 23 2 1 3 4
depth 24 1 2 3 4
....
The recursion-leafs should be the only ones which output so the depth should be constant and small (equal to the number you enter).
EDIT 2:
Ok, wrote the code. Try it out:
#include "stdio.h"
void betterRecursion(int depth, int elems, int* temp) {
if(depth==elems) {
int j=0;for(;j<elems;++j){
printf("%i ", temp[j]);
}
printf(" (at recursion depth %u)\n", depth);
} else {
int i=0;for(;i<elems;++i){
temp[depth] = i;
betterRecursion(depth+1, elems, temp);
}
}
}
int main() {
int temp[100];
betterRecursion(0, 11, temp); // arrange the 11 elements 0...10
return 0;
}
I'd make your rearange function iterative - do while added, and recursive call removed:
void rearange(int numbers[11], int index, int num, int fact) {
int temp;
do
{
temp = numbers[index];
numbers[index] = numbers[index-1];
numbers[index-1] = temp;
int i;
for (i = 1; i <= num; ++i) // print the current sequence
{
printf("%d ", numbers[i]);
}
printf("\n");
fact--; // decrement how many sequences remain
index--; // decrement our index in the array
if (index == 1) // if we're at the beginning of the array
index = num; // reset index to end of the array
} while (fact > 0);
}
This is not a task for a deep recursion.
Try to invent some more stack-friendly algorithm.
Following code has rather troubles with speed than with stack size...
It's a bit slow e.g. for n=1000 but it works.
#include <stdio.h>
void print_arrangement(int n, int* x)
{
int i;
for(i = 0; i < n; i++)
{
printf("%s%d", i ? " " : "", x[i]);
}
printf("\n");
}
void generate_arrangements(int n, int k, int* x)
{
int i;
int j;
int found;
if (n == k)
{
print_arrangement(n, x);
}
else
{
for(i = 1; i <= n; i++)
{
found = 0;
for(j = 0; j < k; j++)
{
if (x[j] == i)
{
found = 1;
}
}
if (!found)
{
x[k] = i;
generate_arrangements(n, k + 1, x);
}
}
}
}
int main(int argc, char **argv)
{
int x[50];
generate_arrangements(50, 0, x);
}
Your program is using too many recursions unnecessarily. It is using n! recursions when actually n would be enough.
To use only n recursions, consider this logic for the recursive function:
It receives an array nums[] of n unique numbers to arrange
The arrangements can have n different first number in them, as there are n different numbers in the array
(key step) Loop over the elements of nums[], and in each iteration create a new array but with the current element removed, and recurse into the same function passing this shorter array as parameter
As you recurse deeper, the parameter array will be smaller and smaller
When there is only one element left, that's the end of the recursion
Using this algorithm, your recursion will not be deeper than n and you will not get segmentation fault. The key is in the key step, where you build a new array of numbers that is always 1 item shorter than the input array.
As a side note, make sure to check the output of your program before you submit, for example run it through | sort | uniq | wc -l to make sure you are getting the correct number of combinations, and check that there are no duplicates with | sort | uniq -d (the output should be empty if no dups).
Spoiler alert: here's my implementation in C++ using a variation of the above algorithm:
https://gist.github.com/janosgyerik/5063197