假设我有两个数组,我将它们传递给函数:
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
为什么我们不能以类似的方式处理数组传递?
编辑:代码中出错。
答案 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
可能是指针的序列(甚至只是一个这样的指针),每个指针都可能指向一个积分值序列(或只是一个整数值)。