Find combination of groups and letters - c

I have to find a combination of groups of letters, second letter in first group should be the same as first letter in second group etc.
For example, solution for this group: AA, CB, AC, BA, BD, DB
is this: CB, BD, DB, BA, AA, AC
I have this code so far, it works, but if there is a lot of groups, it takes ages to compute. I need to make it more efficient.
In the input file, there's this input
10
C D
B C
B B
B B
D B
B B
C A
A B
B D
D C
My code
#include <stdio.h>
#include <stdlib.h>
void permutation(char group[][2], int buffer, int sum) {
int i, j;
char temp;
if (buffer == sum && group[1][1] == group[sum][2]) {
for (i = 1; i < sum; i++)
if (group[i][2] != group[i+1][1]) break;
if (i == sum) {
FILE *output;
output = fopen("output.txt", "a");
for (j = 1; j <= sum; j++) {
fprintf(output, "%c %c\n", group[j][1], group[j][2]);
}
exit(1);
}
} else {
for (i = buffer; i <= sum; i++) {
temp = group[buffer][1];
group[buffer][1] = group[i][1];
group[i][1] = temp;
temp = group[buffer][2];
group[buffer][2] = group[i][2];
group[i][2] = temp;
permutation(group, buffer + 1, sum);
temp = group[buffer][1];
group[buffer][1] = group[i][1];
group[i][1] = temp;
temp = group[buffer][2];
group[buffer][2] = group[i][2];
group[i][2] = temp;
}
}
}
int main() {
FILE *input;
input = fopen("input.txt", "r");
int sum, i;
fscanf(input, "%d", &sum);
char group[sum][2];
for (i = 1; i <= sum; i++) {
fscanf(input, "%s", &group[i][1]);
fscanf(input, "%s", &group[i][2]);
}
permutation(group, 1, sum);
}
EDIT So I have made some changes in my program (thanks to your help, I'm very new to programming so I'm sorry for mistakes), I use permutations no more and I'm just finding path. It works well, but now my input has 100000 groups and it takes a lot of time once again (about 2 hours and I need to make it done in 1 hour in maximal). I will probably have to do that in other way once again xD Any ideas ?
#include <stdio.h>
int find(char group[][2], int buffer, int sum, int path[]) {
int i, j;
for (i = 0; i < sum; i++) {
for (j = 0; j < buffer; j++)
if (path[j] == i)
break;
if (buffer == 0 ||
(group[path[buffer-1]][1] == group[i][0] && buffer == j)) {
printf("%d\n", buffer); // just for me to know what program is currently computing
path[buffer] = i;
find(group, buffer + 1, sum, path);
if (path[sum-1] != 0)
return;
}
}
}
int main() {
FILE *input = fopen("input.txt", "r");
if (input != NULL) {
int sum, i;
fscanf(input, "%d", &sum);
char group[sum][2];
int path[sum];
for (i = 0; i < sum; i++)
fscanf(input, " %c %c", &group[i][0], &group[i][1]);
for (i = 0; i < sum;i++)
path[i] = 0;
find(group, 0, sum, path);
FILE *output = fopen("output.txt", "a");
for (i = 0; i < sum; i++)
fprintf(output, "%c %c\n", group[path[i]][0], group[path[i]][1]);
} else
printf("Input file was not found.");
}

In C array indices start at 0, so an array of size N has valid indices from 0 to N-1. In the code above you are accessing the array group out of bounds, since it has size 2 (valid indices are therefore 0 and 1), yet you are trying to access indices 1 and 2.
Either change:
char group[sum][2];
to:
char group[sum][3];
or use indices 0/1 rather than 1/2.
Note also that your code lacks error checking, e.g. on the call to fopen.

