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

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)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值