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

p..<关于数组和指针>

    1. 先看一个程序,你认为如果编译它,哪里会有错误?

1 #include <stdio.h>
2 #include <conio.h>
3  char a[2][2] = {{1,1},{2,2}};
4  void fuc_1(char **a)
5 {
6 printf("%d",a[0][1]);
7 }
8  void fuc_2(char (*a)[])
9 {
10 printf("%d",a[0][1]);//invalid use of array with unspecified bounds
11  }
12  void fuc_3(char a[][])
13 {
14 printf("%d",a[0][0]);//invalid use of array with unspecified bounds
15  }
16  void fuc_4(char (*a)[2])
17 {
18 printf("%d",a[0][1]);
19 }
20  int main(void)
21 {
22 fuc_1(a);//[Warning] passing arg 1 of `fuc_1' from incompatible pointer type
23   fuc_2(a);
24 fuc_3(a);
25 fuc_4(a);
26 getch();
27 return 0;
28 }

好吧,其实注释部分就说明了哪里有错。下面是解释:

  (1)p255<小启发>:

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

    实参:char c[2][3];  所匹配的形参:char(*)[3];

    实参:char *c[3];    所匹配的形参:char **c;

    实参:char (*c)[3];    所匹配的形参:char (*c)[3];

 

    (2)p227<软件信条>:

    在C语言中,没有办法向函数传递一个普通的多维数组。

    这是因为我们需要知道每一维的长度,以便为地址运算提供正确的单位长度。

    必须提供除了最左边一维以外的所有维的长度。比如

    fuc(int a[][3][5]);

    用下面的方法调用都可以:

    int b[10][3][5]; fuc(b);

    int b[999][3][5]; fuc(b);

    但下面的无法通过编译:

    int b[10][5][5];fuc(b);

 

2.  一些注意事项:

(1)p83数组名是个左值,但是不可修改。

(2)p84数组名并不是一个指针,而是一个数据名。所以,在声明数组时不可声明一个指针。

(3)p87只有字符串常量才能在定义时进行如下初始化:

char *p = "apple";

而其他类型常量不能这样做如:

float *pip = 3.14; /*错误,不能通过编译*/

(4)p87初始化指针时所创建的字符串常量定义为只读。而字符串常量初始化的数组是可以修改的。

 

3.  p201什么时候数组和指针是相同的(C标准):

(1)表达式中的数组名,被编译器当做一个指向该数组第一个元素的指针。

(2)下标总是与指针的偏移量相同。

(3)在函数参数的声明中,数组名,被编译器当做一个指向该数组第一个元素的指针。

对数组的引用如a[i]在编译时总是被编译器改写成*(a+i)的形式。而且下标值的步长被调整到数组元素的大小。

在处理一维数组时,指针并不见得比数组快。C语言把数组下标改写成指针偏移量的根本原因是这种方式是底层硬件使用的基本模型。

 

4. p207没有办法把一个数组本身传给某个函数,因为它总是被转化为一个指向该数组的指针。所以在此函数内部使用sizeof取得数组大小时,得到的实际上是指针的大小。

有一样操作只能在指针中进行,那就是修改数组本身的值。因为数组名是一个不可修改的左值。如下:

int array[100],array2[100];

main(){

array[1] = 3;

*array = 3;

array = array2; /*!!失败!!*/

}

fun1(int *ptr){

ptr[1] = 3;

*ptr = 3;

ptr = array2;

}

 

fun1(int arr[]){

arr[1] = 3;

*arr = 3;

arr = array2;

}

 

5.  p207编程挑战:

(1)定义一个函数,接受一个字符数组参数ca。在函数内部打印出&ca,&(ca[0])和&(ca[1])的值。

(2)定义另外一个函数,接受一个字符指针参数pa。在函数内部打印出&pa,&(pa[0]),&(pa[1]),++pa的值。

(3)建立一个全局字符数组ga并用英文字母初始化。调用两个使他作为参数的函数,比较两个函数打印的值。

(4)在main函数中打印出&ga,&(ga[0]),&ga[1]的值。

(5)解释其中原因。

1 #include <stdio.h>
2 #include <conio.h>
3  char ga[32] = {"Hello World"};
4  void fun1(char ca[])
5 {
6 printf("&ca = %#x \n", &ca);/*%#x:以0x123456的形式打印 */
7 printf("&(ca[0]) = %#x \n", &(ca[0]));
8 printf("&(ca[1]) = %#x \n\n", &(ca[1]));
9 return;
10 }
11  void fun2(char *pa)
12 {
13 printf("&pa = %#x \n", &pa);
14 printf("&(pa[0]) = %#x \n", &(pa[0]));
15 printf("&(pa[1]) = %#x \n", &(pa[1]));
16 printf("++pa = %#x \n\n", ++pa);
17 return;
18 }
19  int main(void)
20 {
21 printf("&ga = %#x \n", &ga);
22 printf("&(ga[0]) = %#x \n", &(ga[0]));
23 printf("&(ga[1]) = %#X \n\n", &(ga[1]));
24 fun1(ga);
25 fun2(ga);
26 getch();
27 }
 

 

打印出:

&ga = 0x402000

&(ga[0]) = 0x402000

&(ga[1]) = 0X402001


&ca = 0x23ff50

&(ca[0]) = 0x402000

&(ca[1]) = 0x402001


&pa = 0x23ff50

&(pa[0]) = 0x402000

&(pa[1]) = 0x402001

++pa = 0x402001

 

 

 

 

posted @ 2011-03-06 17:14  Finux_you  Views(508)  Comments(0Edit  收藏  举报