Your program as several issues:
you use 1 based indexing, which causes confusion and leads to referencing arrays and subarrays beyond their defined ends.
you parse the input with fscanf using the %s specifier: this is unsafe and will write 2 bytes for each of your inputs, writing beyond the end of each subarray and beyond the end of the last array.
You already know how to fix these, preferably by using 0 based indexing
Your algorithm is very ineffective, complexity O(n!) because you enumerate all possible permutations and check for validity only on complete permutations. You can drastically improve the performance by only enumerating permutations which already verify the constraint for their initial elements. The complexity is substantially lower, still quadratic but n is quite small.
Here is a modified version of your code that does this:
#include <stdio.h>
int permutation(char group[][2], int buffer, int sum) {
if (buffer == sum)
return group[sum-1][1] == group[0][0];
for (int i = buffer; i < sum; i++) {
if (group[buffer-1][1] == group[i][0]) {
char temp = group[buffer][0];
group[buffer][0] = group[i][0];
group[i][0] = temp;
temp = group[buffer][1];
group[buffer][1] = group[i][1];
group[i][1] = temp;
if (permutation(group, buffer + 1, sum))
return 1;
temp = group[buffer][0];
group[buffer][0] = group[i][0];
group[i][0] = temp;
temp = group[buffer][1];
group[buffer][1] = group[i][1];
group[i][1] = temp;
}
}
return 0;
}
int main(void) {
FILE *input = fopen("input.txt", "r");
int sum, i;
if (input != NULL) {
if (fscanf(input, "%d", &sum) != 1 || sum <= 0) {
printf("invalid number of pairs\n");
fclose(input);
return 1;
}
char group[sum][2];
for (i = 0; i < sum; i++) {
if (fscanf(input, " %c %c", &group[i][0], &group[i][1]) != 2) {
printf("incorrect input for pair number %d\n", i);
fclose(input);
return 1;
}
}
fclose(input);
if (permutation(group, 1, sum)) {
FILE *output = fopen("output.txt", "a");
if (output == NULL) {
printf("cannot open output file\n");
return 2;
}
for (i = 0; i < sum; i++) {
fprintf(output, "%c %c\n", group[i][0], group[i][1]);
}
fclose(output);
return 0;
} else {
printf("complete path not found\n");
return 1;
}
}
printf("cannot open input file\n");
return 2;
}
I modified other aspects of the code to improve efficiency and reusability:
input is checked for validity.
the recursive function stops and returns 1 when it finds a complete path. This allows the program to continue whether it found the path or not.
output is handled from the main function for consistency.
The above code solves the problem for the specified input with n=50 in less than 0.002 seconds on my laptop. It prints F C C E E F F E E E E E E E E E E B B F F E E A A F F C C A A A A E E F F C C E E E E E E E E E E B B C C E E E E F F E E F F F F E E C C E E E E E E B B F F A A D D A A C C C C E E E E E E B B D D F
EDIT I realized that, since you are looking for a full closed path, you do not need to try different possibilities for the first pair. main can call permutation with 1 instead of 0 and the permutation can be simplified as buffer can never be 0.

