C语言学习之字符串,字符,字节,结构和联合

1. 字符串

        字符串就是一串零个或多个字符,并且以一个位模式全为0的NUL字节结尾。

头文件string.h包含了使用字符串函数所需要的原型和声明。

memxxx函数提供了累死你字符串函数的能力,但是可以处理包括NUL字节在内的任意字节。

2. 结构和联合

结构也是一些值得集合,这些值也称之为它的成员,但是一个结构的各个成员可能具有不同的类型。结构不能通过下标来访问他们,每个结构成员都有自己的名字,他们是通过名字访问的。结构变量无法使用下标来选择特定的成员。结构变量属于标量类型。

在声明结构时,必须列出它包含的所有成员,这个列表包括每个成员的类型和名字:

struct tag{ member-list} variable-lsit;      如:

struct        {

                        int        a;

                        int         b;

                        int        c;

} y[20], *z;                                                直接声明

或者

struct        SIMPLE{

                                int        a;

                                char        b;

                                float        c;

};

struct        SIMPLE x;

struct        SIMPLE y[20], *z;                                标签

标签标识了一种模式,用于声明未来的变量,但是无论是标签还是模式,其本身都不是变量。

声明结构时可以使用的另一种良好技巧是用typedef创建一种新的类型,如下:

typedef struct{

                int        a;

                char        b;

                float        c;

}simple;

simple        x;

simple y[20], *z;

如果想要在多个源文件中使用同一种类型的结构,就应该把标签声明或typedef形式的声明放在一个头文件中。如果源文件需要这个声明,可以使用#include指令把那个头文件包含进来。

结构成员可以是标量,数组,指针甚至是其他结构。

结构成员的直接访问。结构变量的成员是通过点操作符(.)访问的。

结构成员的间接访问。如果你拥有一个指向结构的指针,首先需要对指针执行间接访问操作,从而获得这个结构,然后再使用点操作符来访问它的成员。如

void func( struct COMPLEX *cp);

(*cp).f

箭头操作符(->)和点操作符一样,箭头操作符接受两个操作数,但左操作数必须是一个指向结构的指针,箭头操作符对左操作数执行间接访问取得指针所指向的结构,然后和点操作符一样,根据右操作数选择一个指定的结构成员。如:

cp->f

结构的自引用:

struct SELF_REF1{

                       int        a;

                        struct        SELF_REF1  b;

                        int        c;

};

这种类型的自引用是非法的,中间自引用的b是另外一个完整的结构,它会一直递归下去。整个结构体的长度是确定不了的。

struct SELF_REF1{

                       int        a;

                        struct        SELF_REF1  *b;

                        int        c;

};

编译器在结构长度确定在之前就已经知道指针的长度,所以这种类型自引用是合法的。

结构的初始化:一个位于一对花括号内部,由逗号分隔的初始值列表可用于结构中各个成员的初始化。这些值根据结构成员列表的顺序写出,如果初始列表的值不够,剩余的结构成员将使用缺省值进行初始化。

结构体数据存储的对齐规则:所有的成员在分配内存时都要与所有成员中占内存最多的数据类型所占内存空间的字节数对齐。假如这个字节数为 N,那么对齐的原则是:理论上所有成员在分配内存时都是紧接在前一个变量后面依次填充的,但是如果是“以 N 对齐”为原则,那么,如果一行中剩下的空间不足以填充某成员变量,即剩下的空间小于某成员变量的数据类型所占的字节数,则该成员变量在分配内存时另起一行分配。

作为函数参数的结构体:

typedef struct{

                        char        product[PRODUCT_SIZE]};

                        int        quantity;

                        float        uint_price;

                        float        total_amount;

} Transaction;

void print_receipt(Transaction trans)

{

        printf("%s\n", trans.product);

        printf("%d@%.2f total %.2f\n", trans.quantity, trans.uint_prince,trans.total_amount);

}

这种方式能够产生正确的结果,但它的效率很低,因为C语言的参数传值调用方式要求把参数的一份副本传递给函数。如果PRODUCT_SIZE的值为20,而且我使用的机器上整数和浮点数都占4字节,那么这个结构将占据32字节的空间。要想把它作为参数进行传递,则必须把32字节复制到堆栈中,以后再丢弃。

void print_receipt(Transaction *trans)

{

        printf("%s\n", trans->product);

        printf("%d@%.2f total %.2f\n", trans->quantity, trans->uint_prince,trans->total_amount);

}

如果传递给函数的屙屎一个指向结构的指针,指针比整个结构要小得多,所以把它压到堆栈上效率能高得多。这种方式的缺陷在于函数现在可以对调用程序的结构变量进行修改。如果不希望如此,可以用const关键字来防止此类修改。

void print_receipt(register Transaction const *trans)

{

        printf("%s\n", trans->product);

        printf("%d@%.2f total %.2f\n", trans->quantity, trans->uint_prince,trans->total_amount);

}

位段:位段的声明和结构类似,但它的成员是一个或多个位的字段,这些不同长度的字段实际上存储于一个或多个整型变量中。位段成员必须声明为int,singned int或unsigned int类型。其次,在成员名的后面是一个冒号和一个整数,这个整数指定该位段所占用的位的数目。

注重可移植性的程序应该尽量避免使用位段。

struct CHAR        {

                unsigned ch : 7;

                unsigned font : 6;

                unsigned size : 19;

};

struct CHAR ch1;

使用位段只是基于方便的目的,任何可以用位段实现的任务都可以使用移位和屏蔽来实现。

联合

联合的声明和结构类似,但它的行为方式却和结构不同。联合的所有成员引用的是内存中相同的位置,如果想把在不同的时刻把不同的东西存储于同一个位置就可以使用联合。如:

union        {

                float         f;

                int            i;

}fi;

在一个浮点型和整形都是32位的机器上,变量fi只占据内存中一个32位的字,如果成员f被使用,这个字就作为浮点值访问,如果成员i被使用,这个值就作为整型值访问。

如果联合的各个成员具有不同的长度,联合的长度就是它最长成员的长度。如果这些成员长度相差悬殊,当存储长度较短的成员时,浪费的空间时相当可观的。子这种情况下,更好的办法是在联合中存储指向不同成员的指针而不是直接存储成员本身。

联合的初始化

联合变量可以被初始化,但这个初始值必须是联合第一个成员的类型,而且它必须位于一对花括号里面,如:

union        {

                int        a;

                float     b;

                char      c[4];

}x = { 5 };

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值