Help with ifstream and store dynamic array

Thanks vlad!
Last edited on
Thank you for using code tags.

but if I wanted to READ & LOAD the file with user input. it can't work.


These are pieces of your code, with some paraphrasing :D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int ** a;
int limit = 0;
//...
if (choice == 1) 
{
    a = new int * [limit];
    int i;
    for (i = 0; i < limit; i++) a[i] = new int [limit];
    //...
}

else if (choice == 2)
{
    readData(a, limit);
    Display(a, limit);
    //...
}

//...

void readData(int ** matric, int dimension)
{
    //...
    for (int r = 0; r < dimension; r++)// row loop
    {
          for (int c = 0; c < dimension; c++)  // column loop
		  {
                         inFile >> matrix[r][c]; // read data into matrix
                         // ... This line causes the program to crash
		  }
    }
    //...
}


Your problem is that you allocated sufficient space for your matrix in the if clause, but no in the other clauses, so i choice is 2, a would be an uninitialized pointer, it doesn't point to a block in memory. Moreover, limit is still 0.

Next time, please try to use the debugger, you can pinpoint the problem or at least narrow the code block you feel suspicious about. Then, you can post it and people won't get afraid at the sight of a huge piece of code.
Last edited on
ya i know.. but

for example my folder got a lot of TXT files..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1.)wendy.txt ( which is 3x3 code inside)
Example:
3
8 1 6	
3 5 7	
4 9 2	

2.)jyejye.txt(which is 5x5 code inside)
5
17	24	1	8	15	
23	5	7	14	16	
4	6	13	20	22	
10	12	19	21	3	
11	18	25	2	9	


how i readData() from this TXT file and store back to my dynamic array so that my boolean function can work? no idea about it.. a lot senior trying to help..
closed account (o3hC5Di1)
Hi there,

I was thinking about this - note that I haven't got time to test the code right now, but I think this is the problem:

You store an array like this:

1
2
3
4
3
8 1 6	
3 5 7	
4 9 2


Where the first number is the dimension.
So instead of using the dimension that was passed to the readData function, you should use that first number as your dimension.

In order to do so, change:

inFile.ignore(5,'\n'); //line 118

To:

inFile >> dimension;

