• C

How to Read file into 2d Array

Hi

A part of my code is to read a file containing certain values into a 2D array for further processing. There can be any mumber of rows(more than 300) and any number of columns (less than 360). One of the problems im facing is to get the exact number of rows and columns in the file to dynamically allocate memory for the array. Further  to effectiveluy use fscanf or fgets to scan the file into the array.

Ive been tryina couple of things so now im just confused. Any help would be much appreciated.
NaverickAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Infinity08Commented:
>> Ive been tryina couple of things

If you could post them, then we can have a look at what you tried, and see if you're close or not.


>> A part of my code is to read a file

What kind of file ? A binary file ? Or a text file ? What's the format of the file (can you post an example) ?
0
NaverickAuthor Commented:
Its a text file

getting the exact number of rows and colums and scanning correctly is an issue

been told can use fgets for rows n colums and string tokenizer to scan each character and then covert into array


/*allocate memory for array**/
array = (int**)malloc(rows*sizeof(int));
 for(i=0;i<rows;++i)
 {
   matrix[i] = (int*)malloc(cols*sizeof(int));
   }

The text file could be something like
200   0    10    1    4    0 ............
180    12    1    3    0   9..............
.
.
.
.


/*print the array  to test if working */
 for(j=0;inrows;++i)
 {
   for(k=0;k<ncols;++k)
   {
     fprintf(fpout,"%d ", array[j][k]);
   }
   fprintf(fpout,"\n");
 }
0
Infinity08Commented:
>> The text file could be something like

And each line in the file represents one row, right ?


>> getting the exact number of rows and colums and scanning correctly is an issue

What you can do, is either :

(a) make a first pass over the file, just to find out how many rows and columns there are (so you can allocate the correct amount of memory), and then a second pass to copy the data.

