How do I pass an array of strings to a function? ???
String foo[10];
//Fill the array....
sub myFunc(string in[]), int
{
//...
return;
}
myFunc(foo[]) ; <----------- ??? ??? ???
Leave the brackets out.
The first part is fine, but call it like
myFunc(foo);
Aurora doesn't check bounds though, so it's a good idea to pass a parameter telling how many items there are so you don't try to read unowned memory.
Thank's Parker
You mean something like this:
int num;
num = 10;
String foo[num];
//Fill the array....
sub myFunc(string in[], int num), int
{
//...
return;
}
myFunc(foo, num) ;
;D Kind of.
Now the first part isn't quite right. You have to know the size of the array at compile time. If you want to use a constant, you can do that.
const num = 10;
string foo[num];
sub myFunc(string in[], int num)
{
for (i = 0; i < num; i++)
{
in = num;
}
}
myFunc(foo, num);
would work.
my understanding is that in:
const num = 10;
string foo[num];
"foo" is a pointer to the first element in the array foo[] so what you are doing is using a pointer. That's why you need to tell the function how many elements you have. Of course you could include an extra (final) element which is null and test for it in the function.
Thank's for the answers but as usuall answers gives more questions ;).
Why:
const num = 10;
why not:
int num;
num = 10;
???
Is there any important difference?
Becuase arrays are defined by constants. The size of an array needs to be known by the compiler at compile time, and not run time.
Ah, I see (I think :P)
Thank's
Lasse
Quote from: lviklund on February 25, 2006, 06:44:54 AM
Ah, I see (I thinkÂÃ, :P)
Thank's
Lasse
Constants are defined immediately as the compile progresses so the compiler knows the value when it encounters the array definition.
int num=10;
is not set until the program actually executes which is too late as array dimensions are fixed when the program is compiled.
One can either create an array to hold the largest possible number of elements (which can waste space) or use a linked list.
The compiler needs to know an arrays number of elements at compile time.
string foo[10];
or
const num = 10; // complier knows num is 10
string foo[num];
For dynamic arrays (where you can vary the number of elements), you use 'new' and 'delete' to allocate and deallocate memory dynamically (on the fly) . In C++ you could write ( with floats ) :
int num = 10; // a variable that compiler does not know the value
// of at compile time, only at runtime is it known
float *foo = new float[num]; // memory is allocated at runtime for pointer of len(float*num)
if (!foo) // check if foo fails to be allocated
{
cout << "there is insufficient memory for foo \n";
}
else
{
.
. // do somesthing with foo[]
.
delete foo; // always free up the memory used with new
}
I'm reading all of Paul's stuff to see how this is written in Aurora.
In Aurora that's written
int num=10;
float *foo = new(float, num);
if (foo = NULL)
writeln("there is insufficient memory for foo\n")
else
delete foo;
I'm not quite sure if a block if needs to be used when a block else is... in C/C++ there are no "block if"s, { statement list } is included in the definition for statement so you can do all kinds of crazy stuff ;)
thanks Parker, I just found the new () function and was trying it out. my example barfed on the the if (!foo) and then on other statements using floats so I went to doubles.
I ran this and I'm getting the same numbers each time. I know I'm reading memory. I guess because it is uninitialized those are bits of data in memory left over from something else. I'm going try un-commenting the assignment line after I send this post in case some bad happens.
edit: I un-comment that assignment line, but I get an error: "...\dynamic_array.src (23) Invalid assignment"
// dynamic_array.src
global sub main ()
{
int num = 10; // a variable that compiler does not know the value
// of at compile time, only at runtime is it known
double *foo = new ( double, num+1); // memory is allocated at runtime for pointer of len(double*num)
if ( foo = NULL ) // check if foo fails to be allocated
{
writeln ("there is insufficient memory for foo");
}
else
{
writeln("there is sufficient memory for foo\n");
writeln("a double variable is " + numtostr( len ( double ) ) + " bytes long\n" );
writeln("the length of foo in memory " + numtostr( len ( double ) * num ) + " bytes long\n\n" );
double nn = 0;
for ( int n = 0; n <= num; n++ )
{
nn = nn+1.0;
foo[n] = sqrt(nn) + 1.0; // fill foo[] a value
writeln(numtostr( foo[n] ) + "\n" ); // show foo's values
}
delete foo; // always free up the memory used with new
}
while (GetKey() = "");
return;
}
You should be getting the numbers, if not something's wrong and your computer can't decide on how long a double type should be ;)
To print the address of the pointer, try this:
writeln( "The address of foo is " + NumToStr( foo ) + "\n" );
foo contains an address, *foo contains a value. And len( double ) * num will always return 80, the size of 10 doubles.
:( for some reason it wants to treat foo[] as an array of int. When I change the assignment line to read: foo[n] = n; I get only two values
??? I rewrote the code and got this scary error message:
Compiling...
dynamic_array.src
File: D:\...l\dynamic_array.src (21) Warning: Temporary string assigned to POINTER, possible memory loss
File: D:\...l\dynamic_array.src (22) illegal operand
Error(s) in compiling D:\...l\dynamic_array.src
edit: I'm already suffering hair loss and hearing loss. Now my memory too!
// dynamic_array.src
global sub main ()
{
int num = 4; // a variable that compiler does not know the value
// of at compile time, only at runtime is it known
string *foo = new ( string, num + 1 ); // memory is allocated at runtime for pointer of len(string*num)
if ( foo = NULL ) // check if foo fails to be allocated
{
writeln ("there is insufficient memory for foo");
}
else
{
writeln("there is sufficient memory for foo\n");
writeln("a string variable is " + numtostr( len ( string ) ) + " bytes long\n" );
writeln("the length of foo in memory " + numtostr( len ( string ) * num ) + " bytes long\n\n" );
for ( int n = 0; n <= num; n++ )
{
foo[n] = numtostr( n ); // fill foo[] a value
writeln( foo[n] + "\n" ); // show foo's values
}
delete foo; // always free up the memory used with new
}
while (GetKey() = "");
return;
}
Try this:
// ÂÃ, dynamic_array.src
ÂÃ, global sub main ()
ÂÃ, {
ÂÃ, Ã‚Ã, int num = 10; ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, // a variable that compiler does not know the value
ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, // of at compile time, only at runtime is it known
ÂÃ, Ã‚Ã, double *foo = new ( double, num+1); ÂÃ, // memory is allocated at runtime for pointer of len(double*num)
ÂÃ, Ã‚Ã, if ( foo = NULL ) ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, // check if foo fails to be allocated
ÂÃ, Ã‚Ã, Ã‚Ã, {
ÂÃ, Ã‚Ã, Ã‚Ã, writeln ("there is insufficient memory for foo");
ÂÃ, Ã‚Ã, Ã‚Ã, }
ÂÃ, Ã‚Ã, else
ÂÃ, Ã‚Ã, Ã‚Ã, {
ÂÃ, Ã‚Ã, Ã‚Ã, writeln("there is sufficient memory for foo\n");
ÂÃ, Ã‚Ã, Ã‚Ã, writeln("a double variable is ÂÃ, " + numtostr( len ( double ) ) + " bytes long\n" );
ÂÃ, Ã‚Ã, Ã‚Ã, writeln("the length of foo in memory " + numtostr( len ( double ) * num ) + " bytes long\n\n" );
ÂÃ, Ã‚Ã, Ã‚Ã, double nn = 0;
ÂÃ, Ã‚Ã, Ã‚Ã, for ( int n = 0; n <= num; n++ )
ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, {
ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, nn = nn+1.0;
ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, *foo[n] = sqrt(nn); ÂÃ, // fill foo[] a value
ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, writeln(numtostr(nn)+" ÂÃ, "+numtostr( *foo[n],4 ) + "\n" ); // show foo's values
ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, }
ÂÃ, Ã‚Ã, Ã‚Ã, delete foo; ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, // always free up the memory used with new
ÂÃ, Ã‚Ã, Ã‚Ã, }
ÂÃ, Ã‚Ã, while (GetKey() = "");
ÂÃ, Ã‚Ã, return;
ÂÃ, }
Thanks Peaslee, that did the trick. I tweaked your code a little:
// dynamic_array.src
global sub main ()
{
int num = 4; // a variable that compiler does not know the value
// of at compile time, only at runtime is it known
double *foo = new ( double, num+1); // memory is allocated at runtime for pointer of len(double*num)
if ( foo = NULL ) // check if foo fails to be allocated
{
writeln ("there is insufficient memory for foo");
}
else
{
writeln("there is sufficient memory for foo\n");
writeln("a double variable is " + numtostr( len ( double ) ) + " bytes long\n" );
writeln("the length of foo in memory should be " + numtostr( len ( double ) * num ) + " bytes long\n\n" );
writeln("the length of foo in memory is " + numtostr( foo ) + " bytes long\n\n" );
for ( int n = 0; n <= num; n++ )
{
*foo[n] = 10^n; // fill foo[] a value
writeln(numtostr(n)+" "+numtostr( *foo[n],4 ) + "\n" ); // show foo's values
}
delete foo; // always free up the memory used with new
}
while (GetKey() = "");
return;
}
here's the output I got. Notice the size of foo when I try to read it directly with len.
there is sufficient memory for foo
a double variable is 8 bytes long
the length of foo in memory should be 32 bytes long
the length of foo in memory is 1335440 bytes long
0 1.0000
1 10.0000
2 100.0000
3 1000.0000
4 10000.0000
I'm pretty sure numtostr(len(foo)) is returning the address in foo
I got the example to work with bytes as well:
// dynamic_byte_array.src
global sub main ()
{
int num = 4; // a variable that compiler does not know the value
// of at compile time, only at runtime is it known
byte *foo = new ( byte, num+1); // memory is allocated at runtime for pointer of len(byte*num)
if ( foo = NULL ) // check if foo fails to be allocated
{
writeln ("there is insufficient memory for foo");
}
else
{
writeln("there is sufficient memory for foo\n");
writeln("a byte variable is " + numtostr( len ( byte ) ) + " bytes long\n" );
writeln("the length of foo in memory should be " + numtostr( len ( byte ) * num ) + " bytes long\n\n" );
writeln("the length of foo in memory is " + numtostr( foo ) + " bytes long\n\n" );
for ( int n = 0; n <= num; n++ )
{
*foo[n] = numtostr(2*n); // fill foo[] a value
writeln(numtostr(n)+" "+ *foo[n] + "\n" ); // show foo's values
}
delete foo; // always free up the memory used with new
}
while (GetKey() = "");
return;
}
However, when I rewrote it for string, the output identical to that of byte (above) .
Notice that the length of string returned from numtostr( len ( string ) ) = 1 byte
I don't know what len( foo ) would be, I've never tried it. The LEN function tells the length, so it's probably 8. To get the address, just do this
writeln( NumToStr( foo ) );
since foo is a pointer. If you had just a normal float variable, you'd have to do
writeln( NumToStr( &foo ) );
Maybe this will help.
foo is a pointer (an unsigned int) so len(foo) = 4 bytes
dereference foo = *foo = *foo[0] so len(*foo) = len(*foo[0]) the number of bytes will depend upon the variable type in foo for a double that would be 8 bytes.
In your example
int num = 4
*foo = new ( double, num+1)
the amount of memory allocated for foo is 8 * 5 = 40 bytes or len(*foo)*num+1)
Earn 8)
yeah, I agree with you all but that is not what I get when you apply len(foo).
I made a feeble attempt at creating a 4x4 matrix using pointer and **foo like they show in my C++ book but it didn't work.
I did get get this to work:
// dynamic_int_matrix.src
global sub main()
{
num = 4;
int *pMatrix;
pMatrix = new( int, num*num ); // for a square matrix
if ( pMatrix = null )
{
writeln("insufficient memory\n");
}
else
{
for(int m = 0; m <= num-1; m++)
{
for(int n = 0; n <= num-1; n++)
{
*pMatrix[m][n] = (1+m)*10+n+1;
writeln( numtostr( *pMatrix[m][n] ) + " " );
}
writeln( "\n" );
}
delete pMatrix;
}
while (GetKey() = "");
return;
}
I does make a nice presentation of a matrix though ;)
As far as I know Aurora only supports 1 level of pointers. In C you can do int **x; // pointer to pointer to int
A good example is the main() function:
int main( int argc, char **argv )
You can also write it as char *argv[], they're equivalent because an array is passed by address instead of by value. It's a pointer to a character array. In Aurora we would write string argv[].
Aurora supports multiple indirection but forces typecasting on the second level.
*(string)*(pointer)p;
len(foo) won't show the size of an array allocated with NEW. NEW uses GlobalAlloc on Windows so you could use the API function GlobalSize if you needed to know the memory size of something allocated with NEW.
GlobalSize will return the size to the nearest 8 bytes, since that is how windows manages memory.
NumToStr(foo) is just returning the address stored in the pointer.
I tried the same basic format and got *pMatrix[m][n][k][l] to work I thought you could only do 3 dimensions in Aurora.
I dimensioned the vector as pMatrix[num][num][num][num]. It didn't like num^4, but it took num*num*num*num
1111 1112 1113
1121 1122 1123
1131 1132 1133
1211 1212 1213
1221 1222 1223
1231 1232 1233
1311 1312 1313
1321 1322 1323
1331 1332 1333
2111 2112 2113
2121 2122 2123
2131 2132 2133
2211 2212 2213
2221 2222 2223
2231 2232 2233
2311 2312 2313
2321 2322 2323
2331 2332 2333
3111 3112 3113
3121 3122 3123
3131 3132 3133
3211 3212 3213
3221 3222 3223
3231 3232 3233
3311 3312 3313
3321 3322 3323
3331 3332 3333
// dynamic_double_matrix.src
global sub main()
{
int num = 3;
double *pMatrix;
pMatrix = new( double, num*num*num*num );
if ( pMatrix = null )
{
writeln("insufficient memory\n");
}
else
{
for(int i = 0; i <= num-1; i++)
{
for(int j = 0; j <= num-1; j++)
{
for(int k = 0; k <= num-1; k++)
{
for(int l = 0; l <= num-1; l++)
{
*pMatrix[i][j][k][l] = (1+i)*1000+(1+j)*100+10*(k+1)+l+1;
writeln( numtostr( *pMatrix[i][j][k][l] ) + " " );
}
writeln( "\n" );
}
writeln( "\n" );
}
writeln( "\n\n" );
}
delete pMatrix;
}
while (GetKey() = "");
return;
}
;D This is the kind of stuff I need for my matrix/linear algebra stuff ;D
I can even set up triangular matrices with efficient memory usage.
How do I expand the matrix if I need to? Add a row and/or column?
I have no idea why that didn't give you a syntax error ;) Accessing an array in Aurora is done like so:
array[0,10,10]
Not the C way of
array[0][10][10]
Although it appears works I will have to do a bit of testing on the assembly output to verify what it's doing.
lviklund's Motto is " It's not a bug. It's a feature! "
don't fix it if it works
It only appeared to work because your printing the result right after you were setting it. Trying to access a dynamic array the 'c' way won't work in Aurora as ilustrated by this little test code:
double *pa;
global sub main()
{
pa = new(double,10*10);
*pa[0][1]=10;
writeln(NumToStr(*pa[1][0]) + "\n");
while (GetKey() = "") ;
}
When you used the syntax [][] the compiler allowed it because of a recent change in precendence rules to solve a problem with pointer arrays. What it does is just multiply each index by the type size and add it to the memory address without reguard to dimension so "[1][0]" accesses the same memory location as "
- [1]"
Array offsets are calculated by the compiler because it knows the size of the data and the dimension of the array. When you allocate memory there are no dimenstions, only a raw block of memory so you need to do the calculations yourself.
For example:
int a[15,15];
a[5,10] = 100;
The compiler knows the dimensions of the array from the first statement so it can calculate the proper location in the array:
a[5,10]
is calculated as:
&a + ((5*1) + (10*15))*len(int);
In general, depending on whether you want row or column order, the calcualtions for offsets are as such: (n=index, dim=dimension)
2 dim array = (n1 * dim0 + n0)*datasize;
3 dim array = ((n2 * dim0 * dim1) + (n1 * dim0) + n0) * datasize;
4 dim array = ((n3 * dim0 * dim1 * dim2) + (n2 * dim0 * dim1) + (n1 * dim0) + n0) * datasize;
The final dimension in an array is only used for out of bounds checking in some languages. Usually interpreters.
Dynamic arrays only support one dimension unless you use a bit of pointer math and the above formulas. This change to your code verifies the writes with a second set of loops....
global sub main()
{
int num = 3;
double *pMatrix;
pMatrix = new( double, num*num*num*num );
if ( pMatrix = null )
{
writeln("insufficient memory\n");
}
else
{
//write the data
for(int i = 0; i <= num-1; i++)
{
for(int j = 0; j <= num-1; j++)
{
for(int k = 0; k <= num-1; k++)
{
for(int l = 0; l <= num-1; l++)
{
*(double)(pMatrix+(l+(k*num)+(j*num*num)+(i*num*num*num))*8) = (1+i)*1000+(1+j)*100+10*(k+1)+l+1;
}
}
}
}
//verify the data
for(i = 0; i <= num-1; i++)
{
for(j = 0; j <= num-1; j++)
{
for(k = 0; k <= num-1; k++)
{
for(l = 0; l <= num-1; l++)
{
writeln( numtostr( *(double)(pMatrix+(l+(k*num)+(j*num*num)+(i*num*num*num))*8) ) + " " );
}
writeln( "\n" );
}
writeln( "\n" );
}
writeln( "\n\n" );
}
delete pMatrix;
}
while (GetKey() = "");
return;
}
Goosh!!
My q stirred up some interesting thoughts here.
Good reading.
Thank you all for the discussion.
I have to ask my q again from a different angle.
If I have an Array of strings and I would like to pass the whole array as an argument to a external function, is that possible?
How?
something like:
func(array[])
that sends some kind of adress for the whole array to the external function.
I don't get this.
Lost! Que, Uh.... ???
Does it make any sense?
And the answer is......ÂÃ, Ã‚Ã, ??? uh, errrr, what's the question again?
.
.
.
Oh yeah!ÂÃ, Right from the manual, "A string array allocated by NEW has to be accessed using two indices."ÂÃ, :)
declare printstring(pArray as pointer, cnt as int);
global sub main ()
{
ÂÃ, Ã‚Ã, int num = 4;ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, // a variable that compiler does not know the value
ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, // of at compile time, only at runtime is it known
ÂÃ, Ã‚Ã, string *foo = new ( string, num);
ÂÃ, Ã‚Ã, if ( foo = NULL )ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, // check if foo fails to be allocated
ÂÃ, Ã‚Ã, Ã‚Ã, {
ÂÃ, Ã‚Ã, Ã‚Ã, writeln ("there is insufficient memory for foo");
ÂÃ, Ã‚Ã, Ã‚Ã, }
ÂÃ, Ã‚Ã, else
ÂÃ, Ã‚Ã, Ã‚Ã, {
*foo[0,0] = "This ";
*foo[1,0] = "is ";
*foo[2,0] = "a ";
*foo[3,0] = "test ";
ÂÃ, Ã‚Ã, Ã‚Ã, }
printarray(foo, num);
delete foo;ÂÃ, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, Ã‚Ã, // always free up the memory used with new
while (GetKey() = "");
ÂÃ, return;
}
sub printarray(pArray as pointer, cnt as int)
{
for ( int n = 0; n < cnt; n++ )
{
writeln(*(string)pArray[n,0] + "\n" ); // show foo's values
}
}
Because a string is actually an array of 255 bytes. But you have to be careful when using an array of strings, since overwriting one won't cause an error but it will bring unexpected results.
See the heapsort.src example.
lviklund,
It has stimulated quite a bit of thought.
I think to pass the address of array[] you write:
func( array ) // array is a pointer to the first element in array[]
but inorder to make sure func () knows how big array[] is use:
func( array, N ) // array is a pointer to the first element in array[]
// N is the mumber of elements in array[]
btw, I have to double check my coding, but I got 1 byte for:
writeln ("\n" + numtostr( len( string ) ) + " bytes\n"); // prints '1 bytes' to the screen not '255 bytes'
I could be due to type casting in numtostr().
LEN(string) returns 1 since a string is an array of bytes.
I will have to think about hard coding 255 into the LEN function.
I think LEN(STRING) should return 255, and BASELEN(STRING) should return 1.
I know, stupid question:
How do I find the length of a string variable that contains "Duh". I'm expecting an answer of 3.
len(variable);
What we were discussing was the compiler returning the length of a variable type. LEN works on variables, intrinsic type names such as STRING, FLOAT, DOUBLE, and on Structure names.
print(len(DOUBLE)); returns 8 for example
a = "Duh";
print(len(a)); returns 3
Like I said,"stupid question". And that's a big 3 on the 'duh'. ;D
How about "Douh!" ;D
That'll work.
Some days it just don't pay for me to come out from under the porch! ;D
Here is another Duh.....
I have just realized that I did understand how to pass string arrays.
The problem is that the function that is receiving expects a Fieldarray :o ??? :P.
Never heard of!
I will try to figure out what that is tonight.
Lasse