聚合数据类型:包括数组和结构
区别:
1、访问成员方式:
结构成员的个成员长度不相同,所以的结构通过名字来访问.
数组中的数据类型都相同,可以通过下标或指针来访问.
2、左右值
结构是一个标量.和其他任何标量一样,当结构名在表达式中作为右值使用时,他表示存储在结构中的值.
当它作为左值使用时,它表示结构存储的内存位置.但是当数组名在表达式中做为右值使用时,它的值是一个
指向数组第一个元素的指针.由于它的值是一个常量指针,所以数组名不能作为左值使用.
声明格式:
struct tag{ member-list } variable-list
备注: 结构声明:声明时并未分配内存,在创建结构体变量时才分配内存.
首先,结构体是一个数据类型,所以结构体声明实际上就是:定义了一个名为 tag 的结构体数据类型类型,数据类型tag的使用和int、
char等基本类型的使用在声明变量时是有相同之处,同时也要注意到其不同之处。
其中:member-ist结构成员可以是:标量、数组、指针、或其他结构(不能包含自身结构类型,但是可以包含,自身指针的引用)
结构体变量对结构体变量成员操作有两种方式:结构体变量直接引用变量(x.a)和指向该结构体变量指针进行操作("->")。
variable-list:是定义的结构体变量,可以为:单个机构体变量,结构体数组,指向结构体的指针。
例一:
struct tag{ int a; char b};
struct COMPLE
{
int a;
float b;char c;
int *p;
tag tag_a;//包含结构体tag的变量成员
tag *sp;
COMPLE *p_comple;
}x,*p,y[20];
说明:
x: 创建一个名叫"x"的COMPLE结构体成员变量,
p: 同时声明指向结构体的指针;
y[20]:同时建了一个结构数组y,包含20个结构变量元素,
它包含七个成员b变量: 整型a,浮点型b,字符型c,
整形指针p,tag结构体变量tag_a,
指向COMPLE结构体的*p_comple;
其中结构体x变量对成员的引用操作位为:'.';既x.a,x.b,x.c
p=&x;
用指针对结构体x成员的访问操作符"->"既:p->a,p->b,p->c;
例二:
struct tag
{
int a;
char b;
tag *p_tag;
}y={3,'a'},*p;
声明结构体tag时同时创建了tag型结构体变量y和指向tag结构体类型的指针p。
其中*p_tag和*p有什么区别那;
我们可以验证一下:
p=&y;
printf("a=%d,b=%c\n",p->a,p->b);
printf("y address is %d\n",&y);
printf("p_tag address is %d\n",&y.p_tag);
printf("a_ address is %d \n",&y.a);
结果表明:&y==&y.a==p_tag;
- 也就是说:结构体变量的地址和其第一个成员变量的地址是相同的。
- *p_tag指针是在y变量创建时就自动把y的地址赋值给p_tag。
- p只是指向结构体的一个普通指针而已。
注意:
- 结构自引用
结构体不能包含自身的应用
但是可以包含自身指针的引用:因为编译器在确定结构体的长度之前就已经知道指针的长度。所以这是合法的。
事实上这是同一类型的不同结构;
如
struct tag
{
int ;
tag * p_next;
}
- 警惕陷阱:
typedef struct
{
int a;
COMPLE *next;(由于COMPLE 在这时还没有定义,所以声明无效);
} COMPLE
结构体作为函数参数传递值。(见c和指针 结构体作为函数参数传值)
传递给函数的是结构体的指针,指针比整个结构体小很多,把它压到堆栈上的效率能提高很多。传递指针需要付出的代价是函数使用间接访问结构成员。
在许多机器中,你可以吧参数声明为寄存器变量,从而进一步提高指针的传递方案的效率。在有些机器上,这种声明在函数的其实部分还需要额外的指令,
用于把堆栈的参数(参数先传递给堆栈)复制到寄存器,共函数使用。但是,如果函数对这个指令的间接访问次数超过两三次,那么使用这种方法所节省
的时间将远远高于一条额外指令所花费的时间。
想函数传递指针的缺陷在于函数现在可以对调用程序的结构变量进行修改,如果我们不希望如此,可以在函数中使用const 关键字来防止这类修改。
现在函数原型将如; void print_receipt(register Transaction const *trans);
typedef struct
{
char product[ PRODUCT_SIZE ];
int quantity;
float unit_price;
float total_amount;
} Transaction;
void print_receipt(Transaction trans)
{
printf("%s\n,trans.product);
printf("%d@%.2f total %.2f\n",trans.quantity,trans.unit_price,trans.total_amount);
}
void compute_total_amount(register Transaction *trans)
{
trans->total_amount=trans->quantity*trans->unit_price;
}
compute_total_amount(¤t_trans);//调用compute_total_amount(register Transaction *trans);