目录

 

1. 概要

2. 动态数组的声明

 3. 内存分配和初始化

4. 容量扩张

5. 动态数组的复制

6. 动态数组的删除

7. 代码例


1. 概要

        动态数组(Dynamic array),顾名思义,是一种其大小可以在运行中动态改变的非合并数组(unpacked array)。与之相对的是静态数组(Static array)的大小必须在变量声明时就固定下来,在运行时是不能改变的。由于这一根本特征的差异,两者的用途也截然不同。

        从内存分配的角度来看,静态数组的大小由于是从一开始就固定下来的,所以是在静态存储区(即所谓的栈)进行分配的,而动态数组由于是需要动态可变,因此是在堆(heap)中进行分配的(待确认)。

        动态数组只能有一个维度,而且不能被合并(can not be packed),换句话说只能是非合并数组。

        对动态数组的访问如果越界的话会导致运行时错误(run time error)。

        动态数组有以下三种方法(method):

  1. new[]
  2. size()
  3. delete()

2. 动态数组的声明

[data_type] [identifier_name] [];

变量名之后的’[]’就表示这个变量代表一个动态数组。变量名之前则为所存储的数据类型。例:

Bit[7:0] stack[];  // A dynamic array, whose element represents one byte

String names[];  // A dynamic array, whose element represents one string

 3. 内存分配和初始化

        动态数组在声明之后还没有真正分配内存,或者说此时它的容量大小为0。

        有两种分配内存的方法。

        第一种是调用new()方法,调用new()方法虽然分配了内存但是没有对内存进行初始化;

        第二种是利用列表直接进行初始化,当然其中已经隐含了内存分配

//declaration
bit [7:0] d_array1[];
int d_array2[];

//memory allocation
d_array1 = new[4]; //dynamic array of 4 elements
d_array2 = new[6]; //dynamic array of 6 elements

//array initialization
d_array1 = {0,1,2,3};
foreach(d_array2[j]) d_array2[j] = j;

        一个动态数组变量可以随时基于以上两种方法进行重新内存分配和初始化,如下节所示。

4. 容量扩张

//Change the length of the array after declaration/initialization
d_array1 = new[10]; //dynamic array of 10 elements

        以上语句中d_array1被重新分配了10个地址空间,d_array1中原有的数据被扔掉了。

        当然,用以下形式调用new()的话可以在扩充容量的同时保留d_array1中原有的数据.

//Allocate 6 new elements and retain values of 4 elements.
d_array1 = new[10](d_array1);

5. 动态数组的复制

        动态数组的复制的语法形式与上一节的扩容且保留原数据的调用方法相同,只不过生成的内存块赋给了新的一个变量。以下语句创建了d_array1的一个副本。

d_array2 = new[d_array1.size()](d_array1);

 

6. 动态数组的删除

         与C++中一样,用new()创建的动态数组需要用delete()方法进行删除。如果忘记了删除的话,会导致预料不到的内存泄漏,甚至会导致程序因为内存用量overflow而崩溃。因此,一个良好的习惯是,在不再需要的时候用delete()删除掉用new()创建的东西。

7. 代码例

module example;

reg [31:0] regArray_1[];
reg [31:0] regArray_2[];
reg [31:0] regArray_3[];
string names[];
  
initial
begin
    
    dynarray_init();    #100;    
    dynarray_copy();    #100;    
    dynarray_resize();  #100;    
    

    regArray_1.delete(); // Deleting all the elements of regArray_1, 
    // Display the size of the array after deletion
    $display ("\nSize of the regArray_1 after deletion-becoming 0-size array = %d",regArray_1.size());

    // Dynamic array for storing strings
    names = '{"systemverilog", "matlab", "python", "c++"};
    foreach(names[j]) begin
        $display ("names[%g] = %s", j, names[j]);
    end    
    
    #100 $finish;
end

task dynarray_init();

    $display("\ndynarray_initialization() ... ");

    // Declaration only doesn't allocate memory to dynamic array.
    // Currently, the above regArray has size of 0.
    $display("Before Memory Allocation");
    $display("\tSize of regArray_1 %0d",regArray_1.size());
    $display("\tSize of regArray_2 %0d",regArray_2.size());    

    // Initialization of dynamic array.
    $display ("\nDemonstrating the initialization of dynamic array ...");
    regArray_1 = '{0,1,2,3,4}; //{0,1,2,3,4} is also OK, what is the difference?
    $display("regArray_1 expected value: 0,1,2,3,4");
    foreach(regArray_1[j]) begin
        $display ("%d: %d" , j, regArray_1[j]);
    end
         
    // Re-initialize values for regArray_1
    regArray_1 = new [6];      
    $display ("\nnew() doesn’t do the value initialization...");
    for ( int i = 0 ; i < regArray_1.size(); i ++ )
        $display ("regArray_1[%g] = %d" , i, regArray_1[i]);
        
    foreach(regArray_1[j]) regArray_1[j] = j+10;
    $display("\nregArray_1 expected value: 10,11,12,13,14,15");
    for ( int i = 0 ; i < regArray_1.size(); i ++ )
        $display ("regArray_1[%g] = %d" , i, regArray_1[i]);

