C/C++学习笔记:基础知识5
2014-08-20 21:16
591 查看
1 main函数
主函数是一个特殊的函数,不管把它放在代码的什么位置,每个程序的运行都是从主函数开始的。
(1)全局对象的构造函数会在 main 函数之前执行。
main 主函数执行完毕后,可能会再执行一段代码,如下:
此外,全局类的析构函数也是在main()后面执行。
(2)主函数的参数就是输入命令行的参数,主函数不能被其他函数调用
int main( int argc, char *argv[], char *envp[] )
argc表示少命令行参数,第一个就是执行程序名,所argc最少为1。
argv具体参数
envp系统环境变量,“名称=值”形式,以NULL结束
(3)c语言实现都是通过函数mian的返回值来告诉操作系统函数的执行是否成功
0表示程序执行成功,返回非零表示程序执行失败,具体值表示某种具体的出错信息,别的函数不能调用main函数,但系统可以调用main的。
2 浮点运算
电脑都是用二进制来表示浮点和整数的,在对一些二进制中无法精确表示的小数进行赋值或读入再输出时, 也就是从十进制转成二进制再转回十进制, 你会观察到数值的不一致. 这是由于编译器二进制/十进制转换例程的精确度引起的。
电脑是用一种浮点的格式来近似的模拟实数的运算, 注意是近似, 不是完全。下溢、误差的累积和其它非常规性是常遇到的麻烦。
不要假设浮点运算结果是精确的, 特别是别假设两个浮点值可以进行等价比较.
浮点数的定义决定它的绝对精确度会随着其代表的值变化, 所以比较两个浮点数的最好方法就要利用一个精确的阈值。
这个阈值和作比较的浮点数值大小有关。
3 可变参数
用 <stdarg.h> 提供的辅助设施,定义可变参数的函数
标准 C 要求用可变参数的函数至少有一个固定参数项, 这样你才可以使用va start()
4 其他
编译有问题时通常的检查要点
(1)未初始化的局部变量
(2)整数上溢, 特别是在一些 16 比特的机器上, 一些中间计算结果可能上溢, 象 a* b / c
(3)未定义的求值顺序
(4)忽略了外部函数的说明, 特别是返回值不是 int 的函数, 或是参数 “缩小” 或可变的函数
(5)复引用空指针, 参见第 5 章。
(6)malloc/free 的不适当使用: 假设 malloc 的内存都被清零、已释放的内存还可用、再次释放已释放内存、malloc 的内部被破坏
(7)指针类常规问题, 参见问题 16.7。
(8)printf() 格式与参数不符, 特别是用 %d 输出 long int
(9)试图分配的内存大小超出一个 unsigned int 类型的范围, 特别是在内存有限的机器上
(10)数组边界问题, 特别是暂时的小缓冲, 也许用于 sprinf() 来构造一个字符串,
(11)错误的假设了 typedef 的映射类型, 特别是 size_t
(12)浮点问题, 参见问题 14.1 和 14.4。
(13)任何你自己认为聪明的在特定机器上的机器代码生成小技巧
判断机器的字节顺序是高字节在前还是低字节在前?
有个使用指针的方法:
断言:
assert() 是个定义在 <assert.h> 中的宏, 用来测试断言。一个断言本质上是写下程序员的假设, 如果假设被违反, 那表明有个严重的程序错误。
例如, 一个假设只接受非空指针的函数, 可以写:
assert(p != NULL);
一个失败的断言会中断程序。断言不应该用来捕捉意料中的错误, 例如malloc() 或 fopen() 的失败。
//判断闰年
year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
主函数是一个特殊的函数,不管把它放在代码的什么位置,每个程序的运行都是从主函数开始的。
(1)全局对象的构造函数会在 main 函数之前执行。
main 主函数执行完毕后,可能会再执行一段代码,如下:
//可以使用atexit()函数,注册一个函数 //atexit()以栈的方式注册函数,先调用的最后输出,后调用的最先输出 #include <stdlib.h> #include <stdio.h> int atexit(void (*function")(void)); void fn1( void ), fn2( void ), fn3( void ), fn4( void ); int main( void ) { atexit( fn1 ); atexit( fn2 ); atexit( fn3 ); atexit( fn4 ); printf( "This is executed first.\n" ); } void fn1(){ printf( "next.\n" );} void fn2(){ printf( "executed " );} void fn3(){ printf( "is " );} void fn4(){ printf( "This " );} //输出结果 This is executed first. This is executed next.
此外,全局类的析构函数也是在main()后面执行。
(2)主函数的参数就是输入命令行的参数,主函数不能被其他函数调用
int main(int argc, char *argv[]); int main(int argc, char **argv); int main(void); void main(int argc, char *argv[]); void main(int argc, char **argv); void main(void);
int main( int argc, char *argv[], char *envp[] )
argc表示少命令行参数,第一个就是执行程序名,所argc最少为1。
argv具体参数
envp系统环境变量,“名称=值”形式,以NULL结束
(3)c语言实现都是通过函数mian的返回值来告诉操作系统函数的执行是否成功
0表示程序执行成功,返回非零表示程序执行失败,具体值表示某种具体的出错信息,别的函数不能调用main函数,但系统可以调用main的。
int main(int argc, char **argv, char **env) { int i; for(i=0; env[i]; ++i) printf("%s\n", env[i]); return 0; } //其实函数 //char *getenv( const char *varname ); //的返回值就在main的第三个参数中
2 浮点运算
电脑都是用二进制来表示浮点和整数的,在对一些二进制中无法精确表示的小数进行赋值或读入再输出时, 也就是从十进制转成二进制再转回十进制, 你会观察到数值的不一致. 这是由于编译器二进制/十进制转换例程的精确度引起的。
电脑是用一种浮点的格式来近似的模拟实数的运算, 注意是近似, 不是完全。下溢、误差的累积和其它非常规性是常遇到的麻烦。
不要假设浮点运算结果是精确的, 特别是别假设两个浮点值可以进行等价比较.
浮点数的定义决定它的绝对精确度会随着其代表的值变化, 所以比较两个浮点数的最好方法就要利用一个精确的阈值。
这个阈值和作比较的浮点数值大小有关。
//不要用下面的代码: double a, b; if (a == b) /* 错! */ //要用类似下列的方法: #include <math.h> if (fabs(a - b) <= epsilon * fabs(a)) //epsilon 被赋为一个选定的值来控制 “接近度”。你也要确定 a 不会为 0 //取整数最简单、直接的方法: (int)(x + 0.5); //这个方法对于负数并不正常工作。可以使用一个类似的方法 (int)(x < 0 ? x - 0.5 : x + 0.5);
3 可变参数
用 <stdarg.h> 提供的辅助设施,定义可变参数的函数
标准 C 要求用可变参数的函数至少有一个固定参数项, 这样你才可以使用va start()
//把任意个字符串连接起来的函数, 结果存在 malloc 的内存中: #include <stdlib.h> /* 说明 malloc, NULL, size_t */ #include <stdarg.h> /* 说明 va_ 相关类型和函数 */ #include <string.h> /* 说明 strcat 等 */ char *vstrcat(const char *first, ...) { size_t len; char *retbuf; va_list argp; char *p; if(first == NULL) return NULL; len = strlen(first); va_start(argp, first); while((p = va_arg(argp, char *)) != NULL) len += strlen(p); va_end(argp); retbuf = malloc(len + 1); /* +1 包含终止符 \0 */ if(retbuf == NULL) return NULL; /* 出错 */ (void)strcpy(retbuf, first); va_start(argp, first); /* 重新开始扫描 */ while((p = va_arg(argp, char *)) != NULL) (void)strcat(retbuf, p); va_end(argp); return retbuf; } //调用如下: char *str = vstrcat("Hello, ", "world!", (char *)NULL); //注意最后一个参数的类型重置; 参见问题 5.2, 15.3。注意调用者要释放返回的存储空间, 那是用 malloc 分配的 //error() 函数, 它列印一个出错信息, 在信息前加入字符串 “error: ”和在信息后加入换行符: #include <stdio.h> #include <stdarg.h> void error(const char *fmt, ...) { va_list argp; fprintf(stderr, "error: "); va_start(argp, fmt); vfprintf(stderr, fmt, argp); va_end(argp); fprintf(stderr, "\n"); }
4 其他
编译有问题时通常的检查要点
(1)未初始化的局部变量
(2)整数上溢, 特别是在一些 16 比特的机器上, 一些中间计算结果可能上溢, 象 a* b / c
(3)未定义的求值顺序
(4)忽略了外部函数的说明, 特别是返回值不是 int 的函数, 或是参数 “缩小” 或可变的函数
(5)复引用空指针, 参见第 5 章。
(6)malloc/free 的不适当使用: 假设 malloc 的内存都被清零、已释放的内存还可用、再次释放已释放内存、malloc 的内部被破坏
(7)指针类常规问题, 参见问题 16.7。
(8)printf() 格式与参数不符, 特别是用 %d 输出 long int
(9)试图分配的内存大小超出一个 unsigned int 类型的范围, 特别是在内存有限的机器上
(10)数组边界问题, 特别是暂时的小缓冲, 也许用于 sprinf() 来构造一个字符串,
(11)错误的假设了 typedef 的映射类型, 特别是 size_t
(12)浮点问题, 参见问题 14.1 和 14.4。
(13)任何你自己认为聪明的在特定机器上的机器代码生成小技巧
判断机器的字节顺序是高字节在前还是低字节在前?
有个使用指针的方法:
int x = 1; if(*(char *)&x == 1) printf("little-endian\n"); else printf("big-endian\n");
断言:
assert() 是个定义在 <assert.h> 中的宏, 用来测试断言。一个断言本质上是写下程序员的假设, 如果假设被违反, 那表明有个严重的程序错误。
例如, 一个假设只接受非空指针的函数, 可以写:
assert(p != NULL);
一个失败的断言会中断程序。断言不应该用来捕捉意料中的错误, 例如malloc() 或 fopen() 的失败。
//判断闰年
year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
相关文章推荐
- [学习笔记]C和C++中指针的基础知识点(一)
- [学习笔记]C和C++中指针的基础知识点(二)
- cocos2d-x学习笔记(一)C++基础知识
- C/C++学习笔记:基础知识8
- C++学习笔记1--基础知识
- C++学习笔记——基础知识
- C/C++ 基础知识学习笔记 (不断更新中)
- C/C++学习笔记:基础知识9
- C/C++学习笔记---primer基础知识
- C++学习笔记---------基础知识sizeof用法
- C++学习笔记(一)--基础知识sizeof用法
- C++基础学习笔记----第二课(引用的基础知识)
- C/C++学习笔记:基础知识7
- C/C++学习笔记:基础知识2
- C/C++学习笔记:基础知识4
- C++基础知识学习笔记(一)
- C/C++学习笔记:基础知识
- C++学习笔记1--基础知识
- C++学习笔记(第一章 C++的基础知识 之一)
- 【C++面向对象学习笔记】-基础知识