read a file and save as a matrix - c

i have a file like that :
1 100
2 200
3 300
4 400
1
i want to save it as a matrix and i want to save NULL if there is no second number !
i tried to write the program but it does not work correctly !
#include<stdio.h>
int main() {
int k=0 ,i,j , arr[100][100];
FILE *in= fopen("file.txt","r");
char line[1000];
while(fgets(line,1000,in) !=NULL) k++;
fgets(line,1000,in);
for (i=0;i<k;i++){
for (j=0;j<2;j++){
int tmp ;
fscanf(in ,"%d", &tmp) ;
arr[i][j] = tmp ;
}
}
fclose(in);
return 0; }

Two major problems:
The first is that the first loop will read all lines, even the one with the single number on the line. That means the lonely fgets call will not do anything, and more importantly that the value of k will be wrong.
The second problem is that once you read all data from the file, you don't go back to the beginning of the file, instead you continue to try and read from beyond the end of the file.
The first problem can be solve by skipping the second fgets call, and decreasing k by one.
The second problem can be solved by calling rewind after you counted the number of lines.
Also when you actually read the numbers, you don't need the inner loop, just do e.g.
scanf("%d %d", &arr[i][0], &arr[i][1]);
Actually, you don't need the first line-counting loop at all, you can do it all in a single loop, by using fgets and sscanf and then checking the return value of sscanf. So your program could look something like
#include <stdio.h>
int main(void)
{
int values[100][2];
FILE *input = fopen("file.txt", "r");
size_t entries = 0;
if (input != NULL)
{
char buffer[40];
while (fgets(buffer, sizeof(buffer), input) != NULL && entries < 100)
{
int res = sscanf(buffer, "%d %d", &values[entries][0], &values[entries][1]);
if (res <= 1 || res == EOF)
{
// Read the last line with only one number, or an error happened
values[entries][0] = 0;
values[entries][1] = 0;
break;
}
++entries;
}
if (ferror(input))
{
printf("Error reading file\n");
}
fclose(input);
}
// All done, the number of "records" or "entries" is in the variable entries
// Example code: print the values
for (size_t i = 0; i < entries; ++i)
printf("Line %d: %d %d\n", i + 1, values[i][0], values[i][1]);
return 0;
}

Related

How to resolve this problem relevant File and Null in C?

So I need output size of array in this file text and to do this I must break the loop in the last position by using NULL to break but the problem here that when arr[i] come to value 0, it equal to NULL and break at that position so my size of array is not complete. How to resolve it? Thanks for support!
The file .txt input:
3
4
0
5
6
The code:
#include <stdio.h>
int main() {
char a[20];
char e[40];
int arr[30];
int num, key, k = 0, len = 0;
printf("Enter a filename: ");
scanf("%s", &a);
scanf("%c", &e);
FILE* rfile;
rfile = fopen(a, "r");
if (rfile == NULL) {
printf("Not found the file !!!");
}
else {
printf("Successfully accessed the file: %s\n", a);
int i;
for (i = 0; i < 30; i++) {
fscanf(rfile, "%d", &arr[i]);
fscanf(rfile, "%c", &e);
if (arr[i] == NULL) { // PROBLEM HERE
break;
}
len++;
}
}
printf("The size of array: %d", len);
return 0;
}
You can find some more details regarding what NULL is here, but you should save NULL for pointer comparisons, not comparing against ints as you are doing. In fact, your usage generates a warning:
warning: comparison between pointer and integer
Despite that, 0 == NULL will evaluate to true. Since 0 is in your list of values, you prematurely break revealing your problem. Instead, you simply need to read the entire file, either until you run out of room in your array (already covered by your for loop) or reach the end of the file (designated by EOF). To determine that, you need to check the return value of fscanf. Below is an example of a possible implementation:
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr[30];
int len = 0;
FILE* rfile;
rfile = fopen("file.txt", "r");
if (rfile == NULL) {
printf("Not found the file !!!");
exit(-1);
}
else {
int i;
for (i = 0; i < 30; i++) {
// fscanf returns the number of correctly matched items, or
// EOF when the end of the file is reached (or EOF on error)
int ret = fscanf(rfile, "%d", &arr[i]);
// did we get a correct match?
if (ret == 1)
{
// we matched one number as expected, increment len
len++;
}
// did we reach the end of file?
else if (ret == EOF)
{
// EOF can also indicate an error, check errno here to determine if
// an error occurred instead of end of file, if you want
break;
}
}
}
// prints 5 with your input file example
printf("The size of array: %d\n", len);
return 0;
}
I have no idea what you were trying to accomplish with e, so I removed that as well as other unused variables, and hardcoded user input.
arr is the array of ints arr[i] has type int. NULL is a pointer.
If 0 indicated the end of the data (sentinel value) then:
if (arr[i] == 0) break;
or in a short form
if (!arr[i]) break;

Reading Rows and Columns from File in C

