您的位置:首页 > 编程语言 > C语言/C++

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

2014-08-20 21:16 591 查看
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的第三个参数中


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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: