Detecting Increasing or Decreasing Data - c

I got a data file which consists of a single column with the header name with temperature and the following rows are just a series of recorded temperature. I can read it successfully(perhaps) into the C program using the following command:
#include <stdio.h>
#include <cstdlib>
int main()
{
FILE *fpt; /*define a pointer to predefined structure type FILE*/
fpt = fopen("temperature.dat","r");
char temp[10];
float t[7];
int i;
fscanf(fpt, "%s",temp);
printf("%s",temp);
for(i=0;i<7;++i)
{
fscanf(fpt, "%f",&t[i]);
printf("%.2f",t[i]);
}
printf("%f",t[3]); /*just testing whether the program is reading correctly*/
fclose(fpt);
system("pause");
}
But the problem is how could I detect when there is a series of temperature, for instance 6 temperature values are increasing continuously. I need something like IF total of 6 values of temperature is increased continuously, then it will generate some error message using printf function. Assume that the total input number of data is not fixed, how could I program it.

There is no need to use an extra loop. You can just do
totalInc = 0;
for(i=0;i<7;++i) {
fscanf(fpt, "%f",&t[i]);
printf("%.2f",t[i]);
if (i > 0) {
if (t[i] > t[i-1]) totalInc += 1;
else totalInc -= 1;
}
}
The totalInc will tell you the number of times the current value is greater than the previous value. For your case, you can then just check for totalInc == 6 but really, you can just check for any number of increments. A positive number will indicate a general incremental trend, while a negative number will indicate a general decreasing trend.

To detect whether a file of floats has at least 6 increasing values in a row, you could do something like this:
#include <stdio.h>
#define IN_A_ROW 6
int main() {
FILE *f = fopen("temps.txt", "r");
float x, last_x;
int inc = 0;
fscanf(f, "%f", &last_x);
while (fscanf(f, "%f", &x) == 1) {
if (x > last_x) { // or maybe >=
if (++inc >= IN_A_ROW) {
printf("Found %d increases in a row\n", IN_A_ROW);
return -1;
}
}else
inc = 0;
last_x = x;
}
fclose(f);
return 0;
}

Add a variable (say, inctemp) to count seeing increases in a row, and increment it in your loop if there is an increase. Reset it to 0 if there is not an increase. At the end of your loop, you know how many in a row there were (at least at the end of the data set)
Modified for arbitrary number of reads
int inctemp = 0;
float curtemp, prevtemp;
...
if ( fscanf(fpt, "%f",&prevtemp) == 1)
printf("%.2f",prevtemp);
while( fscanf(fpt, "%f",&curtemp) == 1)
{
printf("%.2f",curtemp);
if( curtemp > prevtemp ) {
inctemp++;
}
else {
inctemp = 0;
}
if( inctemp == 6 ) {
printf("Six increases in a row!\n");
}
prevtemp = curtemp;
}
}

Finding a delta between the temperatures will help you.
#include <stdio.h>
#include <cstdlib>
int main()
{
FILE *fpt; /*define a pointer to predefined structure type FILE*/
fpt = fopen("temperature.dat","r");
char temp[10];
float t[7];
int i, loweringdelta;
fscanf(fpt, "%s",temp);
printf("%s",temp);
loweringdelta = 1;
for (i=0; i<7; ++i)
{
fscanf(fpt, "%f", &t[i]);
printf("%.2f", t[i]);
if (i > 0 && (t[i]-t[i-1]<= 0))
{
loweringdelta = t[i]-t[i-1];
}
}
if (loweringdelta > 0)
{
// Your error message here
}
printf("%f", t[3]); /*just testing whether the program is reading correctly*/
fclose(fpt);
system("pause");
}

You will need some kind of counter to see how many times you have seen incrementing temperatures. Also, read the file in a while loop:
#include <stdio.h>
int main()
{
FILE *fpt; /*define a pointer to predefined structure type FILE*/
fpt = fopen("temperature.dat","r");
char temp[10];
int count = 0;
int i;
float prev_temp = -999.00;
float current_temp;
int threshold = 6;
fscanf(fpt, "%s",temp); // header?
printf("Header: %s\n",temp);
while(!feof(fpt)) {
fscanf(fpt, "%f", &current_temp);
if (current_temp > prev_temp) count++;
else count = 0;
prev_temp = current_temp;
if (count > threshold) printf("Saw %d consecutive increases\n", count);
}
fclose(fpt);
}

