Writing out an array using fprintf - c

I'm having trouble writing an array of double numbers in a text file. The problem is, the code runs, but doesn't write out anything.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *out;
double numbers[30];
int i=0;
for(i;i<30;i++)
scanf("%lf", &numbers[i]);
out=fopen("out.txt", "w");
if (out == NULL) {
fprintf(stderr, "error in opening .txt");
exit(EXIT_FAILURE);
}
while ( i<30 ) {
fprintf(out, "%.3f", numbers[i]);
i++;
}
fclose(out);
return 0;
}
Basically, the code is supposed to write out an array of 30 double numbers in a text file, and round the decimals to '.3'.

You forgot to re-initialise i to 0, hence the current value of i is 30, which effectively causes the while loop to not execute.
i = 0; //Re-initialise i.
while ( i<30 ) {
fprintf(out, "%.3f", numbers[i]);
i++;
}
It would be better, if you use a for loop, as it's syntax helps you to remember to initialise the increment variable.
for (i = 0; i < 30; ++i)
fprintf(out, "%.3f", numbers[i]);

Related

Why my fscanf does not read the first string but reads the last line into the first string instead?

I'm a beginner at files including code so please someone help me. This is what my code looks like.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define first_ten_hours 7.99;
#define after_ten_hours 1.99;
double charges_all(int hour);
double charges_avg(int money, int hour_use);
double round_money(double sum);
int main()
{
FILE *f_read, *f_write;
f_read = fopen("usage.txt", "r");
f_write = fopen("charges.txt", "w");
if(f_read == NULL)
{
printf("Error to open the file.\n");
return 1;
}
char date[2][10];
char studenid[10][100];
double using_hour[10];
int current_line = 1;
for(int i = 0; i < 11; i++)
{
if(current_line == 1)
{
fscanf(f_read, "%s %s", date[0], date[1]);
current_line++;
}
else
{
fscanf(f_read, "%s %lf", studenid[i], &using_hour[i]);
current_line++;
}
}
current_line = 1;
for(int i = 0; i < 11; i++)
{
if(current_line == 1)
{
printf("%s %s\n", date[0], date[1]);
current_line++;
}
else
{
printf("%s %lf\n", studenid[i], using_hour[i]);
current_line++;
}
}
fclose(f_read);
fclose(f_write);
return 1;
}
After the current_line = 1;, I print to check and see the problem.
This is my text file.
12 2022
18010 4.5
92052 3.2
01051 7.4
11052 6.3
13052 5.5
01081 2.2
65052 1.3
94052 2.8
32052 3.7
41051 4.9
and this is the output from the printf loop:
41051 2022
18010 4.500000
92052 3.200000
01051 7.400000
11052 6.300000
13052 5.500000
01081 2.200000
65052 1.300000
94052 2.800000
32052 3.700000
41051 4.900000
But what I want is for the first string at the first line to be 12.
Because of the way you have written your for loop(s), you are accessing elements of the studenid and using_hour arrays that are out-of-bounds on the last iteration of those loops (i.e. when i is 10 – an element at [10] is past the end of an array declared with 10 elements). Such "bad access" causes undefined behaviour, which may (as it appears in your case) include overwriting the value you had previously read into the date array elements.
A "quick fix" is to change the [i] indexes (all of them) to [i - 1]. However, a better way would be to put the read of the first line outside the loops and then run those loops for the next 10 lines:
int main()
{
FILE* f_read, * f_write;
f_read = fopen("usage.txt", "r");
f_write = fopen("charges.txt", "w");
if (f_read == NULL)
{
printf("Error to open the file.\n");
return 1;
}
char date[2][10];
char studenid[10][100];
double using_hour[10];
fscanf(f_read, "%9s %9s", date[0], date[1]); // Read first line differently
for (int i = 0; i < 10; i++) // Run the loop ONLY 10 times ...
{
fscanf(f_read, "%99s %lf", studenid[i], &using_hour[i]);
}
printf("%s %s\n", date[0], date[1]);
for (int i = 0; i < 10; i++)
{
printf("%s %lf\n", studenid[i], using_hour[i]);
}
fclose(f_read);
fclose(f_write);
return 1;
}

Using fscanf *after* fgetc issue

