PDA

View Full Version : C++ Problem with passing arrays as arguments



jdunn
November 17th, 2009, 07:43 PM
I'm fairly new to C++ and haven't gotten used to memory allocation yet. I wrote a small program that reads a file (one-line at a time) as a string and parses data from it into 2-dimensional arrays of different sizes. Then another function (I call it "foo" here) takes each array as an argument and performs calculations. The program works as expected when compiling and running with GNU G++ in linux. However, the same simple program crashes or produces weird results with MingW or Visual C++ (in Vista). I suspect I'm doing something wrong with the memory allocation here. help.



#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

class Assemble
{
public:
string s;
int lnum;


int** A;
int** T;

void readfile()
{
ifstream in("input.txt");
getline(in, s);
stringstream ss(s);
ss >> lnum;

A = new int*[3];
T = new int*[3];

for (int j = 0; j <= lnum; j++)
A[j] = new int[3];
for (int j = 0; j < lnum; j++)
T[j] = new int[3];

parser(lnum, A, 1);
parser(lnum, A, 2);
parser(lnum - 1, T, 1);
parser(lnum - 1, T, 2);

foo(lnum, A, 1);
foo(lnum, A, 2);
foo(lnum - 1, T, 1);
foo(lnum - 1, T, 2);
}

void parser(int arsize, int** GenAr, int i)
{
// data gets parsed from string and stored in array
}

void foo(int arsize, int** GenAr, int i)
{
// crash occurs when calling this function
}

b&m
November 17th, 2009, 08:18 PM
Try with

for (int j = 0; j < lnum; j++)

instead of

for (int j = 0; j <= lnum; j++)

;)

jdunn
November 17th, 2009, 08:31 PM
Try with

for (int j = 0; j < lnum; j++)

instead of

for (int j = 0; j <= lnum; j++)

;)

The Array A is has one more column than Array T...Two two-dimensional arrays of different sizes. This is also why the function calls use slightly different arguments. Also, I'm not using index 0 in the arrays...I'm using 1 to lnum for A and 1 to (lnum - 1) for T.

b&m
November 17th, 2009, 08:45 PM
Try

foo(lnum, A, 2);

instead of

foo(lnumm, A, 2);

jdunn
November 17th, 2009, 08:50 PM
Try

foo(lnum, A, 2);

instead of

foo(lnumm, A, 2);

Oops. Thanks. However, that was not an error in my actual code. It was an error in my edit after cut&paste. Should be fixed now.

Arndt
November 17th, 2009, 08:52 PM
The Array A is has one more column than Array T...Two two-dimensional arrays of different sizes. This is also why the function calls use slightly different arguments. Also, I'm not using index 0 in the arrays...I'm using 1 to lnum for A and 1 to (lnum - 1) for T.

Maybe you should run the program with 'valgrind'. It shows all memory errors, not only those which immediately cause a crash.

Arndt
November 17th, 2009, 09:02 PM
I'm fairly new to C++ and haven't gotten used to memory allocation yet. I wrote a small program that reads a file (one-line at a time) as a string and parses data from it into 2-dimensional arrays of different sizes. Then another function (I call it "foo" here) takes each array as an argument and performs calculations. The program works as expected when compiling and running with GNU G++ in linux. However, the same simple program crashes or produces weird results with MingW or Visual C++ (in Vista). I suspect I'm doing something wrong with the memory allocation here. help.



#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

