Chinaunix首页 | 论坛 | 博客
  • 博客访问: 131488
  • 博文数量: 47
  • 博客积分: 2405
  • 博客等级: 大尉
  • 技术积分: 385
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-28 09:33
文章分类

全部博文(47)

文章存档

2014年(5)

2012年(5)

2011年(7)

2009年(30)

我的朋友

分类: C/C++

2009-07-13 22:04:56

真正深入学习C语言已经3年有余了。不过还是有很多知识点没有记下来,在此总结一下,也帮助C语言新手度过新手难关。

如果你已经认真阅读过谭浩强C,那么复习如下知识大约需要1个小时:)

本篇是《帮你度过C语言新手阶段》系列的最后一篇。

第三十五关:

char *a;

scanf(”%s”,a);

上述程序是绝对禁止的,是错误的。正确的写法如下:

char *a,str[10];

a=str;

scanf(”%s”,a);

第三十六关:

用指针变量来指向一个格式字符串,可以用它来代替printf函数中的格式字符串,如:

char *format;

format=”a=%d,b=%f\n”;

printf(format,a,b);

其实format也可以定义为char format[]形式,但不建议,因为用指针的话,可以很方便指向另一个格式字符串。

第三十七关:

声明一个指向函数的指针:int (*p)(); 定义p是一个指向函数的指针变量,此函数带回整型的返回值。

所以定义指向函数的指针时,只需要注意返回值相匹配即可,而形参部分不需要考虑。

注意,如果写成int *p();由于()的优先级高于*,就变成了声明一个函数,它的返回值是指向整型的指针。

使用p的方法:

int max(int a, int b);

p=max;

num=(*p)(3,5);

在一个程序中,一个指针变量可以先后指向返回类型相同的不同函数。

第三十八关:

用指向函数的指针做函数参数:

sub(int (*x1)(int),int (*x2)(int,int));

这里的参数列表可以选择不写(不推荐此种写法),即sub(int (*x1)(),int (*x2)());,不过如果写参数,就必须要写全写正确。

虽然C允许在参数中用()省略掉形参表,但是,从一个良好的程序风格来看,还是应当禁止这样的使用。

第三十九关:

指针数组的定义:

char *name[]={”follow me”,”basic”,”great wall”,”fortran”,”computer”};

name代表该指针数组的首地址,name+i是name[i]的地址。

程序举例:

char *name[]={”follow me”,”basic”,”great wall”,”fortran”,”computer”};

char **p;

int i;

for (i=0;i<5;i++){

p=name+i;

printf(”%s\n”,*p);

}

第四十关:

struct定义一定不要忘了最后的分号:

struct 结构体名

{成员列表};

在引用结构体变量的域时,*p.num相当于*(p.num),因为.的优先级是最高的!

第四十一关:

共用体的定义为:

union 共用体名称

{

成员列表;

}变量列表;

例如:

union data

{

int i;

char ch;

float f;

}a,b,c;

共用体变量所占的内存长度是最长的成员的长度。

在引用共用体变量时应十分注意当前存放在共用体变量中的究竟是哪一个成员。

&a、&a.i、&a.ch、&a.f都是同一个地址值。

不能对共用体变量名赋值,也不能企图引用变量名得到一个值,更不能在定义共用体时对它初始化。

第四十二关:

声明枚举类型的举例:

enum weekday{sun,mon,tue,wed,thu,fri,sat};

声明了枚举类型之后,就可以用枚举类型来定义变量:

enum weekday workday,weekend;

对于枚举元素,C语言编译时的顺序使它们的值为0,1,2…

workday=mon;

printf(”%d”,workday);

则会显示1

当然你可以改变这种现状:

enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat}workday,weekend;

此时,sun=7,mon=1,tue=2…以此类推

一个整数不能直接赋值给一个枚举变量,而要先进行类型转换:

workday=(enum workday)2;

第四十三关:

用typedef声明结构体类型:

typedef struct

{

int month;

int day;

int year;

}DATE;

这样就声明了新的类型DATE,然后就可以用DATE来声明结构体变量了。如DATE birthday;DATE *p;

用typedef声明数组类型:

typedef int NUM[100];

然后就可以用NUM来定义数组变量:

NUM n;

第四十四关:

C语言的位运算有6个运算符:

1 与&

2 或|

3 异或^

4 取反~

5 左移<<

6 右移>>

位运算的运算量只能是整型或字符型,不能是其他类型,否则会报错。

按位与:用于清零或提取某一位

按位或:用于置1

异或:用于交换两个整型值或两个字符型值。如a=a^b;b=b^a;a=a^b;

取反:令最低位置1。如a=a&~1。此方法适用于在32位和64位机之间兼容。

左移:相当于乘以2,右补0。

右移:如果首位为0,则左补0;如果首位为1,则分为逻辑右移和算术右移两种情况。

逻辑右移:左补0

算术右移:左补1

第四十五关:

位段的概念非常重要,在编写网络程序常会用到。

struct packet_data

{

unsigned a:2;

unsigned b:6;

unsigned c:4;

unsigned d:4;

int i;

}data;

当然也可以不恰好占满一个字节,如

struct packet_data

{

unsigned a:2;

unsigned b:3;

unsigned c:4;

int i;

}data;

这样的话a,b,c会占去2字节中的前9位,而后7位会空闲下来,而i会从另一个新字节开头开始。

在引用位域时,要特别注意其最大值范围,如占2位,那么最大值为3.

位段成员的类型只能指定为unsigned int或int型。

若要强制一个域从新字节开始,那么可以这样:

unsigned a:1;

unsigned b:2;

unsigned :0;

unsigned c:3;

此时c会从一个新字节开始存储。

位段可以用%d来输出。

可以定义无名位段,表示这些位我不用:

unsigned a:1;

unsigned :2; //这两位空间我不用

unsigned c:3;

第四十六关:

在缓冲文件系统中,有一个概念叫做“文件指针”。

在stdio.h中有关FILE结构体类型的声明:

typedef struct
{
short level;    //缓冲区满或空的程度
unsigned flags;    //文件状态标志
char fd;    //文件描述符
unsigned char hold;    //如无缓冲区不读取字符
short bsize;    //缓冲区的大小
unsigned char *buffer;    //数据缓冲区的位置
unsigned char    *curp;    //指针、当前的指向
unsigned istemp;    //临时文件,指示器
short token;    //用于有效性检查
}FILE;

可见,其实FILE也是一个由typedef定义过的类型,其本质是一个结构体类型,其中有很多域,存储着和这个文件相关的各种各样的信息。

在进行文件读写操作时,建议不要使用fprintf和fscanf函数,而尽量使用fread和fwrite函数。

over~


阅读(1163) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~