Related

I want to read data from a file which contains integers and floats

I want to read in data from a file (using C) which contains integers and floats, but I only want to put the floats into an array. I am having trouble with figuring out how to avoid the integers.
This is an example of a data set:
2019 001 3.55 4.63 3.14 4.56 4.21 2.33
2019 002 4.58 5.94 6.16 7.28 8.61 9.91
I hope that your question distinguishes between an int and float as whether or not the number should contain a decimal point. Otherwise, all ints can be floats as well. Therefore, I assume that 123 is not a float and neither is 123.000.
Having said that, a clever solution would be to read all the numbers as floats. While reading the data from the file, assign the number to an int variable. Then you can add that number to your array if that number cannot be contained by an int.
For example,
float input = 123.45;
int n = input; // n is 123
// If input cannot be shaped to an int
if (n != input)
addToArray(input);
Now, it's just a matter of implementing this logic:
#include <stdio.h>
#include <stdlib.h>
// Change this according to your requirements
#define INPUT_FILE "data_set.txt"
#define ARRAY_SIZE 100
int main()
{
float arr[ARRAY_SIZE];
float data;
int n;
int i = 0;
FILE* input_file = fopen("data_set.txt", "r");
if (!input_file)
{
printf("ERROR: Could not open the file!");
exit(EXIT_FAILURE);
}
while (fscanf(input_file, "%f", &data) != EOF)
{
// Truncate the number to an integer
n = data;
// Take the number if it cannot be an integer
if (n != data)
{
arr[i] = data;
++i;
}
}
// Display the output and check the result
n = i;
for (i = 0; i < n; ++i)
printf(" %g", arr[i]);
fclose(input_file);
return 0;
}
If the number of elements in the data set is unknown, use a dynamic array.
A fun solution would be to read all input as float, cast them to int and compare the two variables for equality. If not equal, some rounding means that it is a float, else it is an int.
Remember that float variables are not accurate representation so you might want to add an appropriate threshold to the comparison that fits your usecase.
#include <stdio.h>
int main(void) {
FILE *myFile;
myFile = fopen("test.txt", "r");
float numberArray[16];
int i;
for (i = 0; i < 16; i++)
{
fscanf(myFile, "%f", &numberArray[i]);
}
for (i = 0; i < 16; i++)
{
int temp = (int)numberArray[i];
if( numberArray[i] != temp ){
printf("Float: %f\n\n", numberArray[i]);
}
else{
printf("Int: %d\n\n", temp);
}
}
}

How to read in polynomials and storing them in an array with error checking in C?

