C程序设计语言读书笔记(6)

        结构是一个或多个变量的集合,这些变量可能为不同的类型,为了处理的方便而将这些变量组织在一个名字之下。

#include <stdio.h>
struct name 
{
	char* name;
	int id;
}t, *pt;
char *name = "JOHN";
int main()
{
	struct name s = {"MIKE", 1};
	struct name ts = s;
	t.name = "MAY";
	t.id = 2;
	pt = &t;

	printf("%s %d\n", s.name, s.id);
	printf("%s %d\n", ts.name, ts.id);
	printf("%s %d\n", pt->name, pt->id);
	printf("%s %d\n", t.name, t.id);
	printf("%s\n", name);
	return 0;
}

        该程序中,我特地把结构成员、结构标志和普通变量名都定为name,以说明他们同名是合法的。需要指出的是,结构中也可以嵌套结构。

        以上的程序展示了结构变量的两种声明方法和两种初始化的方法,以及怎么访问结构成员和结构的赋值。当然,也允许有结构数组。这些用法和基本类型无异,只是看起来在某些地方多了个关键字struct而已。

 

        现在总结一下结构的合法操作:作为一个整体复制和赋值,通过&运算符取地址,访问其成员。其中,复制和赋值包括向函数传递参数以及从函数返回值。结构间不可以进行比较。可以用一个常量成员值列表初始化结构,自动结构也可以通过赋值进行初始化。

 

        接着来看下sizeof这个编译时的一元运算符,它可以用来计算任一对象的长度。因为他是编译时运算符,类似sizeof(i++)的语句会在编译时确定i++类型的大小,所以在运行时候不会在递增i的值。

        表达式

        sizeof 对象

        以及

        sizeof(类型名)

        将返回一个整数值,它等于指定对象或类型占用的存储空间字节数。

        以下是利用sizeof来计算一个数组项数的两种写法:
        #define NKEYS (sizeof keytab / sizeof(struct key))
        #define NKEYS (sizeof keytab / sizeof keytab[0])

        其中keytabstruct key类型的数组。

        我想说的是,使用第二种写法的话,即使keytab类型改变了,也不需要改动程序。


        结构的长度不一定等于各成员长度的和。因为不同的对象有不同的对齐要求,所以,结构中可能会出现未命名的“空穴”。例如,假如char类型占用一个字节,int类型占用4个字节,则下列结构:

struct  
{
	char c;
	int i;
};

        可能需要8个字节的存储空间,而不是5字节。使用上述的sizeof运算符可以返回正确的对象的长度。

 

        C语言中提供了一个称为typedef的功能,它用来建立新的数据类型名。但从任何意义上讲,typedef声明并没有创建一个新类型,它只是为某个已存在的类型增加一个新的名称而已。

例如: typedef int Length;

        类似地,声明

        typedef char *String

        将String定义与char *或字符指针同义,此后,便可以在类型声明中和类型转换中使用String

        可以发现,typedef类似于#define语句,但为什么要需要typedef语句呢?一定有什么不同的吧!下面我们来重点看看这两者的差异。

        从表面上看,typedef是语句,后面有分号,而define定义结束后没有分号。

        #define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错。

        而由于typedef是由编译器解释的,因此它的文本替换功能要超过预处理器的能力。例如:

            typedef int (*PFI)(char *, char *);

        该语句定义了类型PFI是“一个指向函数的指针”,该函数具有两个char *类型的参数,返回值类型为int *,它可用于某些上下文。

        下面举个例子,解释一下define的简单文本替换和typedef有什么不同。

#include <stdio.h>
#define PINT int *
typedef int * pint ;
int main()
{
	int a = 1;
	int b = 2;
	const PINT pa = &a; //pa可更改,但是p指向的内容不可更改。
	const pint pb = &b; //pb不可更改,但p指向的内容可更改

	//*pa = 4; 错误
    //pb = &a; 错误
	pa = &b;
	*pb = 4; //正确
	return 0; //正确
}

        const PINT pa = &a;被简单替换成了const int *pa = &a;

        在const pint pb = &b;中,pint被当成了一种类型。类比const int n = 3;这个语句使得n的值不能改变,同理const pint pb = &b;中pb的值不能更改,但指向的内容可以更改。

        使用typedef的好处有:

      1.使表达方式更简洁。

      2.提高程序的可移植性。

      3.为程序提供更好的说明性。

 

        本章接下来讲了一个我从没接触过内容——联合。第一次遇到这个概念。

        联合是可以(在不同时刻)保存不同类型和长度的对象的变量,编译器负责跟踪对象的长度和对其要求。联合提供了一种方式,以在单块存储区中管理不公类型的数据,而不需要在程序中嵌入任何机器有关的信息。

        联合的语法基于结构:

union u_tag
{
	int ival;
	float fval;
	char *sval;
} u;

        变量u必须足够大,以保存类型中最大的一种,具体长度同具体的实现有关。这些类型中的任何一种类型的对象可以赋值给u

#include <stdio.h>
union u_tag
{
	int ival;
	float fval;
	char *sval;
} ;
int main()
{
	union u_tag u = {3};//联合只能用其第一个成员类型的值进行初始化。
	u.fval = 3.3;
	u.ival = 3;
	u.sval = "hello world.";
	printf("%d\n", sizeof(union u_tag));
	printf("%d\n", u.ival);
	printf("%f\n", u.fval);
	printf("%s\n", u.sval);
	return 0;
}

        以上程序只能正确显示最后一次赋值的字段。使用联合时,我们可以先判断在联合中存储什么类型,在操作相应的字段。

        对联合允许的操作与对结构允许的操作相同。联合可以使用在结构和数组中,反之亦然。

 

        C语言中还可以直接定义和访问一个字中的位字段,而不需要通过按位逻辑运算符。

struct 
{
	unsigned int is_keyword : 1;//字段被声明为unsigned int类型,以保证它们是无符号的。
	unsigned int is_extern : 1;
	unsigned int is_static : 1;
}flags;//这里定义了一个变量flags,它包含个位字段。冒号后面的数字表示字段的宽度。

        这样,可以用结构访问成员的方式去操作相应的位。字段也可以仅仅声明为int,为方便移植,需要显示声明该int类型是signed还是unsigned类型。字段不是数组,并且没有地址,因此对它们不能使用&运算符。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值