Your new code has some problems:
find is defined asa returning int, but you return nothing. You indeed do not test if you have found a complete path, fully relying on the assumption that there is at least one and that you have found it.
You do not test for path closure. You may find a closed path by chance, but you may also produce an unclosed path.
Using 2 loops to find the unused pairs is less efficient than using a temporary array used[sum].
The first pair is always the first, so you can simplify the find function a little.
Here is an improved version:
#include <stdio.h>
int find(char group[][2], int buffer, int sum, int path[], unsigned char used[]) {
int i;
char last = group[path[buffer-1]][1];
if (buffer == sum)
return last == group[0][0];
for (i = 1; i < sum; i++) {
if (!used[i] && last == group[i][0]) {
path[buffer] = i;
used[i] = 1;
if (find(group, buffer + 1, sum, path, used))
return 1;
used[i] = 0;
}
}
return 0;
}
int main() {
FILE *input = fopen("input.txt", "r");
if (input != NULL) {
int sum = 0, i;
fscanf(input, "%d", &sum);
char group[sum][2];
int path[sum];
unsigned char used[sum];
for (i = 0; i < sum; i++)
fscanf(input, " %c %c", &group[i][0], &group[i][1]);
path[0] = 0; // always start at first element
used[0] = 1;
for (i = 1; i < sum; i++)
used[i] = 0;
if (find(group, 1, sum, path, used)) {
FILE *output = fopen("output.txt", "a");
for (i = 0; i < sum; i++)
fprintf(output, "%c %c\n", group[path[i]][0], group[path[i]][1]);
}
} else {
printf("Input file was not found.");
}
return 0;
}
EDIT: I tested this new version with your large input file: it crashes on my laptop. The previous version with the permutation functions works like a charm, producing the complete path in 0.060 seconds. So there is a complete path and something is wrong with this find function.
There are few differences between the algorithms:
permutation uses less stack space: a single automatic array of size n*2 (200k) versus 3 automatic arrays total size n*(sizeof(int) + 3) (700k).
permutation uses fewer variables, so recursion uses less stack space, but both probably use more than 1 MB of stack space to recurse 100000 times.
find does more scans, where permutation swaps group pairs and always snaps the next one directly.
I reimplemented find without recursion and finally got it to produce a complete path. It is a different one and it takes much longer to compute, 3.5 seconds.
For larger input files, you definitely should not use recursion and you should even allocate the arrays from the heap with malloc.
Here is the non recursive code, using heap memory:
#include <stdio.h>
#include <stdlib.h>
int find(const char group[][2], int sum, int path[]) {
path[0] = 0;
if (sum <= 1)
return group[0][1] == group[0][0];
unsigned char *used = calloc((size_t)sum, sizeof(*used));
for (int buffer = 1, i = 1;; i++) {
if (i == sum) {
--buffer;
if (buffer == 0) {
free(used);
return 0;
}
i = path[buffer];
used[i] = 0;
} else
if (!used[i] && group[path[buffer-1]][1] == group[i][0]) {
path[buffer] = i;
if (buffer == sum - 1) {
if (group[i][1] == group[0][0]) {
free(used);
return 1;
}
} else {
buffer++;
used[i] = 1;
i = 0;
}
}
}
}
int main() {
FILE *input = fopen("input.txt", "r");
if (input != NULL) {
int sum = 0, i;
fscanf(input, "%d", &sum);
char (*group)[2] = calloc((size_t)sum, sizeof(*group));
int *path = calloc((size_t)sum, sizeof(*path));
for (i = 0; i < sum; i++)
fscanf(input, " %c %c", &group[i][0], &group[i][1]);
if (find(group, sum, path)) {
FILE *output = fopen("output.txt", "a");
for (i = 0; i < sum; i++)
fprintf(output, "%c %c\n", group[path[i]][0], group[path[i]][1]);
}
} else {
printf("Input file was not found.");
}
return 0;
}

Related

Why does the last string not properly enter a multidemsional array which shows character frequency?

