How can I pass a multidimensional array as a ref parameter in func

G

Guest

Here is a code sample ...

int blah = ReadFile( defArray[,], defFileName, w, h);

// Read File Contents into memory array and return for processing
public int ReadFile( ref ushort[,] nArray, string sFname, int w, int h)
{
FileStream fs = new FileStream(sFname, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
// Read data
for (int y=0; y<h; y++)
{
for (int x=0; x<w; x++)
{
nArray[x,y] = br.ReadUInt16();
}
}
br.Close();
fs.Close();
return 0;
}

Can anyone help get this to work and compile ???

THX greg
 
J

Jon Skeet [C# MVP]

vmsgman said:
Here is a code sample ...

int blah = ReadFile( defArray[,], defFileName, w, h);

// Read File Contents into memory array and return for processing
public int ReadFile( ref ushort[,] nArray, string sFname, int w, int h)
{
FileStream fs = new FileStream(sFname, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
// Read data
for (int y=0; y<h; y++)
{
for (int x=0; x<w; x++)
{
nArray[x,y] = br.ReadUInt16();
}
}
br.Close();
fs.Close();
return 0;
}

Can anyone help get this to work and compile ???

You pass arrays by reference in exactly the same way as you pass
anything else by reference:

int blah = ReadFile (ref defArray, defFileName, w, h);

However, it seems to me that it would be more appropriate as a return
value in the above - it's the result of reading the file, and currently
you're just returning 0. If that's meant to be a status code, you
should consider using exceptions for indicating errors.

You should also use "using" blocks (or their equivalent, try/finally
blocks) to make sure that files get closed whether or not an exception
is thrown.
 
R

Robbe Morris [C# MVP]

int blah = ReadFile( ref defArray, defFileName, w, h);

As a side note, why would you make defArray
an input parameter by "ref". Is there a reason you
don't make ReadFile return the byte[]?

Then, check for null on the byte[] for success.


--
2004 and 2005 Microsoft MVP C#
Robbe Morris
http://www.masterado.net

Earn $$$ money answering .NET Framework
messageboard posts at EggHeadCafe.com.
http://www.eggheadcafe.com/forums/merit.asp
 
A

AHN

Arrays are always passed by reference even if you omit 'ref' before the
argument. Array's name is its address.

vmsgman said:
Here is a code sample ...

int blah = ReadFile( defArray[,], defFileName, w, h);

// Read File Contents into memory array and return for processing
public int ReadFile( ref ushort[,] nArray, string sFname, int w, int h)
{
FileStream fs = new FileStream(sFname, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
// Read data
for (int y=0; y<h; y++)
{
for (int x=0; x<w; x++)
{
nArray[x,y] = br.ReadUInt16();
}
}
br.Close();
fs.Close();
return 0;
}

Can anyone help get this to work and compile ???

You pass arrays by reference in exactly the same way as you pass
anything else by reference:

int blah = ReadFile (ref defArray, defFileName, w, h);

However, it seems to me that it would be more appropriate as a return
value in the above - it's the result of reading the file, and currently
you're just returning 0. If that's meant to be a status code, you
should consider using exceptions for indicating errors.

You should also use "using" blocks (or their equivalent, try/finally
blocks) to make sure that files get closed whether or not an exception
is thrown.
 
A

AHN

Try this
int blah = ReadFile( defArray, defFileName, w, h);

Here is a code sample ...

int blah = ReadFile( defArray[,], defFileName, w, h);

// Read File Contents into memory array and return for processing
public int ReadFile( ref ushort[,] nArray, string sFname, int w, int h)
{
FileStream fs = new FileStream(sFname, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
// Read data
for (int y=0; y<h; y++)
{
for (int x=0; x<w; x++)
{
nArray[x,y] = br.ReadUInt16();
}
}
br.Close();
fs.Close();
return 0;
}

Can anyone help get this to work and compile ???

THX greg
 
J

Jon Skeet [C# MVP]

AHN said:
int blah = ReadFile( defArray, defFileName, w, h);

No, that won't compile, because the first parameter needs to be passed
by reference, so needs the "ref" modifier.
 
A

AHN

That compiles and works. Just try. Array variable is the pointer to the
address. So when you give it as argument, anithing done to it in the
function body is done to the array itself. No 'ref' is needed. Ref is needed
if your variable is not a reference type. Array is a reference type. Cheers.

AHN said:
int blah = ReadFile( defArray, defFileName, w, h);

No, that won't compile, because the first parameter needs to be passed
by reference, so needs the "ref" modifier.
 
J

Jon Skeet [C# MVP]

AHN said:
That compiles and works. Just try.

I have. Have you? Try compiling the following, and watch it fail.

using System;

public class Test
{
static int ReadFile(ref ushort[,] nArray,
string sFname, int w, int h)
{
// Implementation skipped
return 0;
}

static void Main()
{
ushort[,] defArray = null;
string defFileName = null;
int w = 0;
int h = 0;
int blah = ReadFile( defArray, defFileName, w, h);
}
}

I get the following with 2.0 beta 2:

Test.cs(18,20): error CS1502: The best overloaded method match for
'Test.ReadFile(ref ushort[*,*], string, int, int)' has some invalid
arguments
Test.cs(18,30): error CS1620: Argument '1' must be passed with the
'ref' keyword

And this with 1.1:
Test.cs(17,20): error CS1502: The best overloaded method match for
'Test.ReadFile(ref ushort[*,*], string, int, int)' has some
invalid arguments
Test.cs(17,30): error CS1503: Argument '1': cannot convert from 'ushort
[*,*]' to 'ref ushort[*,*]'

Both seem reasonably clear to me.
Array variable is the pointer to the address. So when you give it as
argument, anithing done to it in the function body is done to the
array itself.

Changes to the value of the parameter itself, however (rather than the
array it references) will not be visible to the caller unless the
parameter is passed by reference.
No 'ref' is needed. Ref is needed if your variable is not a reference
type. Array is a reference type. Cheers.

I'm sorry, but you clearly don't understand what "ref" actually means.

Once again, please read
http://www.pobox.com/~skeet/csharp/parameters.html
 
A

AHN

Try to compile this one. Before accusing me of not understanding see if you
understand what you're talking about.
Cheers.
-----------------------------------------------
<code>
using System;
namespace refArray
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
private static int[,] intArr = new int[2,3];
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
intArr[0,1] = 44;
int result = RefArray( intArr );
Console.WriteLine( result.ToString() );
}
public static int RefArray( int[,] refarr ) {
refarr[0,1] = 99;
return refarr[0,1];
}
}
}
</code>
---------------------------------

AHN said:
That compiles and works. Just try.

I have. Have you? Try compiling the following, and watch it fail.

using System;

public class Test
{
static int ReadFile(ref ushort[,] nArray,
string sFname, int w, int h)
{
// Implementation skipped
return 0;
}

static void Main()
{
ushort[,] defArray = null;
string defFileName = null;
int w = 0;
int h = 0;
int blah = ReadFile( defArray, defFileName, w, h);
}
}

I get the following with 2.0 beta 2:

Test.cs(18,20): error CS1502: The best overloaded method match for
'Test.ReadFile(ref ushort[*,*], string, int, int)' has some invalid
arguments
Test.cs(18,30): error CS1620: Argument '1' must be passed with the
'ref' keyword

And this with 1.1:
Test.cs(17,20): error CS1502: The best overloaded method match for
'Test.ReadFile(ref ushort[*,*], string, int, int)' has some
invalid arguments
Test.cs(17,30): error CS1503: Argument '1': cannot convert from 'ushort
[*,*]' to 'ref ushort[*,*]'

Both seem reasonably clear to me.
Array variable is the pointer to the address. So when you give it as
argument, anithing done to it in the function body is done to the
array itself.

Changes to the value of the parameter itself, however (rather than the
array it references) will not be visible to the caller unless the
parameter is passed by reference.
No 'ref' is needed. Ref is needed if your variable is not a reference
type. Array is a reference type. Cheers.

I'm sorry, but you clearly don't understand what "ref" actually means.

Once again, please read
http://www.pobox.com/~skeet/csharp/parameters.html
 
A

AHN

This way is more instructive?
---------------------------------------
<code>
using System;
namespace refArray
{
class Class1
{
private static int[,] intArr = new int[2,3];
[STAThread]
static void Main(string[] args)
{
intArr[0,1] = 44;
int result = RefArray( intArr );
Console.WriteLine( intArr[0,1] );
}
public static int RefArray( int[,] refarr ) {
refarr[0,1] = 99;
return refarr[0,1];
}
}
}
</code>
---------------------------------
Other reference types are *class, interface, delegate, object, string*.
Array is not in the list because there's no array type in C# (you define
double[], bool[], string[,] etc.). When you pass an *instance* of any of
those types as argument, 'ref' is irrelevant.

Try to compile this one. Before accusing me of not understanding see if you
understand what you're talking about.
Cheers.
-----------------------------------------------
<code>
using System;
namespace refArray
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
private static int[,] intArr = new int[2,3];
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
intArr[0,1] = 44;
int result = RefArray( intArr );
Console.WriteLine( result.ToString() );
}
public static int RefArray( int[,] refarr ) {
refarr[0,1] = 99;
return refarr[0,1];
}
}
}
</code>
---------------------------------

AHN said:
That compiles and works. Just try.

I have. Have you? Try compiling the following, and watch it fail.

using System;

public class Test
{
static int ReadFile(ref ushort[,] nArray,
string sFname, int w, int h)
{
// Implementation skipped
return 0;
}

static void Main()
{
ushort[,] defArray = null;
string defFileName = null;
int w = 0;
int h = 0;
int blah = ReadFile( defArray, defFileName, w, h);
}
}

I get the following with 2.0 beta 2:

Test.cs(18,20): error CS1502: The best overloaded method match for
'Test.ReadFile(ref ushort[*,*], string, int, int)' has some invalid
arguments
Test.cs(18,30): error CS1620: Argument '1' must be passed with the
'ref' keyword

And this with 1.1:
Test.cs(17,20): error CS1502: The best overloaded method match for
'Test.ReadFile(ref ushort[*,*], string, int, int)' has some
invalid arguments
Test.cs(17,30): error CS1503: Argument '1': cannot convert from 'ushort
[*,*]' to 'ref ushort[*,*]'

Both seem reasonably clear to me.
Array variable is the pointer to the address. So when you give it as
argument, anithing done to it in the function body is done to the
array itself.

Changes to the value of the parameter itself, however (rather than the
array it references) will not be visible to the caller unless the
parameter is passed by reference.
No 'ref' is needed. Ref is needed if your variable is not a reference
type. Array is a reference type. Cheers.

I'm sorry, but you clearly don't understand what "ref" actually means.

Once again, please read
http://www.pobox.com/~skeet/csharp/parameters.html
 
J

Jon Skeet [C# MVP]

AHN said:
Try to compile this one. Before accusing me of not understanding see if you
understand what you're talking about.

I do. Note that *your* method declaration didn't contain the "ref"
modifier. That's why it compiles.

Now look at the declaration of the method which the OP was trying to
call. Spot the difference? The way you provided in your "try this" post
would *not* compile.

Now, have you read the article I refered you to, which explains the
difference between a parameter being passsed *by* reference and a
reference itself being passed by value?

When you said "That compiles and works" after I'd said it didn't, had
you actually tried it? In particular, had you tried to compile it
against the method declaration that the OP had provided, rather than
your own?
 
N

Nigel Norris

AHN,

Some friendly advice.You're wrong. Jon understands C# way better than you
do - why don't you just go and read the excellent article he wrote that will
help you understand exactly why.

Cheers...

AHN said:
This way is more instructive?
---------------------------------------
<code>
using System;
namespace refArray
{
class Class1
{
private static int[,] intArr = new int[2,3];
[STAThread]
static void Main(string[] args)
{
intArr[0,1] = 44;
int result = RefArray( intArr );
Console.WriteLine( intArr[0,1] );
}
public static int RefArray( int[,] refarr ) {
refarr[0,1] = 99;
return refarr[0,1];
}
}
}
</code>
---------------------------------
Other reference types are *class, interface, delegate, object, string*.
Array is not in the list because there's no array type in C# (you define
double[], bool[], string[,] etc.). When you pass an *instance* of any of
those types as argument, 'ref' is irrelevant.

Try to compile this one. Before accusing me of not understanding see if
you
understand what you're talking about.
Cheers.
-----------------------------------------------
<code>
using System;
namespace refArray
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
private static int[,] intArr = new int[2,3];
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
intArr[0,1] = 44;
int result = RefArray( intArr );
Console.WriteLine( result.ToString() );
}
public static int RefArray( int[,] refarr ) {
refarr[0,1] = 99;
return refarr[0,1];
}
}
}
</code>
---------------------------------

