C/C++学习笔记:基础知识5

来源:互联网 发布:鲁班软件 上市 编辑:程序博客网 时间:2024/05/17 07:51

1 main函数

       主函数是一个特殊的函数,不管把它放在代码的什么位置,每个程序的运行都是从主函数开始的。

(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的第三个参数中

浮点运算

电脑都是用二进制来表示浮点和整数的,在对一些二进制中无法精确表示的小数进行赋值或读入再输出时, 也就是从十进制转成二进制再转回十进制, 你会观察到数值的不一致. 这是由于编译器二进制/十进制转换例程的精确度引起的。

电脑是用一种浮点的格式来近似的模拟实数的运算, 注意是近似, 不是完全。下溢、误差的累积和其它非常规性是常遇到的麻烦。

不要假设浮点运算结果是精确的, 特别是别假设两个浮点值可以进行等价比较.

浮点数的定义决定它的绝对精确度会随着其代表的值变化, 所以比较两个浮点数的最好方法就要利用一个精确的阈值。

这个阈值和作比较的浮点数值大小有关。

//不要用下面的代码: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);

可变参数

用 <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)


0 0
原创粉丝点击