2.1 这关语言何事
1961年,NASA(美国航空航天局)程序员测试用于Mercury飞行的,计算环绕地球轨道的Fortran子程序.
Do 10 I = 1,10 误写为 Do 10 I = 1.10
malloc(strlen(str)); 任何时候看到这样的语句都几乎可以断定是错误的.
malloc(strlen(str)+1); 才是正确的写法.(字符串结尾符号'\0')
一个'L'的NUL用于结束一个ACSII字符串
两个'L'的NULL用于表示什么都不指向(空指针)
2.2 多做之过
由于存在fall through, switch语句会带来麻烦.
C语言理念: 程序员应该知道直接正在干什么, 而且保证自己的所作所为是正确的.
在C语言中, const关键字并不真正表示常量.()
相邻的字符串常量将被自动合并成一个字符串.
function apple() { /*在任何地方均可见*/}
extern function pear() {/*在任何地方均可见*/}
static function turnip() {/*在这个文件之外不可见*/}
缺省可见是错误的, 应该缺省采用有限可见性.
2.3 误做之过
符号重载:
static
extern
void
*
&
=
==
<=
<<=
<
()
p = N * sizof * q;
sizeof操作符(不是函数)把*q作为操作数.
apple = sizeof(int) * p; ???
运算符优先级:
早起gets()中的Bug导致Internet蠕虫.
gets()函数并不检查缓冲区的空间(事实上也无法检查)
如果调用提供一个指向stack的指针,并且gets()函数读入的字符数量超过了缓冲区空间
gets()函数将多出的字符进行继续写入后续的stack中,覆盖原先stack上的内容.
finger防护进程包含如下代码:
标准参数处理
把lint程序错误地从编译器中分离出来
编译器日期破坏:
1961年,NASA(美国航空航天局)程序员测试用于Mercury飞行的,计算环绕地球轨道的Fortran子程序.
Do 10 I = 1,10 误写为 Do 10 I = 1.10
malloc(strlen(str)); 任何时候看到这样的语句都几乎可以断定是错误的.
malloc(strlen(str)+1); 才是正确的写法.(字符串结尾符号'\0')
一个'L'的NUL用于结束一个ACSII字符串
两个'L'的NULL用于表示什么都不指向(空指针)
2.2 多做之过
由于存在fall through, switch语句会带来麻烦.
C语言理念: 程序员应该知道直接正在干什么, 而且保证自己的所作所为是正确的.
在C语言中, const关键字并不真正表示常量.()
相邻的字符串常量将被自动合并成一个字符串.
char *arr[] = {
'red',
'green'
'blue'
}
自动合并字符串后,实际效果:
char *arr[] = {
'red',
'greenblue'
}
缺省可见:
function apple() { /*在任何地方均可见*/}
extern function pear() {/*在任何地方均可见*/}
static function turnip() {/*在这个文件之外不可见*/}
缺省可见是错误的, 应该缺省采用有限可见性.
2.3 误做之过
符号重载:
static
extern
void
*
&
=
==
<=
<<=
<
()
p = N * sizof * q;
sizeof操作符(不是函数)把*q作为操作数.
apple = sizeof(int) * p; ???
运算符优先级:
早起gets()中的Bug导致Internet蠕虫.
gets()函数并不检查缓冲区的空间(事实上也无法检查)
如果调用提供一个指向stack的指针,并且gets()函数读入的字符数量超过了缓冲区空间
gets()函数将多出的字符进行继续写入后续的stack中,覆盖原先stack上的内容.
finger防护进程包含如下代码:
main(argc, argv)
char *argv[];
{
char line[512];
...
gets(line);
...
}
建议采用fgets彻底取代gets()
gets(line);
//修改为:
if (fgets(line, sizeof(line), stdin) == NULL) exit(1);
2.4 少做之过
标准参数处理
把lint程序错误地从编译器中分离出来
编译器日期破坏:
char * localized_time(char* filename)
{
struct tm *tm_ptr;
struct stat stat_bloc;
char buffer[120];
stat(filename, &stat_block);
tmp_ptr = locatime(&stat_block.st_mtime);
strftime(buffer, sizeof(buffer), "%a %b %e %T %Y", tm_ptr);
return buffer;
}
// 问题: 返回一个指向stack内存的指针, 在函数结束后堆栈内存自动释放.
// 解决方案:
// 1.返回一个指向字符串常量的指针
// 缺点: 只适用于简单字符串
char * func() { return "Only works for simple strings"; }
// 2.使用全局声明的数组
// 缺点: 变量全局可见, 可能被修改, 内容容易被覆盖, 闲置不用时浪费内存空间.
char * func() {
...
my_global_array[i] =
...
return my_global_arry;
}
// 3.使用静态数组
// 缺点: 内容在下次调用时被覆盖.闲置不用时浪费内存空间.
char * func() {
static char buffer[20];
...
return buffer;
}
// 4.显示分配内存
// 缺点: 调用者负责内存释放, 内存分配与释放位置比较乱, 容易造成内存泄露.
char * func() {
char * s = malloc(120);
...
return s;
}
// 5.调用者申请内存
//
void func(char *result, int size) {
...
strncpy(result, "That'd be in the data segment, Bob", size);
}
buffer = malloc(size);
func(buffer, size);
...
free(buffer);
2.5 轻松一下---有些特性确实就是Bug