class Assemble
{
public:
string s;
int lnum;


int** A;
int** T;

void readfile()
{
ifstream in("input.txt");
getline(in, s);
stringstream ss(s);
ss >> lnum;

A = new int*[3];
T = new int*[3];

for (int j = 0; j <= lnum; j++)
A[j] = new int[3];
for (int j = 0; j < lnum; j++)
T[j] = new int[3];

parser(lnum, A, 1);
parser(lnum, A, 2);
parser(lnum - 1, T, 1);
parser(lnum - 1, T, 2);

foo(lnum, A, 1);
foo(lnum, A, 2);
foo(lnum - 1, T, 1);
foo(lnum - 1, T, 2);
}

void parser(int arsize, int** GenAr, int i)
{
// data gets parsed from string and stored in array
}

void foo(int arsize, int** GenAr, int i)
{
// crash occurs when calling this function
}


Are you sure the crash occurs when foo is called, and not inside foo? Can you remove some foo calls and still get the crash?

jdunn
November 17th, 2009, 09:05 PM
Maybe you should run the program with 'valgrind'. It shows all memory errors, not only those which immediately cause a crash.

sounds interesting. I'll keep it in mind but installing extra software is not going to be one of my first options to fix this. Is GenAr not getting deallocated? I figured once outside the function, GenAr is out of scope.

jdunn
November 18th, 2009, 01:19 AM
There is info on the web and my book about dynamic memory allocation for arrays but none for multi-dim arrays. I had a friend look at my code and point out the errors. It is now fixed. This is how the code reads now:



A = new int*[3];
T = new int*[3];

for (int j = 0; j <= 2; j++)
A[j] = new int[lnum];
for (int j = 0; j <= 2; j++)
T[j] = new int[lnum - 1];

dwhitney67
November 18th, 2009, 02:05 AM
There is info on the web and my book about dynamic memory allocation for arrays but none for multi-dim arrays. I had a friend look at my code and point out the errors. It is now fixed. This is how the code reads now:



A = new int*[3];
T = new int*[3];

for (int j = 0; j <= 2; j++)
A[j] = new int[lnum];
for (int j = 0; j <= 2; j++)
T[j] = new int[lnum - 1];

It's too bad your friend was not able to point out that you could combine the initialization steps.


for (int j = 0; j < 3; ++j)
{
A[j] = new int[lnum];
T[j] = new int[lnum - 1];
}

Also, too bad that your friend could not have persuaded you to use variables names that are more descriptive.

jdunn
November 18th, 2009, 10:26 PM
It's too bad your friend was not able to point out that you could combine the initialization steps.


for (int j = 0; j < 3; ++j)
{
A[j] = new int[lnum];
T[j] = new int[lnum - 1];
}

Also, too bad that your friend could not have persuaded you to use variables names that are more descriptive.

A) I already cleaned up my code, just not for you.
B) I use plenty of comments when variable names aren't so "descriptive" but I often omit them when posting my code on a forum.

TennTux
November 19th, 2009, 07:21 AM
In your original code you had:


A = new int*[3];
T = new int*[3];

for (int j = 0; j <= lnum; j++)
A[j] = new int[3];
for (int j = 0; j < lnum; j++)
T[j] = new int[3];

The initialization of A and T suggests that A and T have three elements each, however, you loop from 0 to lnum which suggests A has lnum+1 elements and T has lnum elements. And each element is an array of three elements Thus you really wanted something like:


A = new int*[lnum+1] ;
T = new int*[lnum] ;
for (int j = 0; j <= lnum; j++)
A[j] = new int[3];
for (int j = 0; j < lnum; j++)
T[j] = new int[3];

However, dwhitney67 has correctly provided the complement where A and T each have exactly 3 elements and each element is an array of lnum+1 or lnum elements. As below:


A = new int*[3] ;
T = new int*[3] ;
for (int j = 0; j < 3; j++)
A[j] = new int[lnum+1];
for (int j = 0; j < 3; j++)
T[j] = new int[lnum];

Which one is correct depends on what you are trying to do.

On the larger issue you may want to think about using a typedef to simplify things. For example:


typedef int* SubArray ;
SubArray* A = new SubArray[3];
SubArray* T = new SubArray[3] ;

or possibly


typedef int[3] SubArray3 ;
SubArray3* A = new SubArray[lnum+1] ;
SubArray3* T = new SubArray[lnum] ;

By using the typedef it starts you thinking of the SubArray as its own type and can help keep the parts separate in your mind. But that's my opinion. :)