C陷阱与缺陷--读书笔记3 语义“陷阱”

第三章
 
一、知识点
1、C语言中的数组值得注意的地方有以下两点:(P41)
(1)、C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来。然而,C语言中数组的元素可以是任何类型的对象,当然也可以是另外打的一个数组。
(2)、对于一个数组,我们只能够做两件事:确定该数组的大小,以及获得指向该数组下标为0的元素的指针。其他有关数组的操作,哪怕它们乍看上去十一数组下标进行运算的,实际上都是通过指针进行的。换句话说,任何一个数组下标运算都等同于一个对应的指针运算,因此我们完全可以依据指针行为定义数组下标的行为。
 
2、对于int calendar[12][31]; 这个语句生命了calendar是一个数组,该数组拥有12个数组类型的元素,其中每个元素都是一个拥有31个整型元素的数组。(P42)
 
3、如果两个指针指向的是同一个数组中的元素,我们可以把这两个指针相减。(P43)
 
4、*(a+i)即数组中下标为i的元素的引用。由于a+i与i+a的含义一样,因此a[i]与i[a]也具有同样的含义。(P44)
 
5、来看几个声明:(P45)
int calendar[12][31];
int *p;
int i;
calendar[4]是calendar数组的第5个元素,是calendar数组中12个有着31个整型元素的数组之一。可以有
p = calendar[4];
这个语句使得指针p指向了数组calendar[4]中下标为0的元素。但是
p = calendar;
这个语句是非法的。因为calendar是一个二维数组,在此处的上下文中使用calendar名称会将其转换为一个指向数组的指针;而p是一个指向整型变量的指针,这样的赋值是非法的。
 
6、下面的语句:(P47)
char *r;
strcpy(r, s);
strcat(r, t);
这个语句是不行的,因为不能确定r指向何处。我们不仅要让r指向一个地址,而且r所指向的地址处还应该有内存空间可供容纳字符串,这个内存空间应该是以某种方式已经被分配了的。下面的语句只要s和t不是太大,就可以正常工作:
char r[100];
strcpy(r, s);
strcat(r, t);
再看下面一个例子,动态分配内存大小:
char *r, *malloc();
r = malloc(strlen(s) + strlen(t));
strcpy(r, s);
strcat(r, t);
这个例子也是错的,原因有三:(1)、malloc函数有可能无法提供请求的内存,这种情况下malloc函数会通过返回一个空指针来作为“内存分配失败”事件的信号;(2)。给r分配的内粗你在使用完之后应该及时释放,这一点务必要记住。显式地给r分配了内存,就必须显式地释放内存。(3)、该例子并未分配足够的内存。库函数strlen返回字符串所包括的字符数目,而作为结束标识的空字符并未计算在内。所以需要如下修改:
char *r, * malloc();
r = malloc(strlen(s) + strlen(t) + 1);
if(!r){
     complain();
     exit(1);
}
strcpy(r, s);
strcat(r, t);
 
/*一段时间之后再使用*/
free(r);
 
7、C 语言中会自动地将作为参数的数组声明转换为相应的指针声明。(P49)
 
8、对于以下语句:(P51)
char *p, *q;
p = "xyz";
上面的语句貌似是使得p的值就是字符串“xyz”,然而实际情况并非如此,实际上,p的值是一个指向有'x'、'y'、'z'和‘\0’4个字符组成的数组的起始元素的指针。因此如果执行: q=p; ,p和q现在是两个指向内存中同一个地址的指针。复制指针并不同时复制指针所指向的数据。
 
9、除了一个重要的例外情况,在C语言中将一个整数转换成一个指针,最后得到的结果都取决于具体的C编译器实现。这个特殊情况就是常数0,编译器保证由0转换而来的指针不等于任何有效的指针。当0被转换成指针使用时,这个指针绝对不能被解除引用。换句话说,当我们将0赋值给一个指针变量时,绝对不能企图使用该指针所指向的内存中存储的内容。下面的写法是完全合法的:
if( p == (char *) 0)
但是如果要写成这样:
if(strcmp (p, (char *) 0) == 0)
就是非法的了,原因在于库函数strcmp的实现中会包括查看它的指针参数所指向内存中的内容的操作。(P52)
 
10、只要x和y的取值都限制在0或者1,那么x&y与x&&y总是得出相同的结果。(P68)
 
11、对于数组结尾后的下一个元素,取它的地址是合法的,但是试图去实际地读取这个元素的值结果是未定义的。(P69)
 
12、在无符号算术运算中,没有所谓的“溢出”一说,如果算术运算符的一个操作数是有符号整数,另一个是无符号整数,那么有符号整数会被转换为无符号整数。对于两个操作数都是有符号整数时,“溢出”就有可能发生,而且“溢出”的结果是未定义的。当一个运算的结果发生“溢出”时,作出任何假设都是不安全的。
判断是否溢出的方法:
if(a > INT_MAX - b)
     complain();
(P69)
posted on 2012-05-01 09:19  谷堆旁边  阅读(345)  评论(0编辑  收藏  举报