I am trying to read this input txt file with my C code:
4 3
1.4 4.6 1
1.6 6.65 1
7.8 1.45 0
7 -2 2
and separate them into rows and columns so that I can sort. I tried doing that but I kept getting weird numbers.
So I tried printing out the rows and columns after I read them from the file and the output was zero. I realized then that my code is not reading the numbers from my text file properly. I have tried different means to fix to no avail. Any help or pointers will be highly appreciated.
#include <stdio.h>
#include <string.h>
#include <stdbool.h> //for bool
int main(){
setvbuf(stdout, NULL,_IONBF, 0);
int c;
FILE *file;
FILE *infile;
char filename[99];
char choice;
int rows, columns;
//while(choice == 'y' || choice == 'Y'){
printf("%s", "Enter file name: ");
fgets(filename, 99, stdin);
char *p = strchr(filename, '\n'); // p will point to the newline in filename
if(p) *p = 0;
file = fopen(filename, "r");
if (file) {
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
}
else{
puts("FILE NOT FOUND");
}
//read rows and columns from file
printf("%s","\n");
fscanf(file, "%d", &rows);
fscanf(file, "%d", &columns);
printf("%d", rows);
printf("%d", columns);
}
Problem 1
int rows = 0;
int columns = 0;
float matrix[rows][columns];
float sumOfRows[rows];
is not right.
After that, the number of elements in matrix and sumOfRows is fixed. They won't change if you change the values of rows and columns later in your program.
You need to read the values of rows and columns first before you define matrix and sumOfRows.
Problem 2
fscanf(file, "%d", &matrix[rows][columns]);
printf("%f",matrix[rows][columns]);
are not right either. Given the defition of matrix, use of matrix[rows][columns] is not right. They access the array using out of bounds indices.
Remember that given an array of size N, the valid indices are 0 to N-1.
Here's one way to proceed to resolve your problems:
fscanf(file, "%d", &rows); // Use %d, not %f
fscanf(file, "%d", &columns); // Use %d, not %f
// Now define the arrays.
float matrix[rows][columns];
float sumOfRows[rows];
// Read the data of matrix
for (int i = 0; i < rows; ++i )
{
for (int j = 0; j < columns; ++j )
{
fscanf(file, "%f", &matrix[i][j]); // Use %f, not %d
}
}
Your problem (actually, two problems) are in the if (file) {... block. First, you use a loop to read all characters from the file. Because of that, at the end of the loop you are also at the end of the file. Any further calls to fscanf result in undefined behavior.
Second, if the file did not open, you print a message (to the wrong output) and still continue to the fscanf part, which definitely leads to undefined behavior.
Solution: Remove the while loop and fix the error handling code:
if(file) {
// Nothing!
} else {
perror(filename);
return 1; // or return EXIT_FAILURE;
}

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

Jump to next line in .txt file in C

I need to make some actions from txt file.
What I was willing to do:
Calculate number of lines in txt
Open txt file
Iterate for each line
Iterate within each line and perform the task within it
Close file
Current code:
int lines(){
FILE *fp = fopen("somedata.txt","r");
int ch;
int count=0;
do{
ch = fgetc(fp);
if( ch== '\n') count++;
}
while( ch != EOF );
fclose(fp);
return count;
}
int main(){
int linesnum=lines();
FILE *fp = fopen("somedata.txt", "r");
if (fp == 0){
fprintf(stderr, "failed to open test0.txt\n");
exit(-1);
}
float areas[linesnum];
for (int j=0;j<linesnum;j++){
float array[150];
for (int i = 0; i < 150; i++){
fscanf(fp, "%f", &array[i]);
if (getc(fp) == (int)'\n'){
//that ends iteration for a line once it founds "\n"
//and assigns its value to temporary array
break;
}
}
//SOME TASK PERFORMED OVER HERE FOR EACH LINE lets say calculate average
if (getc(fp) == EOF){ //That's supposed to be end of iteration through lines
break;
}
}
fclose(fp);
return 0;
}
File is in format (max lines 1000, max elements in each line is 150).
Number of elements in each line is different, so if I make a big matrix of 1000x150, most of elements will be empty; that's why I don't want a matrix, and just simply want perform task for each line.
1 2 3 4 5 6
1 3 2 5 6 7 3 5
1 3 3 2 5 2 3
5 3 4 2 52 5 6
Well, I'm ending up with error Segmentation fault: 11 after performing task for 1st line.
I'm not sure how do I jump to next line after 1st iteration. That's the question.
Any thoughts?
UPDATE: Just had to get rid of EOF break thing in main():
if (getc(fp) == EOF){
break;
}
Something like this may work.
Read a line with fgets. The line must be large enough to hold the longest line.
Use a pointer to line and an offset to parse the values from the line.
%n will receive the number of bytes used by the sscanf so the pointer can be advanced to the next value.
char line[1500];
char *pline;
int used = 0;
int i = 0;
int linesnum = 0;
float array[150];
while ( fgets ( line, sizeof ( line), fp))) {
pline = line;
i = 0;
while ( ( sscanf ( pline, "%f%n", &array[i], &used)) == 1) {
pline += used;
i++;
if ( i >= 150) {
break;
}
}
linesnum++;
if ( linesnum >= 1000) {
break;
}
}

handling trailing \n when using feof()

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

Resources