How to input a data file into a 2D array - c

I've got a file which I need to store in a 2-D array so I can perform matrix operations on it. All I know is that the doubles will be separated by spaces and line breaks, e.g:
2.04 3.0 4.0
5.0 6.1 7.0
8.0 9.03 10.0
I won't know how many numbers there will be, so I need a scalable parsing function. So far I have:
int main(int argc, char* argv[])
{
FILE *fp;
char ch;
fp = fopen("matrix.dat","r");
if ( fp == NULL )
{
puts ( "Cannot open source file");
}
/*count the number of lines*/
int lines=1;
char c;
while((c = fgetc(fp)) != EOF)
{
if(c == '\n')
lines++;
}
printf("lines= %i\n",lines);
/*reopen the file to reset the pointer*/
fclose(fp);
fp = fopen("matrix.dat","r");
double m[lines][lines];
/*Load file into array*/
int i,j;
for(i=0;i<lines;i++)
{
for(j=0;j<lines;j++)
{
fscanf( fp, "%lf", &(m[i][j]));
}
fscanf(fp, "\n", NULL);
}
/*print out stored matrix*/
for(i=0;i<lines;i++)
{
for(j=0;j<lines;j++)
{
printf("%lf ",m[i][j]);
}
printf("\n");
}
}
My issues with this method are
It makes the assumption that the number of rows equals the number of doubles per line, which may not be true.**
Any missing doubles in the file will cause the program to load the wrong matrix into memory (remaining values offset by 1).
I'm currently loading the file into memory twice to count the lines.
Is there a more sensible way to input this data into a 2D array? I need to ensure that the input matrix is square and that my program can handle a square matrix of any order. I'm quite new to C, so examples and naming functions will be much appreciated :) (Apologies for the dodgy indenting)
** Sorry for being so vague, I wanted some error handling, i.e making sure the input is not accepted unless there are exactly nxn doubles.

Like Nicolas, I'm curious what you mean by point (1)...if the matrix is square, then won't the number of rows always equal the number of doubles per line? If not, then I suppose you could look through the file for the row with the most values.
Here's your code modified to do that:
/* count the number of lines */
int lines = 1;
int maxValues = 0;
int count = 0;
char junk;
while((junk == fgetc(fp)) != EOF) {
if(junk == '\n') {
lines++
if(maxValues <= count) {
maxValues = ++count;
}
count = 0;
}
else if(junk == 0x20) {
count++;
}
}
To address point (2), maybe try this modification:
/* load file into array */
int i, j;
for(i = 0; i < lines; i++) {
j = 0;
do {
fscanf(fp, "%lf", &(m[i][j]));
j++;
} while((junk = fgetc(fp)) != '\n');
}
Finally for point (3), I'm pretty sure you can use rewind(fp); to reset the pointer to the beginning of the file.

read the first line with fgets
count the values, let's say they're n
make an array of n * n
read n - 1 lines of n values each
calculate the inverse
Voila!

Related

i am trying to read a file in c language the file structure is in array and i have to seperate it into array x[] and y[]

My code is to find line number and then print all element in it but it is throwing garbage value and main thing to do is to seperate front one as x and y respectively plese help me seperate x[] = [60,15,62.....] and y[] = [229,221,59,....]
Dataset is
60,229
15,221
62,59
96,120
16,97
41,290
52,206
...
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *myFile;
myFile = fopen("datasetLR1.txt", "r");
int count=0;
char c;
for (c = getc(myFile); c != EOF; c = getc(myFile)) {
if (c == '\n'){
count = count + 1;
}// Increment count if this character is newline
}
int numberArray[count*2];
int i;
if (myFile == NULL){
printf("Error Reading File\n");
exit (0);
}
for (i = 0; i < count*2; i++){
fscanf(myFile, "%d,", &numberArray[i] );
}
for (i = 0; i < count*2; i++){
printf("Number is: %d\n\n", numberArray[i]);
}
fclose(myFile);
return 0;
}
After you count the number of lines in the file with your first for loop, you should use rewind(myFile);. This puts you back to the beginning of the file. Without this, you are reading off the end of the file, which is producing the garbage values. Other than that, your code works fine.
You should also look at doing fscanf("%d,%d\n", &x, &y);, which should read off both numbers at once (and the newline) and assign them to x and y respectively. This should simplify your code significantly, however, your code works fine without it.

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

C. Method not reading correctly from textfile when figure contains 2 integers

I have a basic math program where I store the results in a textfile. Each result is stored on a new line in the textfile, and the figures varies between 0 and 15.
The textfile can looking something like this;
1
0
4
9
12
etc.
with each figure on a new line (dont know why the numbers are on the same line here).
The program should find the highest result. It does not matter if there is more than one figure with the same value.
My problem is that, when the figure contains two integers my method only takes the last one and stores this. If I have 15 for example, 5 is stored.
My method looks like this. Would be greatfull for some help!
void BestResult(){
char c;
int max=0;
int converted=0;
if (access("ResultScore.txt", F_OK) != -1){
fPointerScore=fopen("ResultScore.txt", "rt");
while((c=fgetc(fPointerScore))!=EOF){
converted=atoi(&c);
if (converted>max){
max=converted;
}
}
printf("\nThe best result is : %d/15 at the moment", max);
}
AskUserWhatToDo();
}
You are storing it in a character. So char will store only '5' and not '15'. Use data type string or char*.
Problem with your code is, it read all characters(in your file one by one)
Your code need needs to detect end of the line
ch!= '\n'
Try this:
char buffer[10]; /* as big as the biggest number */
char ch;
int i = 0;
double d, dMax = 1000, dMin = -1000;
while ((ch= getc(fp)) != EOF) {
if (ch!= '\n')
buffer[i++] = ch;
else {
buffer[i] = '\0';
d = atof(buffer);
if (d > dMax) dMax = d;
if (d < dMin) dMin = d;
i = 0;
}
}
Personally, I'll solve the problem in this way
int BestResult(FILE *infile) {
char buf[100];
int len=0;
int i=0;
while(fgets(buf,sizeof(buf),infile)!=NULL)
len++;
rewind(infile);
int *numbers;
numbers = (int *) malloc (len * sizeof(int));
while(fgets(buf,sizeof(buf),infile)!=NULL)
sscanf(buf,"%i",&numbers[i]);
int maxnum=numbers[0];
for(i=1;i<len;i++)
if(numbers[i]>maxnum)
maxnum=numbers[i];
return maxnum;
}
So first read the size of the file that defines the number of elements in your case, then allocate an array of integers to the number of items you find, fill the array by parsing line by line with the fgets and fill the array with sscanf, then research the maxnumber.

read a file and save as a matrix

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

fscanf can't read the first integer of my file input in C but reads the rest

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.

Resources