指针和数组是非常容易混淆的两种数据类型,K&R和C专家编程里面的叙述都比较杂乱,没办法,因为C对于这两者的一些规定本身就很混乱。这里把我最近的学习成果整理一下。
1.声明与定义
指针的定义格式如下:
- type_t *p = ?;
-
/*
-
这里的type_t可以任何C语言内嵌的类型,如int,char,也可以是结构体、函数等等;
-
?代表的可以是一个地址常数、一个&取址表达式、或者另一个指针、如果考虑强制类型转换它可以是任意的表达式或者变量。
- 定义产生的符号p即为指针型变量,他和unsigned long型的变量其实没有什么区别。一般来说就是一个32位的无符号整数,表示虚拟空间的某个地址值。
-
*/
数组的定义格式如下:
- type_t a[100] = "mario love lulu";
- /*
- type_t 如前面所述;a即为数组名,其实作用于a的操作可以说是混乱的最大来源之一。
- */
Note1:数组在声明时可以不指定长度,因为声明时连接器还不需要决定为符号分配多少空间;
Note2:新的编译器允许动态指定数组长度,即数据定义时可以用一个变量来制定长度。
Note3:字符串"abc"的长度为4,它其实是'a' 'b' 'c' '\0'
Note4:a[] = "mario love lulu"这种初始化方法只允许与用于定义中,在表达式中不允许这样用,实际上,这种定义形式所包含的操作并没有被翻译成某些指令实现,而是通编译器直接组织数据段的方式来实现。
2.前面说的比较基础,大家可能觉得太简单了,下面来个真正的考题:
写出下面代码的输出:
- #include <stdio.h>
-
-
char ga[] = "abcdefg";
-
-
void my_array_func(char ca[]){
-
printf("addr of array in routine = %#x\n",&ca);
-
printf("what is in this addr? %#x\n",ca);
-
printf("addr of first element of array in routine = %#x\n",&ca[0]);
-
printf("sizeof this array is %d\n",sizeof(ca));
-
}
-
-
main(){
-
printf("value of array symbol in invoker = %#x\n",ga);
- printf("addr of array in invoker = %#x\n",&ga);
-
printf("addr of first elemnet of array in invoker = %#x\n",&ga[0]);
-
printf("sizeof this array is %d\n",sizeof(ga));
-
my_array_func(ga);
-
}
-
~
怎么样,结果是啥呢,这就来揭晓:
- value of array symbol in invoker = 0x804a014
- addr of array in invoker = 0x804a014
-
addr of first elemnet of array in invoker = 0x804a014
-
sizeof this array is 8
-
addr of array in routine = 0xbf93cb10
-
what is in this addr? 0x804a014
-
addr of first element of array in routine = 0x804a014
-
sizeof this array is 4
可以看到,同样一个数组,在传递给函数之前和在子函数内部,其行为特性完全不同了。
很明显,在调用函数之间,编译器对于表达式&ga,直接给出ga的值,也就是该数组的地址;
同时g[0]表示数组的第一个元素,它的地址也就是ga的值即0x804a014。调用sizeof时,程序从符号表里查到ga的大小,并且返回;
另一方面,在子函数中,由于C参数传递永远是传值,也就是传递一份拷贝,即使是传递地址是也是拷贝一个指针变量;同时编译器将所有数组实参全部转化成指向数组第一个元素的指针。在这两条规则的联合作用下,当我们调用my_array_func(ga)时,一个指向数组ga的指针产生了,这个时候,函数内部的参数ca就不再是一个“数组对象”,而是一个赤果果的指针,当然了根据编译器的设定,只要这个指针指向ga的首地址,那么用ga[i]和ca[i]将获得同样的访问效果。此时&ca这个表达式的值是存储ca这个指针变量的地址,也就是0xbf93cb10。而ca的值即为0x804a014。代码中sizeof(ca)等于4也验证了这一点。
综上所述,指针和数组之间的混乱,完全是由数组单方面引起的,指针的行为非常规范,且不存在歧义,而数组由于它流露出“面向对象”的特质,在C语言中的行为表现的无所适从。但是,无论如何,只要掌握几种基本机理,在编程时就能避免混乱的发生。
阅读(2681) | 评论(1) | 转发(1) |