Say I have a class field
a : array of array of double;
it is allocated using nested SetLength calls.
SetLength(a,100);
for i := 0 to length(a)-1 do SetLength( a[i], 100 );
On object Destroy is it necessary to loop through the first level of array to free the second level items of it?
for i := 0 to length(a)-1 do a[i] := NIL;
Is it necessary or the compiler handles freeing of multi dimensional dynamic arrays too?
Dynamic arrays are managed by the compiler. When a dynamic array's reference count drops to zero, it is automatically freed.
This is equally true for multidimensional dynamic arrays of any dimension, at every level.
So when your field a goes out of scope, this dynamic array's reference count is reduced by one. If the new reference count is zero, the array is freed, and so the reference counts of all elements a[0], a[1], ..., a[High(a)] are reduced by one. And, again, if they reach zero, they are freed too.
You don't need to do anything.
You can set the size of a multi-dimensional dynamic array with a single SetLength() call. No need to use any loop.
You do this by simply calling
SetLength(DynamicArray, FirstDimensionSize, SecondDimensionSize, ..NthDimensionSize).
So, in your case, you could set the initial size of your dynamic array by simply using:
SetLength(a,100,100);
And then when freeing up the array, you just call:
SetLength(a,0,0);
Related
I read somewhere that Ada allows a function only to return a single item. Since an array can hold multiple items does this mean that I can return the array as a whole or must I return only a single index of the array?
Yes, an Ada function can return an array - or a record.
There can be a knack to using it, though. For example, if you are assigning the return value to a variable, the variable must be exactly the right size to hold the array, and there are two common ways of achieving that.
1) Fixed size array - cleanest way is to define an array type, e.g.
type Vector is new Array(1..3) of Integer;
function Unit_Vector return Vector;
A : Vector;
begin
A := Unit_Vector;
...
2) Unconstrained array variables.
These are arrays whose size is determined at runtime by the initial assignment to them. Subsequent assignments to them will fail unless the new value happens to have the same size as the old. The trick is to use a declare block - a new scope - so that each assignment to the unconstrained variable is its first assignment. For example:
for i in 1 .. last_file loop
declare
text : String := Read_File(Filename(i));
-- the size of "text" is determined by the file contents
begin
-- process the text here.
for j in text'range loop
if text(j) = '*' then
...
end loop;
end
end loop;
One warning : if the array size is tens of megabytes or more, it may not be successfully allocated on the stack. So if this construct raises Storage_Error exceptions, and you can't raise the stack size, you may need to use access types, heap allocation via "new" and deallocation as required.
Yes, an Ada function can return an array. For example, an Ada String is "A one-dimensional array type whose component type is a character type." Several of the functions defined in Ada.Strings.Fixed—including Insert, Delete, Head, Tail and Trim—return a String.
Is there a way we can copy every element from one multidimensional array to another multidimensional array by just doing one memcpy operation?
int array1[4][4][4][4];
int array2[4][4][4][4];
int main()
{
memset(&array1,1,sizeof(array1));
memset(&array2,0,sizeof(array2));
printf_all("value in array2 %d \n",array2[1][1][1][1]);
memcpy(&array2,&array1,sizeof(array2));
printf("memcopied in array2 from array1 \n");
printf("value in array2 %d \n",array2[1][1][1][1]); //not printing 1
}
Your code is correct. You should not expect the output to show you a value of 1. You should expect it to show you a value of 16843009, assuming a 4 byte int.
The reason is: you are filling array1 with bytes of value 1, not with ints of value 1. i.e. binary 00000001000000010000000100000001 (0x01010101) is being filled into all the int elements with your memset operation.
So regardless of the size of int on your machine (unless it's a single byte!) you should not expect to see the value 1.
I hope this helps.
Yes, your code should already be correct.
You have to consider memory layout when doing this. The arrays are all in one block, multi dimensional is essentially a math trick done by the compiler.
Your code says copy this memory content to the other memory block. since both share the same layout they will contain the same values.
The following code also just copies the values, but access is handled differently so you would have to think about how to get the order of elements correct.
int array1[4][4][4][4]; //elements 256
int array2[256];
int main()
{
memcpy(&array2,&array1,sizeof(array1)); //will also copy
// original access via: a + 4 * b + 16 * c + 64 * d
}
Multidimensional array in C is a flat block of memory with no internal structure. Memory layout of a multidimensional array is exactly the same as that of a 1-dimensional array of the same total size. The multidimensional interface is implemented through simple index recalculation. You can always memcpy the whole multidimensional array exactly as you do it in your code.
This, of course, only applies to built-in multidimensional arrays, explicitly declared as such (as in your code sample). If you implement a hand-made multidimensional array as an array of pointers to sub-arrays, that data structure will not be copyable in one shot with memcpy.
However, apparently you have some misconceptions about how memset works. Your memset(&array1,1,sizeof(array1)); will not fill the array with 1s, meaning that your code is not supposed to print 1 regardless of which array you print. memset interprets target memory as an array of chars, not as an array of ints.
memset can be used to set memory to zero. As for non-zero values, memset is generally unsuitable for initializing arrays of any type other than char.
How do you allocate an array in Go with a run-time size?
The following code is illegal:
n := 1
var a [n]int
you get the message prog.go:12: invalid array bound n (or similar), whereas this works fine:
const n = 1
var a [n]int
The trouble is, I might not know the size of the array I want until run-time.
(By the way, I first looked in the question How to implement resizable arrays in Go for an answer, but that is a different question.)
The answer is you don't allocate an array directly, you get Go to allocate one for you when creating a slice.
The built-in function make([]T, length, capacity) creates a slice and the array behind it, and there is no (silly) compile-time-constant-restriction on the values of length and capacity. As it says in the Go language specification:
A slice created with make always allocates a new, hidden array to which the returned slice value refers.
So we can write:
n := 12
s := make([]int, n, 2*n)
and have an array allocated size 2*n, with s a slice initialised to be the first half of it.
I'm not sure why Go doesn't allocate the array [n]int directly, given that you can do it indirectly, but the answer is clear: "In Go, use slices rather than arrays (most of the time)."
Why is it necessary to specify the number of elements of a C-array when it is passed as a parameter to a function (10 in the following example)?
void myFun(int arr[][10]) {}
Is it so because the number of elements is needed to determine the address of the cell being accessed?
Yes. It's because arr[i][j] means ((int *)arr)[i * N + j] if arr is an int [][N]: the pointer-arithmetic requires the length of a row.
The compiler needs to have an idea when the next row starts in memory (as a 2D array is just a continuous chunk of memory, one row after the other). The compiler is not psyche!
It is only necessary if you used static allocation for your array thought. Because the generate code create a continuous memory block for the array, like pointed out ruakh.
However if you use dynamic allocation it is not necessary, you only need to pass pointers.
Regards
I have a dynamic array myArr. What is stored in the memory in myArr when we use SetLength on it? Is it '00'? Or undefined?
SetLength allocates 16 bytes of memory for myArr in this case.
myArr : array of byte;
SetLength(myArr, 16);
Quoted from the Delphi 7 help, "For a long-string or dynamic-array variable, SetLength reallocates the string or array referenced by S to the given length. Existing characters in
the string or elements in the array are preserved, but the content of newly allocated space is undefined. The one exception is when increasing the length of a dynamic array in which the elements are types that must be initialized (strings, Variants, Variant arrays, or records that contain such types). When S is a dynamic array of types that must be initialized, newly allocated space is set to 0 or nil."
From my observation, for static array, uninitialized elements contain random data. For dynamic array, AFAIK since Delphi 7, uninitialized elements contain their default nothing value. However, you shouldn't rely on this fact because it was implementation detail of SetLength. You should follow the official documentation instead.
In practice, it is initialized with zero's.
The method SetLength internally calls System.DynArraySetLength.
Using Delphi 5, the memory gets filled with #0.
// Set the new memory to all zero bits
FillChar((PChar(p) + elSize * oldLength)^, elSize * (newLength - oldLength), 0);
I assume this behavior has not changed in more recent versions of Delphi.