I have been trying to find a solution for a long time but it seems like i cant.
I was trying to make a program that reads sentences from a file, puts the sentences as strings it into multidimensional array and quicksorts the array sentences alphabetically. Then it puts that array into an another array which shows the frequency of letters in a column position which shows the letter and frequency.
For example sentence 7 "CUD" would be row 7 and have a 1,1 and 1 in columns 3(c) 4(d) and 21(U). This works perfectly except for the last sentence which for some reason doesn't enter at all and shows random numbers.
void isAnAnagram(char anagramTester[][MAX_CHAR]) {
int countLetters[MAX_LINES][26] = {0};
int x;
for (int i =1; i <=MAX_LINES; i++) {
for (int j = 0; (anagramTester[i][j] != '\0'); j++) {
if (anagramTester[i][j] >= 'a' && anagramTester[i][j] <= 'z') {
x = anagramTester[i][j] - 'a' +1;
countLetters[i][x]++;
} else if (anagramTester[i][j] >= 'A' && anagramTester[i][j] <= 'Z') {
x = anagramTester[i][j] - 'A' +1;
countLetters[i][x]++;
}
}
}
for(int i=1;i<=MAX_LINES;i++){ //Rows
printf("row:%d ", i);
for(int j=1;j<=26;j++){ //Cols
printf("%d ",countLetters[i][j]);
}
printf("\n");
}}
This is the function which accepts a 2 dimensional array with strings in it
I have tried changing the loops but fundamentally I don't know why this error is only occurring in the last sentence.
here is the file input and output function
void readSentences(char inputSentences[][MAX_CHAR]){
int lineNum = 0;
FILE *fp = fopen("YOurDETAILS/input.txt", "r+");
fseek(fp, 0, SEEK_SET);
if(fp== NULL ){
/* check does weather file exist etc*/
perror("Error opening file");
lineNum = -1;
/* use this as a file not found code */
}
else {
// fgets returns NULL when it gets to the end of the file
for(lineNum = 1; lineNum <= MAX_LINES; lineNum++){
if(fgets(inputSentences[lineNum], MAX_CHAR, fp) != NULL){
inputSentences[lineNum][MAX_CHAR] = '\0';
}
else {
inputSentences[lineNum][MAX_CHAR] = '\0';
fclose(fp);
}
inputSentences[MAX_LINES][MAX_CHAR] = '\0';
}
}
}
void writeAnswer(char output[][MAX_CHAR]){
FILE *fp = fopen("YOurDETAILS/output.txt", "w");
fprintf(fp,"Sorted Array:\n");
for (int i =1; i <= MAX_LINES; i++) {
fprintf(fp,"sentence %d:%s \n ", i, output[i]);
}
fclose(fp);
}
the contents of the input.txt file are
cat
O, Draconian devil! Oh, lame saint!
tac
Tom Marvolo Riddle
Software engineering
Leonardo da Vinci! The Mona Lisa!
Computer science
CUD
Act
cuddle
Hey there!
Old Immortal dovers
I am Lord Voldemort
duck
the sorting file is
void swap(char sentencesToSwap[][MAX_CHAR], int i, int j){
for(int x = 0;x < MAX_CHAR; x++ ) {
char temp = sentencesToSwap[i][x];
sentencesToSwap[i][x] = sentencesToSwap[j][x];
sentencesToSwap[j][x] = temp;
}
}
void quicksort(char sentencesToSort[][MAX_CHAR], int first, int last){
if(first < last){
char pivotindex = partition(sentencesToSort, first, last);
quicksort(sentencesToSort, first, pivotindex-1);
quicksort(sentencesToSort, pivotindex+1, last);
}
}
int partition(char sentencesToSort[][MAX_CHAR], int first, int last){
swap(sentencesToSort, first, (first + last) / 2);
char *pivot;
pivot = sentencesToSort[first]; // remember pivot
int index1 = first + 1; // index of first unknown value
int index2 = last; // index of last unknown value
while (index1 <= index2) { // while some values still unknown
if (strcasecmp(sentencesToSort[index1],pivot) <= 0)
index1++;
else if (strcasecmp(sentencesToSort[index2],pivot) > 0)
index2--;
else {
swap(sentencesToSort, index1, index2);
index1++;
index2--;
}
}
swap(sentencesToSort, first, index2); // put the pivot value between the two
// sublists and return its index
return index2;
}
The main file is below
char sentences[MAX_LINES][MAX_CHAR];
readSentences(sentences);
isAnAnagram(sentences);
quicksort(sentences, 0, MAX_LINES );
writeAnswer(sentences);

Segmentation error due to allocation issues?