AHN said:
That compiles and works. Just try.

I have. Have you? Try compiling the following, and watch it fail.

using System;

public class Test
{
static int ReadFile(ref ushort[,] nArray,
string sFname, int w, int h)
{
// Implementation skipped
return 0;
}

static void Main()
{
ushort[,] defArray = null;
string defFileName = null;
int w = 0;
int h = 0;
int blah = ReadFile( defArray, defFileName, w, h);
}
}

I get the following with 2.0 beta 2:

Test.cs(18,20): error CS1502: The best overloaded method match for
'Test.ReadFile(ref ushort[*,*], string, int, int)' has some invalid
arguments
Test.cs(18,30): error CS1620: Argument '1' must be passed with the
'ref' keyword

And this with 1.1:
Test.cs(17,20): error CS1502: The best overloaded method match for
'Test.ReadFile(ref ushort[*,*], string, int, int)' has some
invalid arguments
Test.cs(17,30): error CS1503: Argument '1': cannot convert from 'ushort
[*,*]' to 'ref ushort[*,*]'

Both seem reasonably clear to me.
Array variable is the pointer to the address. So when you give it as
argument, anithing done to it in the function body is done to the
array itself.

Changes to the value of the parameter itself, however (rather than the
array it references) will not be visible to the caller unless the
parameter is passed by reference.
No 'ref' is needed. Ref is needed if your variable is not a reference
type. Array is a reference type. Cheers.

