I'm trying to use fscanf to read a file containing 25 ints and store them in memory. However, it appears that for the first 12 values, instead of scanning the actual int in the file fscanf is always showing up as 1. The 13th value shows up as -1, and then the while loop in the code below terminates. Any idea why this might be? Thanks for your help.
#include <stdio.h>
#include <stdlib.h>
#include "matrix.h"
#define ROWS 5
#define COLS 5
void load_file(FILE* file, int** p);
int main()
{
FILE* f1;
f1 = fopen("twenty-five-ints.txt", "r");
int p=0;
int* matrix = &p;
load_file(f1, &matrix);
}
void load_file(FILE* file, int** p) {
*p = malloc(25*sizeof(int));
int number = 0;
int i = 0;
while (fscanf(file, "%d", &number) != EOF) {
*(*p + i) = fscanf(file, "%d", &number);
printf("%d ", *(*p + i));
i++;
}
printf("\n");
}
The printf statement inside the while loop prints out 12 ones separated by spaces, followed by a -1.
There are two things to mention.
Remove one fscanf() call. Othersise, you'll end up losing every alternative value scanned.
fscanf() does not return the scanned value. In case a macth is found, it stores the scanned value in the supplied argument (&number). Use the argument to get the scanned value. You can make use of the return value to check for the suucess os the call to fscanf().
Quoting the man page, (emphasis mine)
The scanf() family of functions scans input according to format as described below. This format may contain conversion specifications; the results from such conversions, if any, are stored in the locations pointed to by the pointer arguments that follow format. [...]
You should not fscanf() twice and you should compare fscanf() to the number of expected fields to be scanned.
while ((i < 25) && (fscanf(file, "%d", (*p + i)) == 1))
printf("%d ", *(*p + i++));
Also, fscanf() does not return the scanned value, what would you expect it to return in this case?
fscanf(file, "%s%d%", &string, &integer);
Aditionally Consider:
Using index notation to dereference the pointer.
Using an aditional pointer to avoid confusion.
Checking the return value from malloc()
void
load_file(FILE *file, int **data)
{
int *pointer;
size_t i;
*data = NULL; // So you can test this after the call to the function
pointer = malloc(25 * sizeof(**data));
/* ^ if this is a constant, this doesn't make a lot of sense */
/* because you can use an array instead. */
if (pointer == NULL)
return;
for (i = 0 ; ((i < 25) && (fscanf(file, "%d", &pointer[i]) == 1) ; ++i)
printf("%d ", pointer[i]);
printf("\n");
*data = pointer;
}
In my opinion, this function is poorly designed. You can't verify if the read values where in fact 25, nor can you specify that anywhere. If you want a function to read a given number of integers with a maximum try this
size_t
load_file(FILE *file, int **data, size_t maximum)
{
int *pointer;
size_t i;
*data = NULL; // So you can test this after the call to the function
pointer = malloc(maximum * sizeof(**data));
if (pointer == NULL)
return;
for (i = 0 ; ((i < maximum) && (fscanf(file, "%d", &pointer[i]) == 1) ; ++i)
;
*data = pointer;
return i;
}
With this function, you can do this
int *data;
// We assume that FILE * is a valid stream
size_t count = load_file(file, &data, 25);
if (data != NULL)
{
for (size_t i = 0 ; i < count ; ++i)
fprintf(stdout, "%d ", data[i]);
fputc('\n', stdout);
free(data);
}
Related
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;
}
#include <stdio.h>
char q[50];
int doo(int p, int n, char* s) {
int i = 0, j = 0;
while (s[i] != '\0') {
if ((i < p) && (i > (p + n))) {
q[j] = s[i];
++j;
}
i++;
}
puts(p);
}
int main() {
char s[50];
int n, p;
printf("<--program by gautam-->\n");
printf("enter the string-->");
gets(s);
printf("\nenter the numbers of character to be deleted and position-->");
scanf("%d%d", &n, &p);
--p;
doo(p, n, s);
return 0;
}
The task is to delete certain elements of a string by asking the user the position and number of elements to delete. I'm trying to copy all elements except those whose position is provided by user, but I'm getting no output at all.
The fundamental error in your code is that you are using the && operator in the test inside your while loop, whereas you should be using the || operator: if either of the conditions is true, then add the character to the output string.
Also, your doo function is declared as returning an int but it doesn't return anything: I fixed this in the code below by returning j (the count of characters copied) but, as you never use that, you may want to redeclare the function as void, instead.
You are also attempting to print p with the puts function, where you most likely want to print q (I can put this one down to a typo).
Lastly: Never use the gets function! Why is the gets function so dangerous that it should not be used? Use fgets(), instead - it's much safer, as it will never read in more characters than you tell it to, so the buffer won't overflow (if you specify the correct size).
Here's a 'fixed' version of your code, with comments added where I've made changes:
#include <stdio.h>
char q[50];
int doo(int p, int n, char* s)
{
int i = 0, j = 0;
while (s[i] != '\0') {
if ((i < p) || (i > (p + n))) { // Need OR not AND here
q[j] = s[i];
++j;
}
i++;
}
q[j] = '\0'; // Add nul terminator (don't need if only calling once, but best to have it anyway)
puts(q); // Should be printing "q" (result string) NOT "p" (position).
return j; // MUST return something - here, the count of characters
}
int main()
{
char s[50];
int n, p;
printf("<--program by gautam-->\n");
printf("enter the string-->");
fgets(s, 50, stdin); // NEVER use gets - it's been removed from the language!
printf("\nenter the numbers of character to be deleted and position-->");
scanf("%d%d", &n, &p);
--p;
doo(p, n, s);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int c1[100];
char c2[150];
char c3[100];
float c4[100];
float c5[100];
float c6[100];
float c7[100];
char c8[100];
char c9[100];
float c10[100];
char string[10][100];
int i, j;
char c;
FILE *fp1;
fp1 = fopen("sample.csv", "r");
while (1) {
c = fgetc(fp1);
if (c == EOF)
break;
else
printf("%c", c);
}
for (i = 1; i <= 10; i++) {
fscanf(fp1, "%d,%[^,],%[^,],%[^,],%[^,],%d,%d",
&c1[i], &c2[i], &c3[i], &c4[i], &c5[i],
&c6[i], &c7[i], &c8[i], &c9[i], &c10[i]);
}
for (j = 0; j <= 10; j++) {
printf("\n");
printf("%d", c3); //Here i am trying to read the column3 values but getting random integer values.
//This problem continues to every column
}
return 0;
}
I have to read file sample.csv and store values into the array so that I can perform operation on that values.
I am not getting the exact value from the csv file that I have read.
I am getting some random integer value on running the program.
There are many problems in your code:
you do not check if fopen() succeeded.
c must be defined as int for proper end of file testing
you must rewind the file with rewind(fp1); or fseek(fp1, 0L, SEEK_SET); before reparsing the contents with fscanf()
the loop index i must start at 0 instead of 1, because arrays are 0 based.
it is idiomatic in C to use for (i = 0; i < 10; i++) ... to handle 10 lines of input. i <= 10 would iterate 11 times.
you must check the return value of fscanf() to ensure the input stream has the expected format. The format string does not handle empty text fields.
the fscanf() format string is incompatible with the arguments provided
the printf format string "%d\n" in incompatible with the type of the argument: the argument is the array c3 which is passed as a pointer to its first member, not an int as expected.
Simply read a line in a loop until there are no more lines
#include <stdio.h>
#include <string.h>
#define MAX_ITEMS 10000
#define LARGEST_LINE 1000
#define LARGEST_ELEMENT 100
int main(void) {
int c1[MAX_ITEMS];
char c2[MAX_ITEMS][LARGEST_ELEMENT+1]; // large enough for each `c2`
char c3[MAX_ITEMS][LARGEST_ELEMENT+1];
char c4[MAX_ITEMS][LARGEST_ELEMENT+1];
char c5[MAX_ITEMS][LARGEST_ELEMENT+1];
int c6[MAX_ITEMS];
int c7[MAX_ITEMS];
int tmpc1;
char tmpc2[LARGEST_ELEMENT+1];
char tmpc3[LARGEST_ELEMENT+1];
char tmpc4[LARGEST_ELEMENT+1];
char tmpc5[LARGEST_ELEMENT+1];
int tmpc6;
int tmpc7;
int lineno = 0;
char buf[LARGEST_LINE]; // large enough for the largest line
while (fgets(buf, sizeof buf, fp1)) {
++lineno;
// no error, process line
if (sscanf(buf, "%d,"
"%" LARGEST_ELEMENT "[^,],"
"%" LARGEST_ELEMENT "[^,],"
"%" LARGEST_ELEMENT "[^,],"
"%" LARGEST_ELEMENT "[^,],"
"%d,%d",
&tmpd1, tmpc2, tmpc3, tmpc4, tmpc5, &tmpd6, &tmpd7) == 7) {
// line ok, copy tmp variables and update indexes
c1[i] = tmpd1;
strcpy(c2[i], tmpc2);
strcpy(c3[i], tmpc3);
strcpy(c4[i], tmpc4);
strcpy(c5[i], tmpc5);
c6[i] = tmpd6;
c7[i] = tmpd7;
i++;
} else {
// line with error, you may want to report to the user
fprintf(stderr, "line %d with error.\n", lineno);
}
}
// read "error", probably EOF; close file and report
fclose(fp1);
for (int j = 0; j < i; j++) {
printf("item #%d: %d, %s-%s-%s-%s, %d %d\n",
c1[j], c2[j], c3[j], c4[j], c5[j], c6[j], c7[j]);
}
return 0;
}
Also consider putting all those c arrays inside a struct and make 1 single array of that structure.
My program needs to read input from a file. The file has a format "int int int" and then some asterisks to indicate that you need to stop reading there. I want to store them in an array of struct and I did. But it seems like my program can't read the very first integer of the input file. I checked it with printf and I can't do anything about it. Help please. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct points{
int i;
int x;
int y;
};
int main(){
int lines = 0;
char c, e;
int i, j, x ,y, a, b, temp ;
FILE *fp;
fp = fopen("input.txt", "r");
if (fp != NULL){
while ((e = fgetc(fp)) != '*'){
if (c == '\n'){
lines++;
}
fscanf(fp, "%d%d%d", &i, &x, &y);
struct points pt[lines];
for (j = 0; j <= lines; j++){
pt[j].i = i;
pt[j].x = x;
pt[j].y = y;
printf("%d ", pt[j].i);
}
for (a = 0; a<=lines; a++){
for (b = a + 1; b <= lines; b++){
if (pt[a].x > pt[b].x){
temp = pt[a].x;
pt[a].x = pt[b].x;
pt[b].x = temp;
}
}
}
}
}
else{
printf("Cannot open File!\n");
}
printf("lines = %d\n", lines);
return 0;
}
Your code:
while ((e = fgetc(fp)) != '*') {
if (c == '\n'){
lines++;
}
fscanf(fp, "%d%d%d", &i, &x, &y);
will read the first character and throw it away if it is NOT an asterisk, and will then attempt to read 3 integers AFTER that first character it threw away. If that first character was a digit, then it will look like you 'lost' (part of) the first number.
You also have the problem that you seem to be trying to read the values into a block-local array pt that exists for a single iteration of the while loop (so its recreated with no (garbage) contents each iteration), and then you want to use it after the loop where it is out of scope (so this code won't compile).
What you want is probably something more like:
#define MAX_POINTS 100
struct points pt[MAX_POINTS];
int i = 0;
while (i < MAX_POINTS && 3 == fscanf(fp, "%d%d%d", &pt[i].i, &pt[i].x, &pt[i].y)) {
printf("%d ", pt[i].i);
i++;
}
for (int a = 0; a <= i; a++) {
for (int b = a+1; b <= i; b++) {
:
Note that this reads integers up until it finds something that doesn't look like an integer (such as an asterisk, but could be anything else, including an end-of-file), rather than reading until it finds an asterisk. If you want to read until you see an asterisk, you need to decide what to do with anything that is neither an asterisk or an integer.
Edit
for your alternate question of how to read numbers up to *** and then read more numbers after them (and possibly more stars), you could use something like:
int val;
char buffer[20];
do {
/* start of a group */
while (1 == fscanf(fp, "%d", &val)) {
/* read an integer within a group */
}
/* fp is at EOF or something not an integer. */
/* so read it and loop if its '***' */
} while (1 == fscanf(" %19[*]", &buf) && !strcmp(buf, "***"));
Have you tried using the format string "%d %d %d" instead of "%d%d%d" (i.e. with spaces)?
Also, there are several other problems I see:
You use a while loop to find the first '*' in the line, but then you ask fscanf to parse 3 ints starting at that location. It may not be able to find an int by looking at a '*'...
You also declare the variable struct points pt[lines]; in the middle of a block; that is not valid C syntax.
Once you fix these things, the problem may be fixed.
I have written a small program which takes input of a file such as:
13,22,13,14,31,22, 3, 1,12,10
11, 4,23, 7, 5, 1, 9,33,11,10
40,19,17,23, 2,43,35,21, 4,34
30,25,16,12,11, 9,87,45, 3, 1
1,2,3,4,5,6,7,8,9,10
and outputs the largest sum of numbers on each line that is less than 50.
However if the inputted file has a trailing newline character the loop runs one too many times and hence another line is added to the array with random data. So I'm looking for a better way to do this comparison to avoid this issue. I'm also assuming all lines have 10 integers on at the moment as i cannot think of a better way to do the end of line loop comparison.
#include <stdio.h>
#include <stdlib.h>
void readLineData(int lineNo, int val[][10], FILE *fp);
int findSum(int lineNo, int val[][10], FILE *fp);
int main(int argc, char *argv[]) {
FILE *fp;
int val[5][10];
// Open file.
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("Cannot open file ");
exit(EXIT_FAILURE);
}
for (int i = 0; !feof(fp); i++) // runs too many times if file ends with '\n'
{
readLineData(i, val, fp);
printf("%d\n", findSum(i, val, fp));
}
fclose(fp);
return EXIT_SUCCESS;
}
void readLineData(int lineNo, int val[][10], FILE *fp) {
char c;
for (int i = 0; i < 10; i++) // assuming line contains 10 integers
{
fscanf(fp, "%d,", &val[lineNo][i]);
}
}
int findSum(int lineNo, int val[][10], FILE *fp) {
int highVal = 0;
int value1 = 0;
int value2 = 0;
for(int i = 0; i < 10; i++) //each letter
{
for(int j = 0; j < 10; j++)// every other letter
{
if((val[lineNo][i] + val[lineNo][j]) > highVal && i != j && (val[lineNo][i] + val[lineNo][j]) <= 50)
{
highVal = val[lineNo][i] + val[lineNo][j];
value1 = val[lineNo][i];
value2 = val[lineNo][j];
}
}
}
printf("Line %d: largest pair is %d and %d, with a total of: ", lineNo+1, value1, value2);
return highVal;
}
any help with those loop comparisons and general notation tips is most welcome.
Thanks
The posted code does not distinguish between two lines that have five integers and (the expected) one line that has 10 integers. Suggest reading in a line at a time, using fgets() and then using sscanf() on the read line to ensure that all the read integers belong to the same line.
Check the return value of input operations. For example, sscanf() (and fscanf()) return the number of assignments made. Only process lines that have the expected 10 integers, which would detect invalid lines including the trailing empty line.
For example:
/* Returns 1 on success and 0 on failure. */
int readLineData(int lineNo, int val[][10], FILE *fp)
{
char line[1024]; /* Arbitrarily large. */
if (fgets(line, sizeof(line), fp))
{
/* %n records position where processing ended. */
int pos;
const int result = sscanf(line,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n",
&val[lineNo][0],
&val[lineNo][1],
&val[lineNo][2],
&val[lineNo][3],
&val[lineNo][4],
&val[lineNo][5],
&val[lineNo][6],
&val[lineNo][7],
&val[lineNo][8],
&val[lineNo][9],
&pos);
/* 10 integers and full line processed,
except if new-line character present. */
return 10 == result &&
(pos == strlen(line) ||
(pos + 1 == strlen(line) && '\n' == line[pos]));
}
return 0;
}
You could simply consume the newline character yourself:
for (int i = 0; !feof(fp); i++) // runs too many times if file ends with '\n'
{
readLineData(i, val, fp);
printf("%d\n", findSum(i, val, fp));
fscanf(fp, "%*c"); // read a character without storing it in a variable
}
Note that there are undoubtedly better ways that involve reading an entire line at once and simply examining its contents; but this is the easiest way that will fit with what you already have.
you could check if fscanf fails in your readLineData function:
int readLineData(int lineNo, int val[][10], FILE *fp) {
for (int i = 0; i < 10; i++) {// assuming line contains 10 integers
if (fscanf(fp, "%d,", &val[lineNo][i]) != 1) {
return 1;
}
}
return 0;
}