Hi so im preety new to coding and I have recently hit a brickwall
This program has a segmentation fault debug and I think it has to do with allocating space for the buffer array or the input file , as those kept popping up as solutions in my search for an answer.
If you know what I did wrong I would appreciate if you told me rather than giving me the solution. Also Im completely lost on how to allocate memory to anything , so it would be great if someone explained how to allocate memory in context to the code.
It is supposed to read a file structured like this
2
3 4
3 4
where 2 = how many files are downloading, 3 = the Kb/s of file( each line represents a file) , and 4 = time remaining until done. The program is supposed to output a file out that has the time needed for all the things to download(mind you when a file finishes the speed goes up to others)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *in = fopen("download.in", "r");
FILE *out = fopen("download.out", "w");
int i, n, j, a, k, o;
char buffer[100];
fgets(buffer, 10, in);
sscanf(buffer, "%d", &n);
int tn[n];
int xn[n];
i = 0;
while (i < n) {
fgets(buffer, 100, in);
sscanf(buffer, "%d %d", &tn[i], &xn[i]);
++i;
}
for (i = 0; i < n; ++i){
for (j = i + 1; j < n; ++j){
if (tn[i] > tn[j]){
a = tn[i];
tn[i] = tn[j];
tn[j] = a;
a = xn[i];
xn[i] = xn[j];
xn[j] = a;
}
}
}
i = 1;
float b ;
k = 0;
o = 1;
while(o < n){
if(xn[o] == xn[o - 1]){
k = tn[o] + tn[o - 1]
;
}
else{
b = (tn[o] * xn[o]) / (tn[o] + tn[o - 1] + k);
k = 0;
}
++o;
}
fprintf( out, "%f", b );
fclose(in); fclose(out);
return 0;
}
I know the answer it gives is not accurate but I want to fix the segmentation fault first then deal with that
gdb r then gdb bt returns this
(gdb) r
Program received signal SIGSEGV, Segmentation fault.
_IO_fgets (buf=0x7fffffffeb30 "", n=10, fp=0x7fffffffeac0) at iofgets.c:50
50 iofgets.c: No such file or directory.
(gdb) bt
#0 _IO_fgets (buf=0x7fffffffeb30 "", n=10, fp=0x7fffffffeac0) at iofgets.c:50
#1 0x0000000000400766 in main () at main.c:11
codeblocks says the code is ok and the site I am trying to give this says there is a segmentation fault aswell.
Here is code with segfault fixed. I had to (1) specify absolute path and (2) change the loop to a for loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *in = fopen("/home/developer/CLionProjects/untitled4/download.in", "r");
FILE *out = fopen("/home/developer/CLionProjects/untitled4/download.out", "w");
int i, n, j, a, k, o;
char buffer[100];
fgets(buffer, 10, in);
sscanf(buffer, "%d", &n);
int tn[n];
int xn[n];
for (i = 0; i < n; i++) {
if (!fgets(buffer, 100, in)) break;
if (sscanf(buffer, "%d %d", &tn[i], &xn[i]) < 2) break;
}
for (i = 0; i < n; ++i) {
for (j = i + 1; j < n; ++j) {
if (tn[i] > tn[j]) {
a = tn[i];
tn[i] = tn[j];
tn[j] = a;
a = xn[i];
xn[i] = xn[j];
xn[j] = a;
}
}
}
i = 1;
float b;
k = 0;
o = 1;
while (o < n) {
if (xn[o] == xn[o - 1]) {
k = tn[o] + tn[o - 1];
fprintf(out, "Some number: %d\n", k);
} else {
b = (tn[o] * xn[o]) / (tn[o] + tn[o - 1] + k);
k = 0;
fprintf(out, "Some number: %d\n", k);
}
++o;
}
fclose(in);
const char *text = "Write this to the file";
fprintf(out, "Some text: %s\n", text);
fclose(out);
int c;
FILE *file;
file = fopen("/home/developer/CLionProjects/untitled4/download.out", "r");
if (file) {
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
}
return 0;
}

how to search an element from a file in c

My code needs to do three things:
Read numbers from a file FILE1 into an array (dynamic)
Sort those numbers
Search for numbers input from a FILE2 in the sorted array.
.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main (int argc, char *argv[]) {
FILE *fp1 = fopen ("myFile1.txt", "r");
if (fp1 == NULL) {
printf ("cannot open this file");
exit (0);
}
FILE *fp2 = fopen ("test1.txt", "w");
if (fp2 == NULL) {
puts ("Not able to open this file");
exit (1);
}
int i = 0, num, j, k;
int *B = NULL;
int *C;
int a;
int size = 32;
B = malloc (sizeof (int) * size);
while (fscanf (fp1, "%d", &num) == 1) {
if (i < size) {
B[i] = num;
fprintf (fp2, "%d\r\n", num);
i++;
}
else {
C = malloc (sizeof (int) * 2 * size);
memcpy (C, B, size * sizeof (int));
free (B);
B = &C[0];
B[i] = num;
i++;
size = size * 2;
i++;
for (j = 0; j < size; ++j) {
for (k = j + 1; k < size; ++k) {
if (B[j] < B[k]) {
a = &B[j];
B[j] = B[k];
B[k] = a;
}
}
}
printf ("after sorting");
for (j = 0; j < size; ++j)
printf ("%d\n", B[j]);
}
}
return 0;
fclose (fp1); /* note this code is never reached */
fclose (fp2);
}
I successfully complete the first part of reading in the numbers from a file. But I am not able to understand how to sort these numbers.
I am trying to apply bubble sort, but it puts 0s in my array. How is my implementation incorrect?
& is the address-of operator. You pass it as a pointer. You need a = B[i], since a is an int.
Now you sort the numbers descending, if you want them to be ascending change the < to > in if (B[j] < B[k]).
Also you must always check whether malloc succeeded or not with e.g.:
if (!B) {
fprintf(stderr,"B alloc error");
exit(-1);
}
Also you might want to consider realloc.
In addition there is a built-in qsort in stdlib.h, which gives much better time than O(n^2).
Note: I haven't tested your file operations, since you said they work properly.

