I am writing a program that will ask the user for a 'n' value, they will then enter 'n' values that will be stored into an array and sorted. I have this part done easy enough.
I will compare this array with input from a number read from a text file. If the number is bigger than any of the current array values it will replace them and slide the rest down. This creates an array of the largest 'n' values
Example: n = 4 n values are : 999 972 954 462 937
a[4] = {999, 972, 954, 462, 937};
Sorted :
a[4] = {999, 972, 954, 937, 462};
if the file input is say 968 the result is.
Resorted :
a[4] = {999, 972, 968, 937, 937};
This is my current code.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
if (argc<3) //error checking
return -1;
int size = atoi(argv[2]);
int a[size];
int i, j, temp=0;
printf("Enter %d numbers\n", size); //user array input for size and n values
for(i = 0; i < size; i++)
scanf("%d", &a[i]);
for(i=0; i < size; i++){ //sorting array
for(j = i+1; j <size; j++){
if( a[i] < a[j]){
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
FILE *input;
input = fopen(argv[1], "r");
if(input ==NULL) //error checking
return -1;
if(fscanf(input, "%d", &temp) != 1)
return -1;
while(fscanf(input, "%d", &temp) ==1){ //loop while there is file input
for(i =1 < size; i++){ //check if temp is larger than array values
if(temp > a[i] && temp < a[i-1]){
for(j = size-1; j >= i; j--) //slide down the rest of the array
a[j] = a[j-1];
a[i] = temp;
}
}
}
for(i=0; i <size; i++){ //print out array
printf("%d ", a[i]);
}
return (0);
}
I have tried this on a smaller simpler skill were I have already created the array and the values instead of using user input. I also just passed the array check sequence through a loop that increases a number value instead of reading from a file. This seemed to work fine with something like
a[5] = {10, 8, 6, 4, 2};
number = 5; // number++ number = 6 number = 7... until 10
result: a[5] = {10, 9, 8, 7, 6};
I am sad to say that even if the program was not printing the right array at the beginning I could see there were numbers from the file. The loop is still going trough the file, but at one point the output just started being the sorted user array. I can't seem to get the array values right. Any ideas?
Continuing from my comments yesterday, I apologize if the errors were due to the retyping of your code, but that is the whole reason you want to try to cut and paste as Jonathan indicated -- eliminate human error in the transcription process.
I think I understand what your primary problem is. If your goal is to read some number of user input values from stdin, sort them in descending order, and then open a file and read a single additional value into the array in sort-order, then you must provide space for the final value in your array at the time it is declared (if using VLA's). Otherwise, you either need to create a second VLA large enough to store the values from the use and the file, and copy the user provided values to the new array or dynamically allocate the array originally (with malloc or calloc) and then realloc as needed to add space for additional values as required.
In this case, it's not that difficult since you know you are reading one value from the file. Just read the size from the command line argument and then create your array as int a[size + 1];
The rest of your task can be handled in a couple of ways. After you read (and validate) the user input, you can sort your values in descending order, read the value from the file, and create an insert & shuffle routine to insert the value in the correct order and move the remaining array elements down, or (probably a less error prone method) is simply to add the element from the file to the end of the array, and call your sort routine again.
(note: you should get used to using qsort rather than attempting to reinvent the bubble-sort, etc.. It is orders of magnitudes more efficient and much less error prone)
You need limit (or eliminate) your use of atoi as it provides zero error checking. A better approach is to use strtol and then check errno and check the end-pointer against the original to determine if there were any digits read. Below a simple helper function incorporates error-checking for strtol to insure you have an actual value for size.
Further, be careful. While you may expect the user will enter size integer values, there is no guarantee they will. It is better to track the number of values actually entered and use that value in subsequent iterations over the array rather than blindly iterating for (i = 0; i < size; i++) throughout the remainder of your code.
Whether you attempt an insert-in-place of the value read from the file, or just add it to the end of the array and call your sort routine again is up to you. I would encourage you to move your sort code into a function to provide that flexibility without having to duplicate the code in main. Look the following over and let me know if you have any questions. Since I presume this was a homework assignment, the insert-in-place case is shown below (but the simple add the file value to the end and call sort again code is included commented out)
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <limits.h> /* for LONG_MAX/MIN */
#include <errno.h> /* for ERANGE,errno */
void sort_int_array_dec (int *a, size_t size);
long xstrtol (char *p, char **ep, int base);
int main (int argc, char **argv) {
/* read size as first argument, or 5 if none given */
int size = argc > 2 ? (int)xstrtol (argv[2], NULL, 10) : 5,
a[size + 1], /* variable length array for user + file values */
n = 0, /* number of values from user */
fval, /* value read from file */
temp, /* temporary value for array */
i = 0;
FILE *fp = NULL;
if (size < 1) return 1;
printf ("enter %d integers\n", size);
while (n < size) { /* read up to size values */
int result, c;
printf (" integer[%2d] : ", n + 1);
/* validate read of each value using scanf return */
if ((result = scanf ("%d", &temp)) != 1) {
if (result == EOF) { /* always check for EOF */
fprintf (stderr, "user canceled input.\n");
break;
}
fprintf (stderr, "error: invalid conversion.\n");
/* empty input buffer of invalid entry */
while ((c = getchar()) != '\n' && c != EOF) {}
}
else /* good value read, save, increment n */
a[n++] = temp;
}
sort_int_array_dec (a, n); /* sort a */
printf ("\nsorted array before inserting value from file:\n\n");
for (int i = 0; i < n; i++)
printf ("a[%2d]: %d\n", i, a[i]);
if (!(fp = fopen (argv[1], "r"))) {
fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
return 1;
}
if (fscanf (fp, "%d", &fval) != 1) { /* read value from file */
fprintf (stderr, "error: read of file value failed.\n");
return 1;
}
printf ("\n value from file: %d\n\n", fval);
/* add fval into array in descending sort order
* (you can add it anywhere and simply call sort again, e.g.)
*/
// a[n] = fval; /* add it to the end of the array */
// sort_int_array_dec (a, n + 1); /* sort a again */
for (i = 1; i < n + 1; i++) {
if (fval > a[i-1]) {
temp = a[i-1];
a[i-1] = fval;
break; /* temp now holds value to insert at i */
}
}
if (i == n + 1) /* if already at last element just set it */
a[n] = fval;
else /* otherwise, insert and shuffle remaining elements down */
for (int j = i; j < n + 1; j++) {
int mov = a[j];
a[j] = temp;
temp = mov;
}
printf ("sorted array after inserting value from file:\n\n");
for (int i = 0; i < n + 1; i++)
printf (" a[%2d]: %d\n", i, a[i]);
return 0;
}
/** sort integer array descending (your code) */
void sort_int_array_dec (int *a, size_t size)
{
size_t i, j;
int temp;
if (size < 2) return; /* nothing to sort */
for (i = 0; i < size; i++) {
for (j = i + 1; j < size; j++) {
if (a[i] < a[j]) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
/** a simple strtol implementation with error checking.
* any failed conversion will cause program exit. Adjust
* response to failed conversion as required.
*/
long xstrtol (char *p, char **ep, int base)
{
errno = 0;
char *endpt = ep ? *ep : NULL;
long tmp = strtol (p, &endpt, base);
/* Check for various possible errors */
if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
(errno != 0 && tmp == 0)) {
perror ("strtol");
exit (EXIT_FAILURE);
}
if (endpt == p) {
fprintf (stderr, "No digits were found\n");
exit (EXIT_FAILURE);
}
if (ep) *ep = endpt;
return tmp;
}
Example Use/Output
$ cat dat/file.txt
523
$ ./bin/addintoarray dat/file.txt 4
enter 4 integers
integer[ 1] : 400
integer[ 2] : 500
integer[ 3] : 600
integer[ 4] : 700
sorted array before inserting value from file:
a[ 0]: 700
a[ 1]: 600
a[ 2]: 500
a[ 3]: 400
value from file: 523
sorted array after inserting value from file:
a[ 0]: 700
a[ 1]: 600
a[ 2]: 523
a[ 3]: 500
a[ 4]: 400
/*I'm a beginner C programmer so I don't know much of the syntax.
But I think I can help you with that problem.
I created a simple code and I hope I can really help
the integers from the file must be already sorted.
So the only integer that we will sort is the recent integer that the user inputed.
*/
/*So here's my code of sorting array of integers coming from file.
Please give it a try.
It's not the same syntax as your code but I know you can see my point*/
#include <stdio.h>
#include <stdlib.h>
//my style here is I'm declaring the max Num that I want to put in array.
//But you can do this with different style.
#define MAX_ARRAY 10
//I created separate functions
void readFile(int num_arr[]);
void sortArray(int num_arr[]);
void writeFile(int num_arr[]);
int main()
{
int num_arr[MAX_ARRAY + 1]; // take note that I added 1 (one). And you will see later why I did that
readFile(num_arr);
sortArray(num_arr);
writeFile(num_arr);
//Now we can sort them. Use a temp_num holder.
return 0;
}
void readFile(int num_arr[])
{
int x = 0;
int y = 0;
int temp_num;
FILE *sample_file_pointer = fopen("sample_file.txt", "r");
//first I read the integers from the file and put them in int array.
while(fscanf(sample_file_pointer, " %d\n", &num_arr[x]) == 1)
{
x++;
}//after reading the integers, the last element of the array we declared is still unused.. Now we will use it.
fclose(sample_file_pointer);
//now we will use the unused element by entering the 'n'. Then we will sort the array later.
printf("Enter value of n: ");
scanf(" %d", &num_arr[MAX_ARRAY]);//We put the n value in the last element of the array
}
void sortArray(int num_arr[])
{
int x = MAX_ARRAY;//We will use this to point the last element of the array.
int temp_num;
/*because the array from
the file is already
sorted, (I know you can
do the sorting of that.
That's why I didn't include
it here to make this short)
we can just test the most recent
integer that is added by the user*/
//We do that with this loop
for(int i = MAX_ARRAY; i > 0; i--)
{
if(num_arr[x] >= num_arr[i - 1])
{
temp_num = num_arr[x];
num_arr[x] = num_arr[i - 1];
num_arr[i - 1] = temp_num;
//now set the x to the swapped element to follow the recent number all through. Till the element test becomes 1.
x = i - 1;
}
}
//now we're ready to write this sorted array to a file again
}
void writeFile(int num_arr[])
{
FILE *sample_file_pointer = fopen("sample_file.txt", "w");
for(int i = 0; i < MAX_ARRAY; i++)
{
fprintf(sample_file_pointer, "%d\n", num_arr[i]);
}
//We can ignore the last element of the array. She's out of the group now. It's her fault for being the lowest.. LOL..
fclose(sample_file_pointer);
}
Related
Am I freeing memory correctly in this program with just free(lineArr) at the end of main()?
I still can't figure out what's causing the issue with all the chars in my output (image attached). I know it's probably something basic with how I have the for loops set up.. things print correctly the first run after compiling, but not the second run. Why would this be?
Thanks
// When the sum of proper divisors for a number is the same as the number
// itself, the "status" of that sum may be considered "perfect"; when less,
// "deficient", and when greater than, "abundant".
//
// This program takes two extra command-line arguments after the executable
// name: an integer and a character. The integer will be the number of
// numbers past 2 to print statuses and histogram bars for; the character
// will be used to construct a histogram bar with height = to the sum of
// divisors for a particular number. Example arguments: ./a.out 6 '*'
// Example output:
// 2 is Deficient *
// 3 is Deficient *
// 4 is Deficient ***
// 5 is Deficient *
// 6 is Perfect ******
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int sumOfDivisiors(int aNum); //prototype for sumOfDivisiors function
typedef struct{ //define a structure called "line" with three members
int lineNum;
int sum;
char status[10];
}line;
int main(int argc, char *argv[]){ //main will accept command line arguments
int howMany;
char usrChar;
line whichLine;
if(argc < 3){
printf("Error: must enter 3 command line arguments.\n");
exit(1);
}
sscanf(argv[1],"%d", &howMany);
sscanf(argv[2], "%c", &usrChar);
line** lineArr = malloc(howMany * sizeof(line*)); //allocate mem for array of struct ptrs
if (lineArr == NULL){
printf("Error: trouble allocating memory. Exiting.\n");
exit(1);
}
for (int n = 2; n <= howMany; n++){ //loop to call func + initialize lineNum, sum, status for current line
int sumResult = sumOfDivisiors(n);
lineArr[n] = malloc(sizeof(line)); //allocate mem for pointer to current line struct
if (lineArr[n] == NULL){
printf("Error: trouble allocating memory. Exiting.\n");
exit(1);
}
line* temp = lineArr[n];
temp->lineNum = n;
temp->sum = sumResult;
if (temp->sum == n){
strcpy(temp->status, "Perfect");
} else if (temp->sum < n){
strcpy(temp->status, "Deficient");
} else {
strcpy(temp->status, "Abundant");
}
}
for (int i = 2; i <= howMany; i++){ //loop to print formatted results
printf("%3d %-10s ", i, lineArr[i]->status);
for (int j = 0; j < lineArr[i]->sum; j++){
printf("%c", usrChar);
}
printf("\n");
}
free(lineArr); //free dynamically allocated memory
return 0;
}
//Definition for sumOfDivisiors function. This function accepts an int number
//as an argument. It takes that number, finds all proper divisors (divisors
//less than the number itself), then returns the integer result of adding
//up all these divisors.
int sumOfDivisiors(int aNum){
int result = 0;
int i;
for (i = 2; i <= sqrt(aNum); i++){
if (aNum % i == 0){
if (i == (aNum/i)){
result += i;
} else {
result += (i + aNum/i);
}
}
}
return(result + 1);
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
i was trying this kick start question, the test give the right answer yet when submitting attempt it says wrong answer, it's second question i'm doing and not sure how this really works here's my code :
function :
int num_subarray (int array[], int array_size, int k) {
int sum = 0, j = 1, i;
for (i = array_size - 1; 0 <= i; i--) {
if (array[i] == j) j++;
else j = 1;
if (j == k) {
sum++;
j = 1;
}
}
return sum;
}
here's the main :
int main () {
int t, n, k, array[N], i, j = 1;
scanf ("%d", &t);
do {
scanf ("%d%d", &n, &k);
i = 0;
do {
scanf ("%d", &array[i]);
i++;
} while (i < n);
printf ("\n Case #%d: %d", j, num_subarray (array, n, k));
j++;
} while (j <= t);
return 0;
}
here's the question :
Countdown - Kick Start
Continuing from my comments, at least from my reading of the question, a k-countdown actually starts with 'k' and counts down to 1, so in the example a 3-countdown is 3, 2, 1 a 6-countdown is 6, 5, 4, 3, 2, 1, etc...
You are also given limits on the array size of 2x10^5 (200000). The consideration there is that on some compilers 200000 4-byte int values will exceed the default stack size, so you may as well make array a global or static to avoid that issue altogether.
Another check you will want to impose is on the read of the values from the file. You will have k at that point and for there to be a k-countdown, the input must contain k and it must be at an index of i < n - k in order for there to be enough elements left in that array to hold a k-countdown. so if you are given k = 10 in a 10-element input, if the 1st element isn't 10 -- that array can't hold a k-countdown (that implementation is left to you -- but if you are failing a large check -- I would suspect that as one of the probable causes)
Putting that together and using the function name kcountdowns instead of your num_subarray and using kcd as your sum, a quick attempt could look like:
#include <stdio.h>
#define NMAX 200000
int arr[NMAX]; /* global storage for array, up to 2x10^5 elements */
/** function to compute no. of kcountdowns in n elements of arr */
int kcountdowns (int n, int k)
{
int i = 0, /* array index */
in = 0, /* flag & counter in(true)/out(false) of a kcountdown */
kcd = 0; /* number of kcountdowns found */
do { /* loop over all elements */
if (in) { /* if in a kcountdown */
if (arr[i] + 1 == arr[i-1]) { /* check current is 1 less than last */
in++; /* increment in flag/count */
if (in == k) { /* full sequence found */
kcd += 1; /* add a kcountdown to sum */
in = 0; /* reset in 0/false */
}
}
else /* otherwise set flag false */
in = 0;
}
if (arr[i] == k) /* if k found, set in to 1-true */
in = 1;
} while (++i < n);
return kcd; /* return number of kcountdows found */
}
(note: the use of the global arr. Generally the use of global variables is discouraged, but here with the potential stack size issue, using a global or making the array static are two reasonable options)
A quick main() that leaves the input check to you to implement could be:
int main (void) {
int t;
if (scanf ("%d", &t) != 1 || t < 1 || 100 < t) /* read/validate t */
return 1;
for (int i = 0; i < t; i++) { /* loop over each case */
int n, k;
if (scanf ("%d %d", &n, &k) != 2 || n < 2 || n < k) /* read/validate n & k */
return 1;
for (int j = 0; j < n; j++) /* loop reading/validating elements */
if (scanf ("%d", &arr[j]) != 1)
return 1;
printf ("Case #%d: %d\n", i + 1, kcountdowns (n, k)); /* output result */
}
(note: you would normally want to read each line into a buffer so you can enforce a validation of only reading a single line of input for the array values. Reading with scanf -- it will happily ignore a '\n' and start reading the next testcase if there is a defect in the input file)
At least with the input given, the results match all testcases, e.g.
Example Test Input
3
12 3
1 2 3 7 9 3 2 1 8 3 2 1
4 2
101 100 99 98
9 6
100 7 6 5 4 3 2 1 100
Example Use/Output
$ ./bin/kcountdown <dat/kcountdown.txt
Case #1: 2
Case #2: 0
Case #3: 1
error check:
$ echo $?
0
Let me know if you have further questions.
My code:
#include <stdio.h>
int main()
{
int count = 0;
int size = 0;
float num[size];
int i = 0;
float avg = 0;
float sum = 0;
while (scanf("%f",&num) != EOF)
{
if ((num[i] != num[i+1]) && (num[i] != num[i-1]))
{
sum = sum + num[i];
size++;
}
}
avg = sum/size;
printf("%0.2f", avg);
}
My input and output:
//input
2
2
1
^Z
//output
1.67
Correct input and output:
2 2 1
^Z
1.50
My question:
1) How can I make my code prompt input of numbers all on one line separated with spaces in between each input? Right now, my code always starts a new line after entering a number.
2) How can I fix my code so that it only calculates the average of non-repeated numbers? (NOTE: my code has to run no slower than O(nlogn). ) So I can't use nested loops as it will then have a run time of O(n^2).
You have some problems in your code:
the usage of num
test on scanf
the test of already used number.
the usage of num
When you write
int size = 0;
float num[size];
You do not allocate memory to store numbers.
and
while (scanf("%f",&num) != EOF)
Is not correct since you are not storing the value read into a float: gcc warns:
warning: format ‘%f’ expects argument of type ‘float *’, but argument 2 has type ‘float (*)[(sizetype)(size)]’ [-Wformat=]
A more correct way to do would be to write:
float num;
...
while (scanf("%f",&num) != EOF)
test on scanf
You test that scanf does not return EOF, but what if your conversion failed if you do not give a number?
The correct way to test what the user gives, is to check that you have the number of conversion wanted:
while (scanf("%f",&num) == 1)
the test of already used number.
Writting
if ((num[i] != num[i+1]) && (num[i] != num[i-1]))
You test last number (i) against past and future number (?!)
You have a simplier approch: have an array to store the already got number. This imply to have a function to test a number has already been got.
Warning The current implementation of is_number_in_array it very naive and make your program run in O(n). You can easyly replace it with some dichotomic search which is O(log n)
So a corrected version of your code could be:
#include <stdio.h>
int is_number_in_array(float num, float *array, int size)
{
for (int i =0; i < size; ++i)
{
if (num == array[i])
return 1;
}
return 0;
}
#define MAX_NUMBER 50
int main(void)
{
/* number of number read */
int size = 0;
/* number already read */
float array[MAX_NUMBER] = {};
/* currently read number */
float num = 0;
float avg = 0;
float sum = 0;
/* get next number, stop when a conversion failed */
while (scanf("%f",&num) == 1)
{
/* test if number is already in array */
if (! is_number_in_array(num, array, size )) {
/* not in array: add it */
array[size ++] = num;
sum += num;
}
/* Add some test here to check that size is not as big as MAX_NUMBER */
}
avg = sum/size;
printf("%0.2f", avg);
return 0;
}
First, read the numbers into an array nums. Let n be the number of numbers in the array. This can be done in O(N). I leave this to you.
Secondly, sort the array using a O(N log N) algorithm. I leave this to you.
Finally, we can identify duplicates by simply consulting neighbours. The tricky part is avoiding going out of bounds. Accessing nums[-1] or nums[n] would result in Undefined Behaviour, so we have to avoid that.
We don't need to look ahead and backwards. We want to use a number the first time we encounter it, so we only need to look backwards.
Don't forget to make sure we have at least one number, because we can't divide by zero.
if (!n) {
fprintf(stderr, "Can't find the average of zero numbers.\n");
exit(1);
}
float sum = 0;
size_t uniques = 0;
for (size_t i=0; i<n; ++i) {
if (i > 0 && nums[i] == nums[i-1])
continue;
sum += nums[i];
++uniques;
}
float avg = sum/uniques;
The complexity analysis is O(N + N log N + N) = O(N log N).
(Both of the other answers include O(N^2) solutions
As an aside, we can do better than O(N log N).
In practical terms, inserting into a well-written hash table has an amortized performance of O(1), and lookups are O(1). We can use this to devise an O(N) solution to the problem.
Using Perl, since it has such hash tables built-in:
#nums
or die("Can't find the average of zero numbers.\n");
my %seen; # Hash table.
my $sum = 0;
my $uniques = 0;
for my $num (#nums) {
next if $seen{$num}++;
$sum += $num;
++$uniques;
}
my $avg = $sum/$uniques;
This approach saves all integers in an array, as long they are not saved already, as to avoid duplicates.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int bytes_read;
int size = 1000;
int i = 0;
int amount = 0;
int number = 0;
// boolean flag to detect duplicate numbers.
int duplicate = 0;
int sum = 0;
float unique_avg = 0;
// Allocate char / int arrays on the heap.
// These can be resized with realloc() if needed.
char* string = (char *) malloc (size);
int* unique_num = (int *) calloc (2 * size, 0);
// Declare char pointers to be used will splitting the string.
char* token;
char* rest = string;
printf ("Please enter a string: ");
bytes_read = getline (&string, &size, stdin);
// In case getline fails to get the input.
if (bytes_read == -1) {
puts ("error!");
}
// getline() read input succesfully.
else {
// Iterate over all space separated string tokens.
while ((token = strtok_r(rest, " ", &rest))){
// Convert string token to number
number = atoi(token);
for(i = 0; i < 2 * size; ++i){
if(number == unique_num[i]){
// Duplicate found.
duplicate = 1;
break;
}
}
if(!duplicate){
unique_num[amount] = number;
++amount;
}
// Restore value of duplicate for next iteration
duplicate = 0;
}
}
// Sum all unique numbers.
for(i = 0; i < amount; ++i){
sum += unique_num[i];
}
// Calculate the avg of unique numbers.
// Float casting is required for the fractional part of the division.
unique_avg = (float) sum / (float) (amount);
// Print the average.
printf("%f", unique_avg);
return 0;
}
Running this code in console yields with example input of 2 2 1:
Please enter a string: 2 2 1
1.500000
I have an array in C where:
int buf[4];
buf[0] = 1;
buf[1] = 2;
buf[2] = 5;
buf[3] = 2;
and I want to count how many elements in the array that have the same value with a counter.
In the above example, the number of elements of similar value is 2 since there are two 2s in the array.
I tried:
#include <stdio.h>
int main() {
int buf[4];
int i = 0;
int count = 0;
buf[0] = 1;
buf[1] = 2;
buf[2] = 5;
buf[3] = 2;
int length = sizeof(buf) / sizeof(int);
for (i=0; i < length; i++) {
if (buf[i] == buf[i+1]) {
count++;
}
}
printf("count = %d", count);
return 0;
}
but I'm getting 0 as the output. Would appreciate some help on this.
Update
Apologies for not being clear.
First:
the array is limited to only of size 4 since it involves 4 directions, left, bottom, top and right.
Second:
if there is at least 2 elements in the array that have the same value, the count is accepted. Anything less will simply not register.
Example:
1,2,5,2
count = 2 since there are two '2's in the array.
1,2,2,2
count = 3 since there are three '2's in the array
1,2,3,4
count = 0 since there are no similarities in the array. Hence this is not accepted.
Anything less than the count = 2 is invalid.
You are really rather hamstrung by the order the values appear within buf. The only rudimentary way to handle this when limited to 4-values is to make a pass with nested loops to determine what the matching value is, and then make a single pass over buf again counting how many times it occurs (and since you limit to 4-values, even with a pair of matches, your count is limited to 2 -- so it doesn't make a difference which you count)
A short example would be:
#include <stdio.h>
int main (void) {
int buf[] = {1, 2, 5, 2},
length = sizeof(buf) / sizeof(int),
count = 0,
same = 0;
for (int i = 0; i < length - 1; i++) /* identify what value matches */
for (int j = i + 1; i < length; i++)
if (buf[i] == buf[j]) {
same = buf[i];
goto saved; /* jump out of both loops when same found */
}
saved:; /* the lowly, but very useful 'goto' saves the day - again */
for (int i = 0; i < length; i++) /* count matching numbers */
if (buf[i] == same)
count++;
printf ("count = %d\n", count);
return 0;
}
Example Use/Output
$ ./bin/arr_freq_count
count = 2
While making that many passes over the values, it takes little more to use an actual frequency array to fully determine how often each value occurs, e.g.
#include <stdio.h>
#include <string.h>
#include <limits.h>
int main (void) {
int buf[] = {1, 2, 3, 4, 5, 2, 5, 6},
n = sizeof buf / sizeof *buf,
max = INT_MIN,
min = INT_MAX;
for (int i = 0; i < n; i++) { /* find max/min for range */
if (buf[i] > max)
max = buf[i];
if (buf[i] < min)
min = buf[i];
}
int range = max - min + 1; /* max-min elements (inclusive) */
int freq[range]; /* declare VLA */
memset (freq, 0, range * sizeof *freq); /* initialize VLA zero */
for (int i = 0; i < n; i++) /* loop over buf setting count in freq */
freq[buf[i]-min]++;
for (int i = 0; i < range; i++) /* output frequence of values */
printf ("%d occurs %d times\n", i + min, freq[i]);
return 0;
}
(note: add a sanity check on the range to prevent being surprised by the amount of storage required if min is actually close to INT_MIN and your max is close to INT_MAX -- things could come to quick stop depending on the amount of memory available)
Example Use/Output
$ ./bin/freq_arr
1 occurs 1 times
2 occurs 2 times
3 occurs 1 times
4 occurs 1 times
5 occurs 2 times
6 occurs 1 times
After your edit and explanation that you are limited to 4-values, the compiler should optimize first rudimentary approach just fine. However, for any more than 4-values or when needing the frequency of anything (characters in a file, duplicates in an array, etc..), think frequency array.
The first thing that's wrong is that you are only comparing adjacent values in the buf array. You have to compare all the values to each other.
How to do this is an architectural question. The approach suggested by David Rankin in the comments is one, using an array of structs with the value and count count is a second, and using a hash table is a third option. You've got some coding to do! Good luck. Ask for more help as you need it.
You are comparing values of buf[i] and buf[i+1]. i.e. You are comparing buf[0] with buf[1], buf[1] with buf[2] etc.
What you need is a nested for loop to compare all buf values with each other.
count = 0;
for (i=0; i<4; i++)
{
for (j=i+1; j<4; j++)
{
if (buf[i]==buf[j])
{
count++;
}
}
}
As pointed out by Jonathan Leffler, there is an issue in the above algorithm in case the input has elements {1,1,1,1}. It gives a value of 6 when expected value is 4.
I am keeping it up, as the OP has mentioned that he wants to only check anything above 2. So, this method may still be useful.
I'm trying to display my output in a 4X4 format. The program receives name of a text file then get the values in the text file and store in the 2D array. Then later displays them like this
7 2 4 5
5 2 6 4
2 2 5 5
9 2 4 5
But the problem is, it doesn't display like that, I'm not sure if it's my loop or what. Any ideas. it runs fine with no errors but the numbers don't display right. Here's my code
int main () {
int i = 0;
int j = 0;
int value = 0;
int a[4][4];
char ch, file_name[100];
FILE *fp;
printf("Enter file name?");
gets(file_name);
fp = fopen("file.txt", "r");
if (fp == NULL)
{
perror("Error \n");
}
else
{
// printf("\n");
while (!feof(fp) && fscanf (fp, "%d ", &value))
{
a[i][j] = value;
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
printf("%d ",a[i][j] );
}
printf("\n");
}
}
}
fclose(fp);
return 0;
}
Your code suffers from various problems since you are mixing the code that reads the input and code that writes the output in one while loop.
Separate the code that reads the input and the code that creates the output. Ideally, put them into different functions.
Declare the functions as:
void readData(FILE* in, int a[4][4]);
void writeData(FILE* out, int a[4][4]);
Use them as:
int main()
{
int a[4][4];
// Your code to open the file.
readData(in, a);
writeData(stdout, a);
}
Implement them as:
void readData(FILE* in, int a[4][4])
{
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
if ( fscanf(in, "%d", &a[i][j]) != 1 )
{
printf("Unable to read an array element.\n");
exit(0);
}
}
}
}
void writeData(FILE* out, int a[4][4])
{
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
fprintf(out, "%d ", a[i][j]);
}
fprintf(out, "\n");
}
}
Well, let's take your problems apart a piece at a time. First, the salient part of your code regarding input and attempted output:
int i = 0;
int j = 0;
int value = 0;
int a[4][4];
...
while (!feof(fp) && fscanf (fp, "%d ", &value))
{
a[i][j] = value;
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
printf("%d ",a[i][j] );
}
printf("\n");
}
}
Before we look at the !feof problem. let's look at the overall logic of your loop structure. When you enter your while loop, the values of i = j = 0;. Presuming your file is open and there is an integer to read, you will fill value with the first integer in the file and then assign that value to the first element of your array with:
a[i][j] = value;
Now, you have stored 1-integer at a[0][0]. (all other values in a are uninitialized and indeterminate) Inexplicably, you then attempt to output the entire array, ... uninitialized values and all.
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
printf("%d ",a[i][j] );
}
printf("\n");
}
Attempting to access an uninitialized value invokes Undefined Behavior (your program is completely unreliable from the first attempt to read a[0][1] on). It could appear to run normally or it could SegFault or anything in between.
You need to complete the read of all values into your array before you begin iterating over the indexes in your array outputting the values.
But wait... there is more... If you did not SegFault, when you complete the for loops, what are the values of i & j now? Your loops don't complete until both i and j are 4, so those are the values they have at the end of the first iteration of your while loop.
Now let's go to the next iteration of your while loop. Presuming there are two integer values in the file you are reading, you read the second integer into value. What happens next? You one-up yourself. After already invoking undefined behavior 15 times by attempting to read 15 uninitialized values a[0][1] -> a[3][3], you then attempt to write beyond the bounds of a with:
a[4][4] = value; /* remember what i & j are now? */
You then hit your for loops..., again with a[0][1] holding the only validly initialized value and the cycle repeats.
But wait..., there is more... After having read the last integer in your file, you arrive at the beginning of your while loop one last time:
while (!feof(fp) && fscanf (fp, "%d ", &value))
You test !feof(fp) and no EOF has been set because your last read was a valid read of the last integer which completed with the last digit and did not trigger a stream error, so you proceed to fscanf (fp, "%d ", &value) which now returns EOF (e.g. -1), but since you simply test whether fscanf(..), -1 tests TRUE so off you go again through the entire body of your loop invoking undefined behavior at least 16 more times.
Are you beginning to understand why the output may not have been what you wanted?
You have already had a good answer on how to go about the read and print. I'll offer just an alternative that does not use any functions so it may help you follow the logic a bit better. The following code just reads from the filename given as the first argument, or from stdin by default if no argument is given. The code validates that the file pointer points to a file that is open for reading and then enters a while loop reading an integer at a time into &array[rows][cols] with fscanf and validating the return of fscanf is 1. Anything else is considered failure.
The remainder of the read loop just increments cols until is reaches NCOLS (4 here - being the number of columns per-row), then it increments the row-count in rows and sets the column-index cols back to zero.
A final validation is performed before output to insure NROWS of integers were read and that cols was set to zero during the final iteration of the read-loop. The contents of array is then output. The code is fairly straight-forward:
#include <stdio.h>
#define NROWS 4
#define NCOLS NROWS
int main (int argc, char **argv) {
int array[NROWS][NCOLS] = {{0}}, /* declare and intialize array */
rows = 0, cols = 0; /* rows / columns index */
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;
}
/* validate no more than NROWS of NCOLS integers are read */
while (rows < NROWS && fscanf (fp, "%d", &array[rows][cols]) == 1) {
cols++; /* increment column */
if (cols == NCOLS) { /* if row full */
rows++; /* increment rows */
cols = 0; /* zero columns */
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
if (rows != NROWS || cols) { /* validate rows = NROWS & cols = 0 */
fprintf (stderr, "error: read only %d rows and %d cols.\n",
rows, cols);
return 1;
}
for (int i = 0; i < NROWS; i++) { /* output stored values */
for (int j = 0; j < NCOLS; j++)
printf (" %2d", array[i][j]);
putchar ('\n');
}
return 0;
}
(you have already been advised not to use gets which is subject to easy buffer overflow and so insecure it has been completely removed from the C11 library. If your professor continues to suggest its use -- go find a new professor)
Example Input File
$ cat dat/arr2dfscanf.txt
7 2 4 5
5 2 6 4
2 2 5 5
9 2 4 5
Example Use/Output
$ ./bin/arr2dfscanf <dat/arr2dfscanf.txt
7 2 4 5
5 2 6 4
2 2 5 5
9 2 4 5
Also note, that by reading with fscanf in this manner, it doesn't matter what format your input is in -- as long as it is all integer values. This will produce the same output:
$ echo "7 2 4 5 5 2 6 4 2 2 5 5 9 2 4 5" | ./bin/arr2dfscanf
Look things over and let me know if you have further questions.