However, you should be careful using pointers in this way, because it may result in memory leaks.
It would be safer to use a std::vector matrix (you're only iterating the matrix front to back every time anyway).

Anyway - hope that helps.

All the best,
NwN
erase because have to try yourself and not just copy
Last edited on
@nwn

It's failed..

because i not wan passed to readData function instead.

inside my folder maybe got the other txt that inside have the 3x3 or 5x5 or more for the magic square.

my readData is let me to choose the file that I want to load and show it that whether is magic square or not..

if i run directly all my function are working well..

sorry for disturb
I suggest the following realization of function readData. The file name is passed as an argument to the function. So it has to be entered in the main. Also the function accepts pointer to the matrix which in the main has to be defined as

int **a = 0;

If the fiile was successfully opened when read in data otherwise return 0 as dimension of the square.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int readData( const std::string &fileName, int *** matrix  )
{
	std::ifstream inFile( fileName ) ;

	if ( !inFile )
	{
		cout<<"\nFile does'nt exist\n"<<endl;
		return ( 0 );
	}

	int dimension = 0;

	inFile >> dimension;
	
	*matrix = new int *[dimension];

	for ( int r = 0; r < dimension; r++ )
	{
		( *matrix )[r] = new int[dimension];
	}

	for ( int r = 0; r < dimension; r++ )// row loop
	{
		  for ( int c = 0; c < dimension; c++ )  // column loop
		  {
			inFile >>( *matrix )[r][c]; // read data into matrix
		  }
	}
	
	return ( dimension );
}
Last edited on
To test the function shown above you can write a simple test program. Here it is.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>

int readData( int ***matrix )
{
	int dimension = 5;

	*matrix = new int *[dimension];

	for ( int r = 0; r < dimension; r++ )
	{
		( *matrix )[r] = new int[dimension];
	}

	for ( int r = 0; r < dimension; r++ )// row loop
	{
		  for ( int c = 0; c < dimension; c++ )  // column loop
		  {
			( *matrix )[r][c] = r * dimension + c; // read data into matrix
		  }
	}

	return ( dimension );
}


int main()
{
	int **a = 0;

	int d = readData( &a );

	for ( int i = 0; i  < d; i++ )
	{
		for ( int j = 0; j < d; j++ )
		{
			std::cout << a[i][j] << ' ';
		}
		std::cout << std::endl;
	}

	for ( int i = 0; i < d; i++ ) delete [] a[i];
	delete [] a;

	return 0;
}


So the only you need to return to the original realization is to add std::ifstream
and read data from the stream instead of initialization the array as in this example.
Last edited on
You can also to write a separate function that will delete the pointer before reading a next file and before exiting the program.

1
2
3
4
5
6
7
8
9
void clearMatrix( int ***matrix, int dimension )
{
	if ( *matrix )
	{
		for ( int i = 0; i < dimension; i++ ) delete [] ( *matrix )[i];
		delete [] *matrix;
		*matrix = 0;
	}
}



In this case the body of the main of the previous test program will look the following way

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main()
{
	int **a = 0;

	int d = readData( &a );

	for ( int i = 0; i  < d; i++ )
	{
		for ( int j = 0; j < d; j++ )
		{
			std::cout << a[i][j] << ' ';
		}
		std::cout << std::endl;
	}

	clearMatrix( &a, d );

	return 0;
}


Now all is ready to update your original program taking as a base this test program.

For example to test displaying the files you can write


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <fstream>
#include <string>

int readData( const std::string &fileName, int *** matrix  )
{
	std::ifstream inFile( fileName ) ;

	if ( !inFile )
	{
		cout<<"\nFile does'nt exist\n"<<endl;
		return ( 0 );
	}

	int dimension = 0;

	inFile >> dimension;
	
	*matrix = new int *[dimension];

	for ( int r = 0; r < dimension; r++ )
	{
		( *matrix )[r] = new int[dimension];
	}

	for ( int r = 0; r < dimension; r++ )// row loop
	{
		  for ( int c = 0; c < dimension; c++ )  // column loop
		  {
			inFile >>( *matrix )[r][c]; // read data into matrix
		  }
	}
	
	return ( dimension );
}

void clearMatrix( int ***matrix, int dimension )
{
	if ( *matrix )
	{
		for ( int i = 0; i < dimension; i++ ) delete [] ( *matrix )[i];
		delete [] *matrix;
		*matrix = 0;
	}
}

int main()
{
	int **a = 0;
	std::string fileName( "wendy.txt" );
	int d = readData( fileName, &a );

	if ( d != 0 ) // here was a typo remove the semicolon ;
	{

		for ( int i = 0; i  < d; i++ )
		{
			for ( int j = 0; j < d; j++ )
			{
				std::cout << a[i][j] << ' ';
			}
			std::cout << std::endl;
		}
	}

	clearMatrix( &a, d );

	return 0;
}
Last edited on
Also as you have already a function displaying the matrix then you can rewrite the previos test program the following way



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include <fstream>
#include <string>

int readData( const std::string &fileName, int *** matrix  )
{
	std::ifstream inFile( fileName ) ;

	if ( !inFile )
	{
		cout<<"\nFile does'nt exist\n"<<endl;
		return ( 0 );
	}

	int dimension = 0;

	inFile >> dimension;
	
	*matrix = new int *[dimension];

	for ( int r = 0; r < dimension; r++ )
	{
		( *matrix )[r] = new int[dimension];
	}

	for ( int r = 0; r < dimension; r++ )// row loop
	{
		  for ( int c = 0; c < dimension; c++ )  // column loop
		  {
			inFile >>( *matrix )[r][c]; // read data into matrix
		  }
	}
	
	return ( dimension );
}

void Display( int **matrix, int dimension ) // display matrix
{ 
	std::cout << " Magic Square Program " << std::endl << std::endl;

	for ( int r = 0; r < dimension; r++ )
 	{ 
		for ( int c = 0; c < dimension; c++ )
		{
			std::cout << matrix[r][c] <<"\t";  // display numbers
		} 
		std::cout << std::endl;
	}
}

void clearMatrix( int ***matrix, int dimension )
{
	if ( *matrix )
	{
		for ( int i = 0; i < dimension; i++ ) delete [] ( *matrix )[i];
		delete [] *matrix;
		*matrix = 0;
	}
}

int main()
{
	int **a = 0;
	std::string fileName( "wendy.txt" );
	int d = readData( fileName, &a );

	if ( d != 0 ) Display( a, d );

	clearMatrix( &a, d );

	return 0;
}
 
Last edited on


@vlad .

thanks for your help and currently my code are working fine..
it can read the file and I can use the function to compare whether is magic square or not already =) . it too hard for me.. by the way..

can you give me some explanation beside the code? for

why you use
 
*** int matrix 


and which line are you using that READ from the text file and can save back to the 2d dimension array?

Consider a simple example

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

void f( int x ) { x = 20; }

int main()
{
   int x = 10;
   
   std::cout << "Before f( x ) x = " << x << std::endl;
   f( x );
   std::cout << "Before f( x ) x = " << x << std::endl;
}


In the example value of x was not changed after calling f.

Now consider a lightly updated example.

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

void f( int *x ) { *x = 20; }

int main()
{
   int x = 10;
   
   std::cout << "Before f( x ) x = " << x << std::endl;
   f( &x );
   std::cout << "Before f( x ) x = " << x << std::endl;
}


In this example the value of x was changed after calling f.

The same is valid for the declaration

int **a;

Inside readData the value of 'a' must be changed because we always allocate the memory anew every time the function is called. So 'a' is passed to function by reference that is by using pointer. If 'a' itself would be passed to the function then a local copy of 'a' would be created inside the function body and after exiting the function this local copy would be destroyed. So the original value of 'a' would not be changed. In general when a pointer to object is passed a local copy of it is created in a called function. But we change not the pointer iteslf but the object that is referenced by the pointer. After exiting the function local copy of the pointer is destroyed however the object pointer by the pointer will keep its new value because we directly assign to it a new value not to its copy. One more consider the first example with int x.

I have not understood the second your question.
Last edited on
Topic archived. No new replies allowed.