endtask

task dynarray_copy();

    $display("\ndynarray_copy() ... ");
    
    // copy regArray_1 to regArray_2
    regArray_2 = new[regArray_1.size()] (regArray_1);    
    $display("\nregArray_2 expected value equals to regArray_1, because it is copied from regArray_1");
    foreach(regArray_2[i])
        $display ("regArray_2[%g] = %d" , i, regArray_2[i]);

    // Another method of copy. Different from C++!
    regArray_3 = regArray_1;
        
    $display("\nregArray_3 expected value equals to regArray_1, because it is copied from regArray_1");
    foreach(regArray_3[i]) begin    
        $display ("regArray_3[%g] = %d" , i, regArray_3[i]);
    end
    regArray_3[3] = 100;
    regArray_3[5] = 1000;
    $display("\nModify regArray_3 doesn't affect regArray_1");
    foreach(regArray_3[i]) begin    
        $display ("regArray_1[%g] = %d, regArray_3[%g] = %d" , i, regArray_1[i], i, regArray_3[i]);
    end    

    $display("\nA different method to print the content of the array...");
    $display("regArray_1 = %p",regArray_1);
    $display("regArray_3 = %p",regArray_3);
    
endtask

task dynarray_resize();
    
    regArray_1 = {0,1,2,3,4}; //'{0,1,2,3,4} is also OK, what is the difference?
    $display ("\nBefore resizing...");
    foreach(regArray_1[i])
        $display ("regArray_1[%g]: %d" , i, regArray_1[i]);        
    // Resize the dynamic array, with the old contents of regArray are retained/inherited.
    regArray_1 = new[regArray_1.size() + 5](regArray_1);
    $display ("\nAfter resizing, the first 10 elements of regArray_1 are retained:");
    foreach(regArray_1[i])
        $display ("regArray_1[%g]: %d" , i, regArray_1[i]);        

endtask

endmodule

 运行后会得到结果如下所示:

dynarray_initialization() ... 
 Before Memory Allocation
     Size of regArray_1 0
     Size of regArray_2 0Demonstrating the initialization of dynamic array ...
 regArray_1 expected value: 0,1,2,3,4
           0:          0
           1:          1
           2:          2
           3:          3
           4:          4new() doesn’t do the value initialization...
 regArray_1[0] =          x
 regArray_1[1] =          x
 regArray_1[2] =          x
 regArray_1[3] =          x
 regArray_1[4] =          x
 regArray_1[5] =          xregArray_1 expected value: 10,11,12,13,14,15
 regArray_1[0] =         10
 regArray_1[1] =         11
 regArray_1[2] =         12
 regArray_1[3] =         13
 regArray_1[4] =         14
 regArray_1[5] =         15dynarray_copy() ... 
regArray_2 expected value equals to regArray_1, because it is copied from regArray_1
 regArray_2[0] =         10
 regArray_2[1] =         11
 regArray_2[2] =         12
 regArray_2[3] =         13
 regArray_2[4] =         14
 regArray_2[5] =         15regArray_3 expected value equals to regArray_1, because it is copied from regArray_1
 regArray_3[0] =         10
 regArray_3[1] =         11
 regArray_3[2] =         12
 regArray_3[3] =         13
 regArray_3[4] =         14
 regArray_3[5] =         15Modify regArray_3 doesn't affect regArray_1
 regArray_1[0] =         10, regArray_3[0] =         10
 regArray_1[1] =         11, regArray_3[1] =         11
 regArray_1[2] =         12, regArray_3[2] =         12
 regArray_1[3] =         13, regArray_3[3] =        100
 regArray_1[4] =         14, regArray_3[4] =         14
 regArray_1[5] =         15, regArray_3[5] =       1000A different method to print the content of the array...
 regArray_1 = '{'ha, 'hb, 'hc, 'hd, 'he, 'hf}
 regArray_3 = '{'ha, 'hb, 'hc, 'h64, 'he, 'h3e8}Before resizing...
 regArray_1[0]:          0
 regArray_1[1]:          1
 regArray_1[2]:          2
 regArray_1[3]:          3
 regArray_1[4]:          4After resizing, the first 10 elements of regArray_1 are retained:
 regArray_1[0]:          0
 regArray_1[1]:          1
 regArray_1[2]:          2
 regArray_1[3]:          3
 regArray_1[4]:          4
 regArray_1[5]:          x
 regArray_1[6]:          x
 regArray_1[7]:          x
 regArray_1[8]:          x
 regArray_1[9]:          xSize of the regArray_1 after deletion-becoming 0-size array =           0
 names[0] = systemverilog
 names[1] = matlab
 names[2] = python
 names[3] = c++