The function reads coefficients for the polynomial from standard input and stores them in the given array. The capacity parameter tells the function how much room the coeff[] array has for coefficients. The function tries to read all the coefficients it can until it reaches the end-of-file and returns the number of coefficients it actually reads. If the input polynomial is bad (e.g., with too many coefficients or with input that doesn't parse as a floating point number), this function will print "Invalid polynomial" and exit the program with a status of 101.
The input file is like this:
0.0 6.0
25.00 -47.50 25.17 -5.00 0.33
The first two numbers is the range of the plot and the second line represents the coefficients of the polynomial.
This is the code I have so far:
/**
*/
// Include our own header first
#include "poly.h"
// Then, anything else we need in the implementation file.
#include <stdlib.h>
#include <stdio.h>
/** Exit status if the input polynomail is bad. */
#define INVALID_POLYNOMAIL_STATUS 101
int readPoly( int capacity, double coeff[] )
{
double variable = 0.0;
int ch;
int count = 0;
while ( ( ch = getchar() ) != EOF ) {
for(int i = 0; i < capacity; i++) {
if(scanf("%lf", &variable) != 1) {
fprintf(stderr, "Invalid input");
exit(101);
}
else {
coeff[i] = variable;
count++;
}
}
}
return count;
}
getchar may read the beginning of a value, this is not correct like that
A simple way is to stop on any error (EOF or bad value) :
int readPoly( int capacity, double coeff[] )
{
int i;
for(i = 0; i < capacity; i++) {
if (scanf("%lf", &coeff[i]) != 1)
break;
}
return i;
}
An other way is to bypass by hand the spaces to be able to indicate an error :
int readPoly( int capacity, double coeff[] )
{
int i;
for (i = 0; i < capacity; i++) {
for (;;) {
int c;
if ((c = getchar()) == EOF)
return i;
if (!isspace(c)) {
ungetc(c, stdin);
break;
}
if (scanf("%lf", &coeff[i]) != 1) {
fprintf(stderr, "Invalid input");
exit(101);
}
}
return i;
}
Note count is redundant with i, just i is enough, and you can also directly scanf into the array

Comparing digits of two inputs to see if they are the same

I am currently trying to finish a code where a user inputs two 5 digit long numbers. The code then checks to see if there are any identical numbers in the same spot for the two numbers and displays how many identical numbers there are in the same spot of the two inputs. (ex. comparing 56789 and 94712 there would be one similar digit, the 7 in the 3rd digit place.) As of now I have been able to break down the inputs into the digits in each spot, I just need help comparing them. Originally I thought I could just create an int that would serve as a counter and use modulus or division to output a 1 whenever the digits were the same, but I have been unable to put together a formula that outputs a 1 or 0 depending on if the digits are alike or not.
suppose you know the length of strings n (as a condition you would need them to be equal, if they differ in length other validation is needed)
//n is the length of string
for(int i=0;i<n;i++)
{
if(string1[i]==string2[i])
{
//do something, make a counter that increments here...
//also save index i, so you can tell the position when a match occured
}else
{
//do something else if you need to do something when chars didnt match
}
}
Here you when i=0, you are comparing string1[0] with string2[0], when i=1, you compare string1[1] with string2[1] and so on.....
I'd recommend reading the two in as strings or converting to strings if you have the ability to. From there it's a simple string compare with a counter. Something like this:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int is_numeric(char *str)
{
while (*str)
if (!isdigit(*str++))
return (0);
return (1);
}
int main(void)
{
char num1[32];
char num2[32];
int count = 0;
printf("Digit 1\n>> ");
if (scanf("%5s", num1) != 1 || !is_numeric(num1))
return (0);
printf("Digit 2\n>> ");
if (scanf("%5s", num2) != 1 || !is_numeric(num2))
return (0);
if (strlen(num1) != 5 || strlen(num2) != 5)
return (0);
for (int i=0; i<5; ++i)
if (num1[i] == num2[i])
++count;
printf("%d\n", count);
return (0);
}
You can do it very easy using modulo (%) and divide (/). First you do % 10 to get the least significant digit and do the compare. Then you do / 10 to remove the least significant digit. Like:
#include <stdio.h>
#include <string.h>
int main(void) {
unsigned int i1, i2;
int i;
int cnt = 0;
printf("Input first 5 digit number:\n");
if (scanf(" %u", &i1) != 1 || i1 < 10000 || i1 > 99999) // Get integer input and check the range
{
printf("input error\n");
return 0;
}
printf("Input second 5 digit number:\n");
if (scanf(" %u", &i2) != 1 || i2 < 10000 || i2 > 99999) // Get integer input and check the range
{
printf("input error\n");
return 0;
}
for (i=0; i<5; ++i)
{
if ((i1 % 10) == (i2 % 10)) ++cnt; // Compare the digits
i1 = i1 / 10;
i2 = i2 / 10;
}
printf("Matching digits %d\n", cnt); // Print the result
return 0;
}
It can also be done using strings. Read the input as unsigned int and then convert the value to a string using snprintf and finally compare the two strings character by character.
Something like:
#include <stdio.h>
#include <string.h>
int main(void) {
char str1[32];
char str2[32];
unsigned int i1, i2;
int i;
int cnt = 0;
printf("Input first 5 digit number:\n");
if (scanf(" %u", &i1) != 1) // Get integer input
{
printf("input error\n");
return 0;
}
snprintf(str1, 32, "%u", i1);
if (strlen(str1) != 5) // Convert to string
{
printf("input error - not 5 digits\n");
return 0;
}
printf("Input second 5 digit number:\n");
if (scanf(" %u", &i2) != 1) // Get integer input
{
printf("input error\n");
return 0;
}
snprintf(str2, 32, "%u", i2); // Convert to string
if (strlen(str2) != 5)
{
printf("input error - not 5 digits\n");
return 0;
}
for (i=0; i<5; ++i)
{
if (str1[i] == str2[i]) ++cnt; // Compare the characters
}
printf("Matching digits %d\n", cnt); // Print the result
return 0;
}
The reason for taking the input into a unsigned int instead of directly to a string is that by doing that I don't have to check that the string are actually valid numbers (e.g. the user type 12W34). scanf did that for me.

Reading array of integers from the first line of a text file and raising error if it exceeds 10

I've looked around and haven't seen this question answered yet. Basically I am trying to create an array of integers from text files that have sequences of integers e.g, 2 5 2 9 1 0 3 53 7 . I want to print an error message if line in the text file exceed 10 integers. There is only one line in the text file.
Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *file = fopen("somenumbers.txt", "r");
int integers[10];
int i=0;
int num;
if (file == NULL)
{
printf("Error Reading File\n");
exit (0);
}
while(fscanf(file, "%d", &num) > 0) {
integers[i] = num;
i++;
}
for (i = 0; i < 16; i++)
{
printf("Number is: %d\n\n", integers[i]);
}
fclose(file);
return 0;
}
Should I check the check the contents of the array after it is finished being created or during the initial iteration through the line? Are there any functions that would make it easy to determine if the line in the text file is larger than the limit(10)?
You must check in while loop as below;
while(fscanf(file, "%d", &num) > 0) {
if (i >= 10) {
printf("error\n");
break;
}
integers[i++] = num;
}
You should ensure that you never access integers[10], otherwise it's array out-of-bounds error which results in undefined behavior (i.e. literally anything can happen after that). So if you succeeded in reading 11-th number (which should go into integers[10]), you should stop the loop immediately.
The reason you are getting the error is the size of integers array being 10. Due to that size, if you read more than 10 integers, you will have a segment violation problem.
To find out that you have more than 10 integers, all you need to understand you should give an error is to read the 11th integer. So instead of declaring the array with size 10, switch it to 11. Then, when you read the 11th integer you may print an error message and exit properly.
Also, you may want to bound the loop printing the numbers by the amount of integers you have read.
Below is a sample code, based on yours, that implements the fixes I mentioned.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *file = fopen("somenumbers.txt", "r");
int integers[11];
int i=0, k=0;
int num;
if (file == NULL)
{
printf("Error Reading File\n");
exit (0);
}
while(fscanf(file, "%d", &num) > 0) {
integers[i] = num;
if(k++ == 10) {
{
printf("Too many integers!!!\n"); /* or any other error message you'd like */
exit (0);
}
}
/* loop iterates until k integers are printed. k contains the # of integers read. */
for (i = 0; i < k; i++)
{
printf("Number is: %d\n\n", integers[i]);
}
fclose(file);
return 0;
}
Check before:
...
while (fscanf(file, "%d", &num) > 0) {
if (i >= 10) {
/* handle error */
break; /* or return */
}
...
to prevent trying to access an array element that does not exist
You have two errors:
1) When reading, you may write the input value outside the array boundary
2) When printing, you for sure acces outside array boundary.
Try this instead:
while(fscanf(file, "%d", &num) > 0) {
integers[i] = num;
i++;
if (i == 10)
{
break; // Can't store more value so stop the loop using break
}
}
// Save the number of values read
int total = i;
for (i = 0; i < total; i++)
// ^^^^ notice
{
printf("Number is: %d\n\n", integers[i]);
}
As an alternative to break you can put the check of i into the while condition like:
while(i < 10 && fscanf(file, "%d", &num) > 0) {
//^^^^^^ notice
integers[i] = num;
i++;
}
You have some issues with your code:
The code posted is prone to buffer overflow, as you are not checking if more than 10 integers have been found. This means you will be accessing outside the bounds of integers[10], which only causes undefined behavour.
Since you want to read one integer at a time with fscanf(), you should use:
while (fscanf(file, "%d", &num) == 1)
Instead of:
while(fscanf(file, "%d", &num) > 0)
fscanf() returns the number of values read, and using 1 instead of > 0 would make more sense in this case.
This segment here:
for (i = 0; i < 16; i++)
{
printf("Number is: %d\n\n", integers[i]);
}
is accessing beyond bounds of integers[10]. You need to change the guard so you don't exceed the limit of 10 integers.
Your code can look like this:
#include <stdio.h>
#include <stdlib.h>
#define MAXINT 10
int main(void) {
FILE *file;
int integers[MAXINT], num;
size_t count = 0;
file = fopen("somenumbers.txt", "r");
if (!file) {
fprintf(stderr, "%s\n", "Error reading file");
exit(EXIT_FAILURE);
}
while (fscanf(file, "%d", &num) == 1) {
if (count == MAXINT) {
printf("More than %d integers found!\n", MAXINT);
exit(EXIT_FAILURE);
}
integers[count++] = num;
}
printf("Success! No more than %d integers found:\n", MAXINT);
for (size_t i = 0; i < count; i++) {
printf("integers[%zu] = %d\n", i, integers[i]);
}
fclose(file);
return 0;
}