In C, there are many posts concerning using fgetc after fscanf, dealing with an additional \n, but I am seeing another issue when using them in the reverse order; fscanf after fgetc.
When using fscanf after fgetc, I get a different fscanf-result to if I just omit fgetc (in the example script, just hard-coding num=1000 and commenting-out the block using fgetc).
I can replicate this correct fscanf-result while still using fgetc if I rewrite the file contents to the myFile variable, as in the below script. Removing this line produces the different incorrect fscanf-result.
What is causing the difference in the fscanf-result when using fgetc first, and how can I address the issue?
/* First read tab-delimited 4-digit int data from a text file,
* parsing into an array of the correct size num, then compute
* the mean of the array while avoiding overflow. */
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *myFile;
myFile = fopen("int_values.txt", "r");
int c=0, i=0;
float mean = 0.0;
// Identifying there are 1000 values in the tab-delimited file.
// Using fgetc
int num = 1;
while ((c=fgetc(myFile)) != EOF ){
if (c == '\t')
++num;
}
int arr[num]; // Array of correct size for all values from file.
// Redeclaring since fgetc seems to break fscanf
myFile = fopen("int_values.txt", "r");
// Read and store each value from file to array.
for (i=0; i<num; i++){
fscanf(myFile, "%d ", &arr[i]);
}
// Compute average cumulatively to avoid overflow.
mean = arr[0]
for (i=1; i<num; i++){
//printf("In the %dth place, arr has value %d.\n", i, arr[i]);
mean *= (float)i / (float)(i+1);
mean += arr[i] / (float)(i+1);
}
fclose(myFile);
printf("The overall mean of the %d values in the file is %f.\n\n", num, mean);
return 0;
}
Identifying there are 1000 values in the tab-delimited file.
Do not count tabs. Instead, read the ints. It's far too easy for the number of tabs to not relate correctly to the number of int.
Sum the int into a long long to avoid overflow. Use double for generic floating-point math.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *myFile = fopen("seal_weights.txt", "r");
if (myFile) {
int num = 0;
long long sum = 0;
int value;
// return 1 on success, EOF on end-of-file, else 0 on non-numeric input
while (fscanf(myFile, "%d", &value) == 1) {
sum += value;
num++;
}
double mean = num ? (double) sum / num : 0.0;
printf("The overall mean of the %d values in the file is %f.\n\n", num,
mean);
// read in again and save values if truly desired.
// This step not needed to compute average.
rewind(myFile);
int i;
int arr[num];
for (i = 0; i < num; i++) {
if (fscanf(myFile, "%d", &arr[i]) != 1) {
break;
}
}
// Use arr[] in some way.
fclose(myFile);
}
return 0;
}

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;
}

Detecting Increasing or Decreasing Data

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);
}

C - writing output to a file

EDIT:
void print(const int *v, const int size) {
FILE *fpIn;
fpIn = fopen("char-array.txt", "a");
int i;
if (v != 0) {
for (i = 0; i < size; i++) {
printf("%d", (int)v[i]);
fprintf(fpIn, "%d\n", (int)v[i]);
}
perm_count++;
printf("\n");
}
fclose(fpIn);
}
I guess this is a relatively simple question :)
Basically the program is using a permutation algorithm, and printing the output to standard output in the console. I also want to write the content to a file via fprintf I assume. Though I cant seem to get it working. It just prints garbage characters into the first line in the text file and nothing more !
I will paste the code below, and help is much appreciated ! The write to file code is found within the print function.
Thanks,
T.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <time.h>
clock_t startm, stopm;
#define START if ( (startm = clock()) == -1) {printf("Error calling clock");exit(1);}
#define STOP if ( (stopm = clock()) == -1) {printf("Error calling clock");exit(1);}
#define PRINTTIME printf("%2.3f seconds used by the processor.", ((double)stopm- startm)/CLOCKS_PER_SEC);
int perm_count = 0;
void print(const int *v, const int size) {
FILE *fpIn;
fpIn = fopen("char-array.txt", "wb");
int i;
if (v != 0) {
for (i = 0; i < size; i++) {
printf("%d", (char)v[i]);
fprintf(fpIn, "%d", v[i]);
fprintf(fpIn, "\n");
}
perm_count++;
printf("\n");
}
}
void permute(int *v, const int start, const int n) {
int i;
if (start == n-1) {
print(v, n);
}
else {
for (i = start; i < n; i++) {
int tmp = v[i];
v[i] = v[start];
v[start] = tmp;
permute(v, start+1, n);
v[start] = v[i];
v[i] = tmp;
}
}
}
int main() {
int i, x;
printf("Please enter the number of terms: ");
scanf("%d", &x);
int arr[x];
printf("Please enter the terms: ");
for(i = 0; i < x; i++)
scanf("%d", &arr[i]);
START
permute(arr, 0, sizeof(arr)/sizeof(int));
STOP
printf("Permutation Count: %d\n", perm_count);
PRINTTIME
return 0;
}
1. Incorrect access modes in fopen call
You open your file as a binary file: fopen("char-array.txt", "wb");. Don't put b to this string containing access modes if you are going to write formatted strings there. And since you probably want to append new data at the end of the file instead of overwritting them, use a instead of w:
fopen("char-array.txt", "a");
2. Writing to the output buffer, not directly into the file
When you are using functions like fprintf, you don't write directly to the file but to the output buffer. You have to use fflush to write data from the output buffer into the file, or you can just close your file by using fclose function which flushes this buffer automatically.
Just add this line:
fclose(fpIn);
at the end of print function.
3. Incorrect formatting of the output
You should not cast int to char. It will truncate your numbers. And you also have fprintf(fpIn, "\n"); in wrong scope I guess. It could look like this:
for (i = 0; i < size; i++) {
printf("%d ", v[i]);
fprintf(fpIn, "%d ", v[i]);
}
perm_count++;
printf("\n");
fprintf(fpIn, "\n");
Don't waste your time doing programming you don't have to, the use of fprintf is nice but since all you want to do is print the output, you can just print things into the file directly using UNIX built-in commands. Say your program is called wirteoutput then all you have to do is pass the following command when calling it from the shell writeoutput > file.txt. All you would have to use would be the printf function.
If you are curious about this, this is an old function and you can find a detailed description in the original paper The UNIX Operating System. Look at the section called Standard I/O.
You didn't cast to a char (from a int) when you wrote to the file as you did with the screen display. The following will provide the same numbers in the file as you're seeing on screen:
fprintf(fpIn, "%d", (char)v[i]);

Resources