《C专家编程》读书笔记(3)

***什么时候数组和指针是相同的***

 (1)“表达式中的数组名”就是指针;
对数组下标的引用总是可以写成“一个指向数组的起始地址的指针加上偏移量”。
例如,假如我们声明:

int  a[ 10 ],  * p, i  =   2 ;

就可以通过以下任何一种方法来访问a[i]:

// 第一种方法
=  a;
p[i];
// 第二种方法
=  a;
* (p + i);
// 第三种方法
=  a + i;
* p;

编译器自动把下标值的步长调整到数组元素的大小。每个指针只能指向一种类型的原因所在:(1)编译器需要知道对指针进行解除引用操作时应该取几个字节;(2)每个下标的步长应取几个字节。

(2)把数组下标作为指针的偏移量
(3)“作为函数参数的数组名”等同于指针
“类型的数组”的形参的声明应该调整为“类型的指针”,编译器会将数组形式改写成指向数组第一个元素的指针形式。编译器只向函数传递数组的地址,而不是整个数组的拷贝。
下面三种形式通过编译器的隐式转换后是相同的:

void  my_function( int *  turnip)  { ... }
void  my_function( int  turnip[])  { ... }
void  my_function( int  turnip[ 200 ])  { ... }

 

***数组与指针的其它知识点***

有一样操作只能在指针里进行而无法在数组中进行,那就是修改它的值。数组名是不可修改的左值,它的值是不能改变的。

func1( int *  ptr)       func2( int  arr[])      int  array[ 100 ], array2[ 100 ];
{                          {                          main()
    ptr[
1= 3;             arr[1= 3;       {
    
*ptr = 3;               *arr = 3;               array[1= 3;
    ptr 
= array2;         arr = array2;        *array = 3;
}
                          }
                              array = array2;  //不能修改数组名
                                                       }

 

***C语言中的多维数组***

C语言中定义和引用多维数组唯一的方法就是使用数组的数组。像[i,j,k]这样的下标形式是C语言中的合法形式,只是它并非同时引用这几个下标(它实际所引用的下标值是k,即逗号表达式的值)。

访问多维数据carrot[10][20]中的单个字符都是通过carrot[i][j]的形式,编译器在编译时会把它解析为*(*(carrot+i)+j)的形式。

 

对多维数组中各层数组的访问:
int a[2][3][5];
int (*p)[3][5] = a;
int (*q)[5] = a[0];
int *r = a[0][0];

 

多维数组的初始化中一种有用的方法是建立指针数组。字符串常量可以用数组初始化值,例如:
char   * vegetables[]  =  
{
"carrot",
"celery",
"corn",
"cilantro"
}
;

 

多维数组中“数组的数组”和“字符串指针数组”的定位方式的差别:

(1)数组的数组:
char  a[ 4 ][ 6 ];     // 一个数组的数组
// 在编译器符号表中,a的地址为9980
// 运行时步骤1:取i的值,把它的长度调整为一行的宽度(这里是6),然后加到9980上
// 运行时步骤2:取j的值,把它的长度调整为一个元素的宽度(这里是1),然后加到前面所得的结果上
// 运行时步骤3:从地址(9980+i*scale_factor_1+j*scale_factor_2)

 

(2)字符串指针数组:
char   * p[ 4 ];     // 字符串指针数组
// 在编译器符号表中,p的地址为4624
// 运行时步骤1:取i的值,乘以指针的宽度(4个字节),并把结果加到4624上
// 运行时步骤2:从地址(4624+i*4)取出内容,为“5081”
// 运行时步骤3:取j的值,乘以元素的宽度(1个字节),并把结果加到5081上
// 运行时步骤4:从地址(5080+j*1)取出内容

char *p[4]的定义表示p是一个包含4个元素的数组,每个元素为一个指向char的指针。查寻过程先找到数组的第i个元素(每个元素均为指针),取出指针的值,加上偏移量j,以此为地址,取出地址的内容。

 

“数组名被改写成一个指针参数”规则并不是递归定义的。数组的数组会被改写成“数组的指针”,而不是“指针的指针”。

实参                                                          所匹配的形式参数
数组的数组                 
char  c[ 8 ][ 10 ];         char  ( * )[ 10 ];           数组指针
指针数组                     
char   * c[ 15 ];            char   ** c;               指针的指针
数组指针(行指针) 
char  ( * c)[ 64 ];          char  ( * c)[ 64 ];        不改变
指针的指针                 
char   ** c;                 char   ** c;              不改变

备注:数组指针是一个指向数组的指针,例如上图中的char (*c)[64]是一个指向64个元素的char数组的指针。

 

严格地说,无法直接从函数返回一个数组。但是,可以让函数返回一个指向任何数据结构的指针,当然也可以是一个指向数组的指针。
int  ( * f())[ 20 ]
{
int (*pear)[20];    //声明一个指向包含20个int元素的数组的指针
pear = (int(*)[20])calloc(20,sizeof(int));
return pear;
}

// 调用该函数
int  ( * result)[ 20 ];
result 
=  f();        // 调用函数
( * result)[ 0 =   1 ;    // 访问结果数组
char a[4][6]的定义表示a是一个包含4个元素的数组,每个元素是一个char类型的数组(长度为6)。所以查找到数组中的第i个元素(前进i*6个字节),然后找到数组中的第j个元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值