Seg. fault read line-by-line

I am trying to calculate the mode or the integer that appears the most for each line.
I get an print two values and then segmentation fault.
for (i = 0; i < count; i++) {
if (array[i]) {
int i, j, k, cnt = 1, p, big;
int b[MAX_NUM] = {0};
printf("count:%d\n", count);
for (i = 1; i <= array[i]; i++) {
for (j = i + 1; j <= array[i]; j++) {
if (array[i] == array[j])
printf("cnt:%d\n", cnt);
cnt++;
}
printf("cnt2:%d\n", cnt);
b[k] = cnt;
k++;
cnt = 1;
}
big = b[k];
p = 1;
for (i = 2; i <= array[i]; i++) {
if (big < b[i]) {
big = b[i];
p = i;
}
}
printf("The element that occurs offen is %d\n", array[p]);
printf("And it has occurred %d times\n", b[p]);
}
}
}
}
}
return 0;
}
EDIT:
See the look here in my code. The values that are printed are the numbers on each line of the file followed by a blank line like this:
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
Integers: 9
.....
You redefine i and p in an inner scope where they shadow current definitions. This is obviously unintentional as the for expression looks quite wrong:
if (array[i]) {
int i, j, k=1, cnt = 1, p, big;
// ^
// Redefinition of i.
// You should use a different name for the loop index below
// Same remark for p, it is safer to not redefine local variables
// in inner scopes. Any { starting a block creates a new scope
// in which variables can be defined, or in this case redefined.
...
for (i = 1; i <= array[i]; i++) {
...
for (i = 2; i <= array[i]; i++) {
...
In the same area of the code, you use k without a prior initialization.
The code to compute maximum occurrences can be put into a separate function and simplified this way:
#include <stdio.h>
// get the number of ocurrences of val in array a of size n
int get_number_of_occurrences(int a[], int n, int val) {
int cnt = 0, i;
for (i = 0; i < n; i++) {
if (a[i] == val)
cnt++;
}
return cnt;
}
// return the index for the number that occurs the most
int get_max_occurrence_index(int a[], int n) {
int p = 0, cnt, max = 0, i;
for (i = 0; i < n; i++) {
cnt = get_number_of_occurrences(a, n, a[i]);
if (max < cnt) {
max = cnt;
p = i;
}
}
return p;
}
int main() {
int i, n, a[20], max;
printf("Enter the maximum number of elements\n");
scanf("%d", &n);
printf("Enter the elements\n");
for (i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
i = get_max_occurrence_index(a, n);
max = get_number_of_occurrences(a, n, a[i]);
printf("The element that occurs most oftenly is %d\n", a[i]);
printf("And it has occurred %d times\n", max);
return 0;
}
If you want to use this logic in your original program, you should use it for each line as you read the file instead of at the end where it only applies to the last line. The line parsing code is incorrect too: you take the first digit's ASCII value as the value instead of parsing it with strtol().
Here is a corrected version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define MAX_NUM 1000
#define MAX_LINE_LEN 2048
#define N 100
void fatal(const char *msg) {
printf("%s\n", msg);
exit(1);
}
int main(int argc, char *argv[]) {
FILE *fp;
char filename[100];
char line[MAX_LINE_LEN];
char *p;
int array[MAX_NUM];
int index, count, max;
printf("Please enter the file name: \n");
if (scanf("%99s", filename) != 1) {
fatal("Error in entering file.");
}
if ((fp = fopen(filename, "r")) == NULL) {
fatal("Unable to open the file.");
}
while ((p = fgets(line, MAX_LINE_LEN, fp)) != NULL) {
/* skip white space */
p += strspn(p, " \t\n");
if (*p == '#' || *p == '\0') {
/* ignore comment and blank lines */
continue;
}
/* scan and convert the numbers */
for (count = 0; *p != '\0'; ) {
if (isdigit((unsigned char)*p)) {
array[count++] = strtol(p, &p, 10);
printf("%d\n", array[count]);
} else {
/* skip to next space or end of string */
p += strcspn(p, " \t\n");
}
/* skip white space after the number */
p += strspn(p, " \t\n");
}
index = get_max_occurrence_index(array, count);
max = get_number_of_occurrences(array, count, array[index]);
printf("The element that occurs most often is %d\n", array[index]);
printf("And it has occurred %d times\n", max);
}
fclose(fp);
return 0;
}
Maybe i just can not see through your code, but at no point do i see you loading the actual numbers from your file into any variable or array to work with.
You are loading a line with while ((p = fgets(line, MAX_LINE_LEN, fp)) != NULL) {
Inside that loop, you are breaking this line into tokens to count how many numbers you have.
As far as i can see, array[count]++; is used to count how many numbers are in each line. Using the index as the line number.
You should start by thinking about how to get your data into a usable format
You can start trying to load the values into a 2 dimensional array.
Using the first dimension for the line number and the second for the values.
If you don't understand your code well enough, you should start with more comments
What do you use your difines and variables for.
#define MAX_NUM 1000 //maximum number of lines
int array[MAX_NUM] = {0}; //index refers to line number of file. used to count numbers in each line.
// read file line by line, split every line into tokens to count amount of numbers
while ((p = fgets(line, MAX_LINE_LEN, fp)) != NULL) {
if (count >= MAX_NUM) {
fatal("Array error");
}
if (line[0] != '#') {
p = strtok(line, " ");
while (p != NULL) {
if (isdigit(*p)) {
array[count]++;
}
p = strtok(NULL, " ");
}
}
count++;
//printf("COUNT:%D\n", count);
}
Choosing good variable names in addition would be even better
#define MAX_NUM 1000 -> #define MAX_LINE_NUM 1000
I have no idea about what your variables int i, j, k, cnt = 1, p, big; do.
Give them better names and or comment them. Will not only help you, but your helpers that need to understand what you intend to do with them.
First i thought you needed help with the algorithm for the mode so i wrote this first:
Using very basic stuff to keep it as simple as possible.
Would be cleaner to put it into functions if you know how.
Did not use functions since it seems you do not know completely how to work with them (you should look into that)
This algorithm is doing the following:
Take the first number in the array
Run through the array and everytime you find that number, you increase a counter
Save the number and the count as highest and highestCnt
Repeat with every number in the array and overwrite highest and highestCnt whenever count > highestCnt
When there are multiple number with the highest occurrence it will only remember the number that was counted first. If you want to return all numbers with the highest occurrence, the coude would need to be changed.
Could do something like checking if count == highestCnt and then set something so you know there is no single number with the highest count until you find one with an even higher count.
#include<stdio.h>
#define sizea 100
int main(void) {
int array[sizea] = { 1,3,6,8,3,6,7,4,6,9,0,3,5,12,65,3,76,5,3,54,
1,3,6,89,3,6,7,4,6,9,0,4,5,12,65,3,76,5,3,54,
1,9,6,8,3,45,7,4,6,9,0,89,5,12,65,3,76,5,3,54,
6,3,6,8,3,6,7,4,6,9,0,23,5,12,65,3,76,5,3,54,
1,3,6,90,3,6,7,4,6,9,0,5,5,12,65,3,76,5,3,54 };
int number;
int count = 1;
int highest = 1;
int highestCnt = 1;
int end = sizea - 1; //end defines at what element in the array the loop will end
int j; //j is used to load a number that will be count
int i; //i is used run through the array and compare every number the the one that is being count
for (j = 0; j <= end; j++) {
number = array[j]; // load a number to count
count = 1; // start counting at 1
for (i = j+1; i <= end; i++) {
// if we find the same number again, we increase the counter
// then we load the last element into the current array position
// then we change decrement "end" by 1
// this is like throwing out all the numbers we allready count
// using while instead of if so it will check the last element that was moved to current position as well
// check for i <= end so it doesnt count twice when the last element equals our number
while (array[i] == number && i <= end) {
count++;
array[i] = array[end];
end--;
}
}
// if the count of the number is highers the the previus highest, it's obviously our new highest count.
if (count > highestCnt) {
highest = number;
highestCnt = count;
}
}
printf("number: %i, count: %i", highest, highestCnt);
}

Populate a Matrix based on user input and a pattern in C

I have a program to develop but I'm having some difficulties in one part.
I have to read a number of tests (t) that will be made. After that I must read a number (n) of columns and rows to make a square matrix² (nxn). After instance of the matrix, the program must populate it from the input of the user. The user will type ., b or w. Based in this pattern I have to populate the matrix. Each line that the user will type must contain n characters (., b or w) and he will type n times. This will fill the matrix (n characters by n lines). Can you guys give me a hand?
This is the code I have:
int main(void)
{
//vars
int n = 0, t = 1, x = -1, y = -1, teste = 1;
int i,j;
//Start
scanf(" %d %*c",&t);//scans t
while (t-- > 0) {
scanf(" %d", &n);//scans n
if(n>0 && n < 100){
int table[n][n];//the matrix n x n
for (i = 0; (i < n);++i) {//iterator to lines
char l[n];
scanf ("%s", l); //scans a line
for (j = 0; j < n; ++j) {//iterator to colums
//these ifs are to identfy the input
if (l[j] == 'b'){
table[i][j]=1;
}else if(l[j] == 'w'){
table[i][j]=2;
x=j;y=i;
}else{
table[i][j]=0;
}
}
}
}
return 0;
}
I made the exactly same thing in Java and it worked. Where am I failing?
Your variable l doesn't allow enough space to store the null at the end of the string. You are therefore overflowing into some other variable, and that may be affecting all sorts of things.
You should probably read the line into a far larger string, and make sure it is the correct length. You should also error check each read operation; you should also report invalid characters in the input.
This code works for me. Note the way it echoes data so it is possible to see what's going wrong. Error reporting should really be to standard error; I've been lazy.
#include <stdio.h>
#include <string.h>
static void dump_board(FILE *fp, const char *tag, int n, int table[n][n])
{
fprintf(fp, "%s: (%d x %d)\n", tag, n, n);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (table[i][j] == 0)
putc('=', fp);
else if (table[i][j] == 1)
putc('B', fp);
else if (table[i][j] == 2)
putc('W', fp);
else
putc('?', fp);
}
putc('\n', fp);
}
}
int main(void)
{
int n = 0, t = 1, x = -1, y = -1;
if (scanf(" %d %*c", &t) != 1)
{
printf("Failed to read t\n");
return 1;
}
printf("%d data sets\n", t);
while (t-- > 0)
{
if (scanf(" %d", &n) != 1)
{
printf("Failed to read n\n");
return 1;
}
printf("Size of data set: %d x %d\n", n, n);
int c;
while ((c = getchar()) != EOF && c != '\n')
;
if (n > 0 && n < 100)
{
int table[n][n];
for (int i = 0; i < n; i++)
{
char line[4096];
if (fgets(line, sizeof(line), stdin) == 0)
break;
int len = strlen(line);
if (line[len-1] != '\n')
{
printf("Format error: line too long (%d bytes)\n", len);
return 1;
}
line[--len] = '\0';
if (len != n)
{
printf("Format error: line <<%s>> is not length %d\n", line, n);
return 1;
}
for (int j = 0; j < n; ++j)
{
if (line[j] == 'b')
table[i][j] = 1;
else if (line[j] == 'w')
{
table[i][j] = 2;
x = j;
y = i;
}
else if (line[j] == '.')
table[i][j] = 0;
else
{
printf("Format error: invalid character %c\n", line[j]);
return 1;
}
}
}
dump_board(stdout, "Input", n, table);
printf("Last white piece at (%d,%d)\n", x, y);
}
}
return 0;
}
Input
2x
4
b..w
.bw.
.b.b
w.w.
8
b.w.b.w.
.w.b.w.b
bbwwbbww
b......w
ww....bb
bwb..wbw
bbbbwwww
........
Output
2 data sets
Size of data set: 4 x 4
Input: (4 x 4)
B==W
=BW=
=B=B
W=W=
Last white piece at (2,3)
Size of data set: 8 x 8
Input: (8 x 8)
B=W=B=W=
=W=B=W=B
BBWWBBWW
B======W
WW====BB
BWB==WBW
BBBBWWWW
========
Last white piece at (7,6)

Resources