C Programming: Error in program. Won't show Max/Min/Average of files inputted by user

I'm attempting to create a code that the user inputs a filename and the program will then find the Min, Max, and Average of the numbers in the file.
This is a sample of a file the user would input into the program (the # are comments and would be ignored):
#Data from field experiment 312A
#2015-01-12
35.6
3.75
#2015-01-13
9
#2015-01-14
43.43
7.0001
And this is what I have for my code for the moment, I tried combining different methods, but fear I am just too lost at this point.
#include <stdio.h>
#include <math.h>
int main()
{
char ch, file_name[25];
FILE *fp;
double average, num = 0, min = 0, max = 0, sum = 0, N;
int i;
printf("Please enter the name of the file to load:\n");
scanf(file_name);
fp = fopen(file_name, "r");
if (fscanf(fp, "%lf", &N) == 1)
{
for (i = 0; i < N; i++)
if (num < min || i == 0)
min = num;
if (num > max || i == 0)
max = num;
sum += num;
}
fclose(fp);
average = sum/N;
printf("Smallest: %7.2lf\n", min);
printf("Largest: %7.2lf\n", max);
printf("Average: %7.2lf\n", average);
return(0);
}
Any help would be appreciated.
In your code,
scanf(file_name);
is wrong usage of scanf(), you're missing a format specifier. You have to change that to
scanf("%24s", file_name); //%s is the format specifier for a string input
Check the man page for more details.
Apart from that, there are logical errors in your program. You're reading the file only once, which is not what you want. Also, there is no meaning of the for() loop.
My advice will be:
Open the file, then check for success of foepn(). Otherwise, don't procceed.
Read a whole line using fgets().
Convert the input string to float using strtod().
If conversion success, check for < min and > max, change accordingly, and sum the result.
Otherwise, if conversion fails, it is a comment, ignore that line.
Continue untill fgets() returns NULL (erach end of the file)
Calculate the average based on sum / (number of successful conversions)
Print the sum, max and min.
Close the file.
That said, the recommended signature of main() is int main(void).
EDIT:
A pseudo-code (as requested for better understanding)
#include <stdio.h>
#include <math.h>
#include <float.h>
int main(void)
{
char file_name[25] = {0};
FILE *fp = NULL;;
double average = 0, min = DBL_MAX, max = 0, sum = 0;
int N = 0;
char buf[128] = {0}; // buffer tyo be used with fgets()
ask for the filename (using `scanf("%24s", file_name);`)
open the file (using `fp = fopen(file_name, "r");`)
if file cannot be opened successfully (`if (!fp)`)
exit
while (reading a complete line from file using `fgets(buf, 128, fp)` != EOF) //EOF ==> end of file
{
if (buf[0] == `#`) //comment, no propcessing reqd, continue
continue;
val = strtod(buf, NULL); //you should use proper error checking, as metioned in the man page
if (val) // valid float value found
{
if ( val < min )
min = val;
else if ( val > max )
max = val;
sum += val; //add the value
N++; //increase the counter
}
}
close the file (using `fclose(fp);`)
calculate `average = sum/N;`
printf("Smallest: %7.2f\n", min);
printf("Largest: %7.2f\n", max);
printf("Average: %7.2f\n", average);
return(0);
}
You should initialize min with a very large number.
Your if needs {} otherwise the code executes other than you think.
before you calculate sum/N you should check N>0.
Your combination of fscanf and for does not work this way.

Resources