通过动态二维数组时,为什么我们不需要列数?

时间:2017-06-15 06:21:03

标签: c++ c arrays

假设我有两个数组,我将它们传递给函数:

select saleid, dataid,t4.price,(case when rn=1 then cost else 0 end)Cost 
,price-(case when rn=1 then cost else 0 end)Profit
FROM(
select a.saleid,a.dataid,a.price, d.cost
,ROW_NUMBER()over(PARTITION by d.dataid order by d.dataid)rn
     from #TmpSale a
left join #TmpData d on a.dataid=d.dataid
)t4

为什么我们不能以类似的方式处理数组传递?

编辑:代码中出错。

3 个答案:

答案 0 :(得分:1)

与您所说的相反的情况是:您不必传递行数。假设数组索引的工作方式如下:

int arr[MAX_ROW][MAX_COL]; /* with both 3 */

           col
     --------------->
    | 0,0   0,1   0,2
row | 1,0   1,1   1,2
    V 2,0   2,1   2,2

当您通过int arr[][MAX_COL]时,编译器会知道下一行的位置,例如arr[row][col]的地址。

如果您使用指针手动执行此操作,它将如下所示:&arr[0][0] + row * MAX_COL + col。在该示例中,您还必须知道数组的列大小MAX_COL以计算下一行。

原因是,数组在内存中是连续的。上面的数组在内存中表示如下:

|     row = 0     |     row = 1     |     row = 2     |
| 0,0   0,1   0,2 | 1,0   1,1   1,2 | 2,0   2,1   2,2 |

编译器还必须知道行偏移量,因为当您将声明为int arr[MAX_SIZE]的数组传递给函数void foo (int arr[])时,它会衰减为指向数组{{1}的开头的指针}。在数组数组(2D数组)的情况下,它也会衰减到指向其第一个元素的指针,这是指向单个数组int* arr的指针。

简而言之:使用int (*arr)[MAX_COL]编译器可以获得使用int arr[][MAX_COL]来处理数组所需的所有信息。

答案 1 :(得分:0)

实际上恰恰相反,你只能省略其中一个索引(在多维数组的情况下),最里面的索引。

这是因为,作为函数参数传递的数组会衰减到指向第一个元素的指针。引用C11,章节§6.3.2.1

  

除了,当它是sizeof运算符,_Alignof运算符或者&运算符的操作数时   一元 void func(int arr1[][5], int **arr2) //an array of array of 5 ints 运算符,或者是用于初始化数组的字符串文字,一个包含的表达式   类型''类型''的数组转换为类型为的表达式''指向类型''的指针   到数组对象的初始元素并且不是左值。 [...]

因此,像

这样的符号
 void func(int (*arr1) [5], int **arr2)  //pointer to the starting element of an array of 5 ints

export class MyApp {
  rootPage:any = LoginPage;
   let self = this;
  if (status) {
            var _dataObj = JSON.parse(data);            
            rest.setAuthToken(_dataObj.userId, _dataObj.authToken);
            self.rootPage = LoginPage;                    
  }
}

是等价的。

答案 2 :(得分:0)

实际上只有一个整数数组(即int arr1[][5])和一个指向int指针的指针,即int **arr2。即使像arr1[10][5]这样的数组作为参数传递给函数,衰减到指向元素所在的内存开头的指针,内存布局也会有一个(大)差异。编译器处理对这些指针的访问。

BTW,主要应该是int n=5,m=4;int arr1[m][n],而不是int n=5,m=4;int arr1[n][m]

关于内存布局:

形式为int [10][5]的2D整数数组表示为10个连续的"行",每个包含5"列" (即积分值)。这个数组的大小是10 * 5 * sizeof(int),大小是一个" row"是5 * sizeof(int)

指向int int **p的指针只是一个指针;它的大小为sizeof(int**),即使你有" malloced"一系列整数指针lile p = malloc(10 * sizeof (int*));注意" *"在sizeof(int *)中,当您创建一个指向整数的指针序列时,而不是整数序列。这是内存布局的主要区别:它不是整数的2D数组,而是整数指针的一维数组。如果一个人实际上分配了10行和#34;为" 10"整数,每行可以位于内存的不同部分。管理这样(扩展)的10x5整数值所需的空间是" 10 * sizeof(int *)+ 10 * 5 * sizeof(int)"。

关于访问:

假设一个int arr[][5]类型的变量,它是一个整数的2D数组,其中列的大小为5,并且未确定行数。非正式地,像int x = arr[3][4]这样的访问被转换为访问数组的(3*5 + 4)元素,即" row times rowsize plus column&#34 ;;请注意 - 基于此公式 - 编译器不需要知道数组实际具有多少行。

相反,让我们假设一个int **p类型的变量。您可以将x = p[3][4]之类的访问视为等同于int *r = p[3]; int x = r[4];请注意,r的类型为int *,即它是一个指针,然后r[4]取消引用此指针并返回一个整数值。

这是非正式的描述。 然而,主要的问题是arr[][5]的内存布局只包含连续的整数值,而int **arrr可能是指针的序列(甚至只是一个这样的指针),每个指针都可能指向一个积分值序列(或只是一个整数值)。