C专家编程(Expert C Programming)
一基本概念
1、与时间相关的几个函数
char *ctime( const time_t *timer );
Each of these functions returns a pointer to the character string result. If time represents a date before midnight, January 1, 1970, UTC, the function returns NULL
The ctime function converts a time value stored as a time_t structure into a character string. The timer value is usually obtained from a call to time, which returns the number of seconds elapsed since midnight (00:00:00), January 1, 1970, coordinated universal time (UTC). The string result produced by ctime contains exactly 26 characters and has the form:
Wed Jan 02 02:03:55 1980\n\0
#include <time.h>
#include <stdio.h>
void main( void )
{
time_t ltime;
time( <ime );
printf( "The time is %s\n", ctime( <ime ) );
}
struct tm *gmtime( const time_t *timer );
Converts a time value to a structure.
Converts a tmtime structure to a character string.
char *asctime( const struct tm *timeptr );
2、效率到上。
3、尽量不要使用无符号数。不然会在系统默认的类型转换中,将负数升级而出错。只有在使用位段和二进制掩码时,才用无符号数。
#include "iostream"
using namespace std;
void main( void )
{
int d=-1;
if(d<sizeof(d)) cout<<"OK"<<endl;
else cout<<"OK2"<<endl;
}
输出结果为OK2.因为在比较中,将int升级成unsigned int,从而d成为很大的数。当然,只是中间变量,d的值不变。
3、无论什么时候看到malloc(strlen(str))都是错的,应当加1.
4、NUL表示结束一个ASCII字符串,而NULL表示什么也不指向(空指针)。ASCII字符中零的位模式被称为NUL。
5、const并不真正表示常量,与常数7等有本质区别。break是跳出循环或swtich语句。
6、C语言中的符号重载
7、结合性用来解决相同优先级问题。
8、gets
char * gets(char *str)
读取的字符指针str,操作错误返回NULL,从标准输入流读取字符串并回显,读到回车符时退出
gets()会把多出来的字符压到堆栈中。
char s[2];
gets(s);
这会出问题。
常用fgets来替换gets()来解决。
char *fgets(char *str, int num, FILE *fp)
str 存放读入的字符数组指针,num 最大允许的读入字符数,fp 文件指针。读一行字符,该行的字符数不大于num-1,操作成功时返回str指针,失败时返回NULL
char s[2];
if(fgets(s,sizeof(s),stdin)==NULL) exit(0);
9、返回局部变量的隐患
char* DoIt(){
char s[12];
strcpy(s,"Ok");
return s;
}
由于局部变量在堆栈中分配内存,当函数执行完后,其内存被回收,这样它返回的内容可能被下一个内容覆盖。
解决方法:
可以全局变量,静态数组。最好的方法就是要求调用者分配内存来保存函数的返回值,反映定大小。
#include "iostream"
using namespace std;
void DoIt(char *result,int size){
//...
strcpy(result,"OK");
}
int main()
{
int size=10;
char* buffer=(char*)malloc(size);
DoIt(buffer,size);
//...
free(buffer);
}
10、常指针
char *p1="ok";
char **p2=&p1;
char* const *p=p2;
我们要记住,只要const与类型相邻,则其将修饰类型,否则才修饰变量。
如
int const *p1;
const int *p2;
int *const p3;
//p3=p1;
只有在第三种情况下,const才修饰p3,前两种情况下,const都是修饰int。
11、结构中也允许存在位段,无名字段,以及字对齐所需的填充字段。通过在字段的声明后面加一个冒号以及一个表示字段字长的整数来实现的。
struct pid_tag{
unsigned int inactive :1;
unsigned int :1;
};
称为深入逻辑元件的编程。位段的类型必须是int,unsigned int,signed int.
12、“在调用函数时,参数按照从右到左的次序压到堆栈里”是不完全正确的。一个int型参数一般会被传递到寄存器中,而结构参数则很可能被传递到堆栈中。
关于联合
在结构中,每个成员依次存储,而在联合中,所有成员都从偏移地址零开始存储。这样,每个成员的位置都重叠在一起:在某一时刻,只有一个成员真正存储于该地址。
关于枚举
把一串名字与一串整形值联系在一起。
13、数组和指针
如下两个图显示字符指针与字符数组解析的差异
我们可以发现,定义成char p[10];
而在声明中声明为extern char* p时。
查找p[i]将按下面的思路进行。
本来p是一个数组,p[i]是一个字符,而现在声明为指针,则按指针那一套来处理,这样[p+i]就能找到正确数据,而成了[[p]+i],取出来的结果肯定不正确。所以是类型不匹配。
14、链接
编译器创建一个输出文件,这个文件包含了可重定位的对象。这些对象就是与源程序对应的数据和机器指令。
如果函数库的一份拷贝是可执行文件的物理组成部分,那么我们就称之为静态链接。如果可执行文件只是包含了文件名,让载入器在运行时能够寻找程序所需要的函数库,我们称之为动态链接。
链接器通过把库文件名或路径名植入可执行文件中来做到运行链接时的函数查找。静态链接也只是嵌入了所需要的函数。动态库-每一个链接到该函数库的程序都共享它的同一份拷贝,而静态链接则是每一个对象都拥有一份该函数库内容的拷贝。函数库应当始终使用与位置无关的代码。
纯代码:不必进行修改就可以被其它进程执行。