I'm sorry, but you clearly don't understand what "ref" actually means.

Once again, please read
http://www.pobox.com/~skeet/csharp/parameters.html
 
J

Jon Skeet [C# MVP]

AHN said:
This way is more instructive?

Not really - it's still passing an array reference by value, rather
than passing an array reference *by* reference, which is what the OP's
method is declared to take. (The OP's method implementation doesn't
actually require the parameter to be passed by reference, but the
declaration does.)
Other reference types are *class, interface, delegate, object, string*.
Array is not in the list because there's no array type in C# (you define
double[], bool[], string[,] etc.).

There's no need for "string" to be in there either, as a string is an
object too. (There *is* a System.Array class, by the way.)
When you pass an *instance* of any of those types as argument, 'ref'
is irrelevant.

If that were true, the following programs would give the same result.
They don't. So no, I still don't think you know what you're talking
about.

First, passing a string parameter by value:

using System;

class Test
{
static void Main()
{
string x = "Bar";
Foo(x);
Console.WriteLine(x); // Prints "Bar"
}

static void Foo (string x)
{
x = "Foo";
}
}

Second, passing the string parameter by reference:

using System;

class Test
{
static void Main()
{
string x = "Bar";
Foo(ref x);
Console.WriteLine(x); // Prints "Foo"
}

static void Foo (ref string x)
{
x = "Foo";
}
}

The result of the first program is "Bar" and the result of the second
program is "Foo". The only difference is in whether the parameter to
"Foo" is passed by reference or not.

Of course, all this is explained in the article I've referred you to
several times now. I can only assume that you still haven't read it.
 
G

Guest

Hello Jon, AHN, Nigel

I really appreciate your willingness to help, I went and read the articles
the Jon wrote. I while I think it will need a little time to gel I think I
have the basic idea.

I revised my code and am still having problems I am including all you will
need to tell what my misunderstanding is ...

using System;
using System.IO;

namespace LineTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
const int w = 1024, h = 768;
ushort[,] defArry = new ushort[w,h];

string sn = "6212-06"; // Change to arg[0] after testing

string sFilePath = @"C:\Program Files\Varian\Systems\";
sFilePath += (sn + @" HMC\");
sFilePath += @"Receptor Test Data\";

string sDefFile = sFilePath + @"Defect Maps\lnnf_G4_defect_map.raw";

defArry = FileToArray( sDefFile );
}

public ushort[,] FileToArray( string sFileName )
{
const int w = 1024, h = 768;
ushort[,] tmpArry = new ushort[w,h];

using (FileStream fs = new FileStream(sFileName,
FileMode.Open, FileAccess.Read))
{
using (BinaryReader br = new BinaryReader(fs))
{
for (int y=0; y<h; y++)
{
for (int x=0; x<w; x++)
{
tmpArry[x,y] = br.ReadUInt16();
}
}
}
}
return tmpArry;
}

}
}



I thank you again in advance and hopefully this will help others with the
same misunderstanding. I am getting compiler error
LineTest\LineTest\Class1.cs(28): An object reference is required for the
nonstatic field, method, or property 'LineTest.Class1.FileToArray(string)'
 
J

Jon Skeet [C# MVP]

vmsgman said:
I really appreciate your willingness to help, I went and read the articles
the Jon wrote. I while I think it will need a little time to gel I think I
have the basic idea.

I revised my code and am still having problems I am including all you will
need to tell what my misunderstanding is ...

Okay, here are some of the problems:

1) You're currently creating a new array and setting the value of
defArry to that, and then ignoring that value completely, setting the
value to the return value of FileToArray. Just write:

ushort[,] defArry = FileToArray (sDefFile);

as your last line - you don't use the variable before then, so you
might as well declare it there.


2) You'd be wise to use Path.Combine to combine your filenames rather
than getting the right number of backslashes on yourself. It will also
help to make the code portable if you ever need to make your code work
on Unix.


3) You're calling an instance method (FileToArray) from a static method
(Main) without there being an instance of the class (Class1) to call
the method on. In this case, as the method doesn't really have anything
to do with any particular instance, it would be easiest to make the
method static. You should read up on what static means though - it's
very important to understand it.>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top