(b) allocate a 2D array that is big enough to hold any amount of data the file can contain (you mentioned that it's always less than 360), and then simply fill the 2D array with the data from the file.

(c) read the data from the file, and realloc the 2D array to change it's size if needed.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

NaverickAuthor Commented:
Its a text file

getting the exact number of rows and colums and scanning correctly is an issue

been told can use fgets for rows n colums and string tokenizer to scan each character and then covert into int

fgets(size,sizeof(nRrow),fpin);

/cant figue out for colums/

/*allocate memory for array**/
array = (int**)malloc(rows*sizeof(int));
 for(i=0;i<rows;++i)
 {
   array[i] = (int*)malloc(cols*sizeof(int));
   }

for(i=0;i<rows;i++) {
       
        fgets(nRow,sizeof(nRow),fpin);
        ptrRow=nRow;
        k=0;
        while((token=strtok(ptrRrow,"\t"))!=(char *)NULL && k<cols) {
                array[i][k++]=atoi(token);
                ptrRow=(char *)NULL;
        }
     }




The text file could be something like(while creating the file i have inserted tabs between two values)
200   0    10    1    4    0 ............
180    12    1    3    0   9..............
.
.
.
./*print the array  to test if working */
 for(j=0;inrows;++i)
 {
   for(k=0;k<ncols;++k)
   {
     fprintf(fpout,"%d ", array[j][k]);
   }
   fprintf(fpout,"\n");
 }
0
Infinity08Commented:
Did my previous post help ?


>> 200   0    10    1    4    0 ............
>> 180    12    1    3    0   9..............

Incidentally, is there a reason that the first values of each line are much bigger than the others ? Or is that a coincidence ?

Or do they represent the amount of items in the row maybe ?
If so, does the file also contain the amount of rows somewhere (maybe the first line of the file ?) ?
And is it to be expected that rows can have a different amount of items ? (200 != 180)
0
NaverickAuthor Commented:
That makes a lot of sense.....but cant figure how to get number of colums

fgets(size,sizeof(nRrow),fpin);

will just have to count number of values in first row to count number of colums till i get to /n .....right??
0
NaverickAuthor Commented:
For some reason i do get high values in the first column.... its just a coincidence. I can modify my previous code to also print the number of rows. But it will print at the end of the file after the last row

No all rows will have the same number of values
0
NaverickAuthor Commented:
guess im mixing one too many thigs for a not so difficult task...hence its just messed up due to lack of structure and logic
0
Infinity08Commented:
>> will just have to count number of values in first row to count number of colums till i get to /n .....right??

Yes, that would give you the amount of columns.

Which of the 3 approaches I listed earlier do you plan to use ?
0
NaverickAuthor Commented:
>>>>>What you can do, is either :

The logic there will take me there..... Its just the technicality im stuck with...are the bits of code any good...?
0
Infinity08Commented:
Yes, but which of the 3 approaches did you pick ? Which one do you want to implement ?
0
NaverickAuthor Commented:
(a) make a first pass over the file, just to find out how many rows and columns there are (so you can allocate the correct amount of memory), and then a second pass to copy the data.

Seems to be the most efficient precise and logical and simpler. The other are bit difficult for me to comprehend. Might be someting to do with using a buffer. While the second option of predefining a large array may either give rise to unsufficient memory or having to deal with filling empty cells with null ..again not sure but id go with (a)
0
Infinity08Commented:
>> While the second option of predefining a large array may either give rise to unsufficient memory

360*360*sizeof(int) is still reasonable in size. Assuming an int is 4 bytes, that would be 518400 bytes, or about half a MB.

>> or having to deal with filling empty cells with null

You don't need to fill them, because you know how many rows and columns there are (by the time you reach the end of the file).


>> again not sure but id go with (a)

Ok, that sounds good. Let's go with that.

So, we'd make a first pass over the file, just to find out how many rows there are (ie. how many lines in the file), and how many columns there are (ie. how many numbers on one line).
After that, you allocate the needed amount of memory.
Then you rewind the file, and start again from the beginning. This time you fill the allocated array with the numbers from the file.
0
NaverickAuthor Commented:
the number of rows will be greater than 360 may 1000 or more....but colums will be less than 360.

as far as the snippets of code ive posted are they any good for the chosen method
0
Infinity08Commented:
Except for this line :

>>                 ptrRow=(char *)NULL;

the code you posted looks ok for allocating the memory and filling the array with the data from the file.

But you still need to find out the amount of rows and columns.
0
Infinity08Commented:
Just give it a try with the above information, and don't hesitate to ask if you have a doubt about something.
0
NaverickAuthor Commented:
will do...thx for guiding me..will get back...as soon as i have something in hand....Thx again
0
NaverickAuthor Commented:
Hey Infinity
 I manged to do that bit. It did work to the best of my knowledge. However if u can pls go thru the code n c if its ok. i will have to later modify this bit and make it a function. Howevr, the logic seems to b fine i think. Is there any way of speeding process because the main code is supposed to run in real time and there could be at least 20 files (360x1000) to process. I have attached a small examle txt file.

I have another query amongst others. Should i cotinue on this or frame a new question. In breif , how can i dynamically increase the size of an array (add a new row) without loosing the values already stored in the previous rows. As this array will be used to for further frocessin with the array got from the file.

Thanx a lot

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
 
 
int main(int argc, char *argv[])
	{
	FILE *fin, *fout ; 
	int colCnt,rowCnt, col=0,row=0;
	int i,j;
	int**matrix;
	
 
	if(argc!=2)
		{
		printf("Check Arguments\n");
		exit(0);
		}
	if(!(fin=fopen(argv[1],"r")))
		{
		printf("Unable to open file\n");
		exit(1);
		}
	
	while((colCnt=fgetc(fin))!='\n')
		{
		if(colCnt=='\t')
			{
			++col;
			}
		}
	rewind(fin);
	while((rowCnt=fgetc(fin))!=EOF)
		{
		if(rowCnt=='\n')
			{
			++row;
			}
		}
 
	rewind(fin);
	
	printf("Number of cols = %d ",col);
	printf("Number of rows = %d\n ",row);
 
	matrix =(int**)malloc(row*sizeof(int));
	for(i=0;i<row;i++)
		{
		matrix[i]=(int*)malloc(col*sizeof(int));
		}
 
	for(i=0;i<row;i++)
		{
		for(j=0;j<col;j++)
			{
			fscanf(fin,"%d",&matrix[i][j]);
			printf("%d ",matrix[i][j]);
			}
		printf("\n");
		}
	fclose(fin);
	return 0;
		
	}

Open in new window

hist.txt
0
Infinity08Commented:
You have two while loops : one for counting the columns, and one for the rows. You don't need to rewind after the first loop, since you'll be reading the same characters again, and you already know that you've seen only one '\n'.


>>         matrix =(int**)malloc(row*sizeof(int));

This has to be :

        matrix =(int**)malloc(row*sizeof(int*));

since you're allocating and array of int*'s here, not an array of int.

Also, consider checking whether malloc returns NULL each time you call it, to be sure that the allocation succeeded before continuing with the rest of the code.


The rest of the code looks fine.


>> Is there any way of speeding process because the main code is supposed to run in real time and there could be at least 20 files (360x1000) to process.

There are a few ways (like : instead of rewinding the file and reading it again, read it into a memory buffer the first time, and use the memory buffer for the second pass). But don't optimize, until you actually notice a problem with performance ...


>> Should i cotinue on this or frame a new question.

Since it's a short question, and still somewhat related to the original question, I'll answer it here ;)


>> how can i dynamically increase the size of an array (add a new row) without loosing the values already stored in the previous rows

When the realloc call succeeds for increasing the size of a block of memory, it guarantees that the original data will remain unchanged. See the reference page for more information :

        http://cplusplus.com/reference/clibrary/cstdlib/realloc/
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.