Chapter 9 More about Arrays
数组何时是指针?
对数组的声明有三种类型:
1、声明外部数组
2、定义数组
3、声明为函数参数
当声明时,第一、二种情况下不能用指针重写,第三种可以使用[]或者*形式,二者均可。使用数组时,一律采用指针的方式解引用。
数组被当作指针看待,三种情况:
1、数组名一旦在表达式中出现,则被编译器当作一个指向数组首元素的指针。在sizeof和&的时候为例外。
2、数组的下标等价于指针+偏移量。
3、函数参数中的数组被当作一个指向数组首元素的指针。
特别的,解引用指针时,a[6]和6[a]是等价的,因为a+6*sizeof(typeof(a))==6*sizeof(typeof(a))+a。
Parameter和Argument之间的区别:Parameter指的是在函数声明时的“参数名称”;Argument是函数调用时用实际值(包括变量和常量)填入的参数。
如果要传递数组的一个切片,可以用&array[i]来实现。
如果传递&array[-1],则可以让数组的下标变为[1,N]。
C中的多维数组
C中只有“元素为数组的数组”,即是多维数组。只能用[][]的形式而不是[,]的形式引用。内存中的分布按照最后一维开始,依次排列。
(附注:“元素为数组的数组”标明引用的时候,有多少维数组就必须采用多少维的[]来解引用)
只能初始化
char* p[]={"abc","def","ghi"};
而不能初始化
int* p[]={{1,2,3},{4,5,6}};
必须采用
int r1[]={1,2,3};
int r2[]={4,5,6};
int* p[]={r1,r2};
====================
Chapter 10 More About Pointers
Iliffe Vector
对于char a[4][6]的解引用:
a[i][j]
运行时:1、取i,乘以6(6*sizeof(char))=o1 2、取j,乘以1(sizeof(char))=o2 3、a+o1+o2
(附注:对int a[3][3]={1,2,3,4,5,6,7,8,9};,有(*a)[1]==2,*(a[1])==4)
对于char* p[4]的解引用:
p[i][j]
运行时:1、取i,乘以sizeof(pointer),加在p的基址上 2、解引用上述结果,得到一个新的地址 3、取j,乘以sizeof(char) 4、将第2步中的数据和第3步的数据求和,得到一个地址,然后解引用,得到结果
Ragged Arrays
为了节约空间,例如传递三个不定长的字符串,可以使用ragged array。这时第二维的长度不确定。
数组和指针参数如何被编译器更改
Argument | Parameter
char c[8][10] | char (*c)[10]
char* c[15] | char **c
char (*c)[64] | char (*c)[64]
char **c | char **c
也就是说,将数组[]改写成指针时,以第一维为主。
(附注:对char*** p的parameter传递char u[][][]的argument,会产生一个warning,这是因为传递的是char (*)[][]而不是char***)
向函数传递一维数组
因为一维数组传递的只是首元素的地址,所以需要再传递一个数据来指明数组的长度。可以增加一个parameter也可以在数组末尾加上一个magic number。
对于二维数组,作为parameter时需要指明第二维的长度。
使用指针传递给一个函数一个多维数组
作为parameter
方法1:int a[100][100],只能传递确定维数确定长度的数组。
方法2:int a[][100],第二维还是确定的
方法3:int **a;,需要一个类型转换并且需要重新换算。
方法4:int *a,自己人肉计算偏移吧。
使用指针返回一个数组
返回的方式:
int (*paf())[20];
返回一个int (*) [20];
动态数组
利用malloc和realloc实现。
数组何时是指针?
对数组的声明有三种类型:
1、声明外部数组
2、定义数组
3、声明为函数参数
当声明时,第一、二种情况下不能用指针重写,第三种可以使用[]或者*形式,二者均可。使用数组时,一律采用指针的方式解引用。
数组被当作指针看待,三种情况:
1、数组名一旦在表达式中出现,则被编译器当作一个指向数组首元素的指针。在sizeof和&的时候为例外。
2、数组的下标等价于指针+偏移量。
3、函数参数中的数组被当作一个指向数组首元素的指针。
特别的,解引用指针时,a[6]和6[a]是等价的,因为a+6*sizeof(typeof(a))==6*sizeof(typeof(a))+a。
Parameter和Argument之间的区别:Parameter指的是在函数声明时的“参数名称”;Argument是函数调用时用实际值(包括变量和常量)填入的参数。
如果要传递数组的一个切片,可以用&array[i]来实现。
如果传递&array[-1],则可以让数组的下标变为[1,N]。
C中的多维数组
C中只有“元素为数组的数组”,即是多维数组。只能用[][]的形式而不是[,]的形式引用。内存中的分布按照最后一维开始,依次排列。
(附注:“元素为数组的数组”标明引用的时候,有多少维数组就必须采用多少维的[]来解引用)
只能初始化
char* p[]={"abc","def","ghi"};
而不能初始化
int* p[]={{1,2,3},{4,5,6}};
必须采用
int r1[]={1,2,3};
int r2[]={4,5,6};
int* p[]={r1,r2};
====================
Chapter 10 More About Pointers
Iliffe Vector
对于char a[4][6]的解引用:
a[i][j]
运行时:1、取i,乘以6(6*sizeof(char))=o1 2、取j,乘以1(sizeof(char))=o2 3、a+o1+o2
(附注:对int a[3][3]={1,2,3,4,5,6,7,8,9};,有(*a)[1]==2,*(a[1])==4)
对于char* p[4]的解引用:
p[i][j]
运行时:1、取i,乘以sizeof(pointer),加在p的基址上 2、解引用上述结果,得到一个新的地址 3、取j,乘以sizeof(char) 4、将第2步中的数据和第3步的数据求和,得到一个地址,然后解引用,得到结果
Ragged Arrays
为了节约空间,例如传递三个不定长的字符串,可以使用ragged array。这时第二维的长度不确定。
数组和指针参数如何被编译器更改
Argument | Parameter
char c[8][10] | char (*c)[10]
char* c[15] | char **c
char (*c)[64] | char (*c)[64]
char **c | char **c
也就是说,将数组[]改写成指针时,以第一维为主。
(附注:对char*** p的parameter传递char u[][][]的argument,会产生一个warning,这是因为传递的是char (*)[][]而不是char***)
向函数传递一维数组
因为一维数组传递的只是首元素的地址,所以需要再传递一个数据来指明数组的长度。可以增加一个parameter也可以在数组末尾加上一个magic number。
对于二维数组,作为parameter时需要指明第二维的长度。
使用指针传递给一个函数一个多维数组
作为parameter
方法1:int a[100][100],只能传递确定维数确定长度的数组。
方法2:int a[][100],第二维还是确定的
方法3:int **a;,需要一个类型转换并且需要重新换算。
方法4:int *a,自己人肉计算偏移吧。
使用指针返回一个数组
返回的方式:
int (*paf())[20];
返回一个int (*) [20];
动态数组
利用malloc和realloc实现。