(四)结构体、共用体、枚举、字节对齐

来源:互联网 发布:飞鸽传书软件怎么用 编辑:程序博客网 时间:2024/06/16 12:50
一、结构体
1、概念:
结构体是复合的数据类型,是不同类型 数据的集合
在C语言中没有具体的结构体类型,但是C语言给出了定义结构体类型的语法格式,所以结构体也成为自定义类型
2、结构体类型定义的语法格式
struct  <结构体标签>{
成员类型  成员名;
成员类型  成员名;
....    ....
成员类型  成员名;
};
例如:定义一个学生的类型
struct student{
int sno;
char name[20];
int age;
float score;
};
3、结构体变量的定义
1》常规定义:
struct student{
int sno;
char name[20];
int age;
float score;
};
struct student  st1;  //st1为结构体变量
2》与类型同时定义
struct student{
int sno;
char name[20];
int age;
float score;
}st2; /st2为结构体变量
3》直接定义
struct {
int sno;
char name[20];
int age;
float score;
}st3; /st3为结构体变量
4、结构体变量的初始化
1》完全初始化

按顺序给结构体中的每个成员赋值,例如

struct student  st1 = {1001,"张飞",25,98.1}; 
2》部分初始化

按顺序给结构体中的前若干个成员赋值,例如:

struct student  st2 = {1001,"张飞"};  //st2为结构体变量
3》指定成员初始化
不按顺序给结构体中某一些成员赋值,例如:

struct student  st3 = {.name="张飞",25,.sno = 1002};  //st2为结构体变量
5、结构体变量的使用:
1》赋值:
除了初始化之外,不能像 .name="张飞",25,.sno = 1002 这样赋值,例如
struct student st;
st = {100,"abc",22,95.7};    //错误
但是:同类型的结构体变量之间可以相互赋值,例如:
struct student st;
//st = {1001,"张飞",25,98.1};   //错误的
st = st1;   //正确的
另外,也可以分别给每一个成员赋值,例如:
st.sno = 1001;
strcpy(st.name,"赵云");
st.age = 26;
st.score = 95.7;

2》打印:
不能整体打印,必须分别打印每一个成员,例如:
printf("st1:%d,%s,%d,%f\n",st1.sno,st1.name,st1.age,st1.score);
printf("st2:%d,%s,%d,%f\n",st2.sno,st2.name,st2.age,st2.score);
printf("st3:%d,%s,%d,%f\n",st3.sno,st3.name,st3.age,st3.score);
printf("st:%d,%s,%d,%f\n",st.sno,st.name,st.age,st.score);
3》传参:
1)值传递

void fun1(struct student st){printf("st:%d,%s,%d,%f\n",st.sno,st.name,st.age,st.score);st.sno = 1001;strcpy(st.name,"赵云");st.age = 26;st.score = 95.7;}
2)地址传递

void fun2(struct student * pst){printf("in_fun2:%d,%s,%d,%f\n",(*pst).sno,(*pst).name,(*pst).age,(*pst).score);(*pst).sno = 1001;strcpy((*pst).name,"赵云");(*pst).age = 26;(*pst).score = 95.7;}
int main(void){struct student  st1 = {1001,"张飞",25,98.1};  //st2为结构体变量#if 0fun1(st1);   //值传递printf("st1:%d,%s,%d,%f\n",st1.sno,st1.name,st1.age,st1.score);#elsefun2(&st1);  //地址传递printf("st1:%d,%s,%d,%f\n",st1.sno,st1.name,st1.age,st1.score);#endifreturn 0;}
6、结构体数组
元素为结构体类型的数组称为结构体数组,例如:
#include <stdio.h>#include <string.h>//结构体类型定义struct student{int sno;char name[20];int age;float score;};int main(void){struct student st[50] = {{1001,"张三",25,99},{1002,"李四",22,95},{1003,"王五",26,97}};int i;for(i = 0; i < 3; i++)printf("%d,%s,%d,%f\n",st[i].sno,st[i].name,st[i].age,st[i].score);return 0;}
7、结构体指针
指向结构体变量的指针称为结构体指针,例如:

#include <stdio.h>//结构体类型定义struct student{int sno;char name[20];int age;float score;};int main(void){struct student st = {1001,"张三",25,99};struct student *pst;pst = &st;printf("%d,%s,%d,%f\n",st.sno,st.name,st.age,st.score);printf("%d,%s,%d,%f\n",(*pst).sno,(*pst).name,(*pst).age,(*pst).score);printf("%d,%s,%d,%f\n",pst->sno,pst->name,pst->age,pst->score);return 0;}
8、结构体成员类型:
1》基本类型:
struct A{
int a;
float b;
};
2》数组:
struct A{
int a[5];
float b;
};
3》结构体:
#include <stdio.h>struct A{int a;float b;};#if 0struct B{int x;struct A y;   //用已有的结构体类型定义成员变量};#elsestruct B{int x;//定义一个新的结构体类型同时定义该结构体变量struct {int a;float b;}y;};#endifint main(void){struct B st = {100,{123,34.56}};printf("%d,%d,%f\n",st.x,st.y.a,st.y.b);return 0;}
4》指针:

#include <stdio.h>struct A{int a;int *p;};int main(void){int x = 123;struct A st = {100,&x};printf("%d,%d\n",st.a,*st.p);return 0;}
5》结构体指针:
例1:

#include <stdio.h>struct A{int a;float b;};struct B{int x;struct A *pst;};int main(void){struct A sta = {123,3.5};struct B stb = {100,&sta};printf("%d\n",stb.x);printf("%d,%f\n",stb.pst->a,stb.pst->b);return 0;}
例2:

#include <stdio.h>typedef struct B{int x;struct B *pst;}ST;typedef struct node{int data;struct node *next;}list,*plist;int main(void){ST  st1 = {100,NULL};ST  st2 = {200,&st1};ST  st = {300,&st};list nd = {1000};plist pnd = &nd;printf("pnd->data = %d\n",pnd->data);printf("%d\n",st2.x);printf("%d\n",st2.pst->x);printf("%d,%d\n",st.x,st.pst->x);return 0;}
二、共用体
也叫联合体,是一种复合数据类型,C语言中也没有该类型的具体定义,但是给出了定义该类型的语法格式
也是由不同类型数据组成,但是共用体中的多个数据共同使用同一块内存空间。
1、共用体类型的定义
union <共用体标签>{
成员类型  成员名;
成员类型  成员名;
....    ....
成员类型  成员名;
};
例如:定义一个共用体的类型
union student{
int sno;
char name[20];
int age;
float score;
};
2、共用体变量的定义
1》常规定义:
union student{
int sno;
char name[20];
int age;
float score;
};
union student  st1;  //st1为共用体变量
2》与类型同时定义
union student{
int sno;
char name[20];
int age;
float score;
}st2; /st2为共用体变量
3》直接定义
union {
int sno;
char name[20];
int age;
float score;
}st3; /st3为共用体变量


3、使用
1》赋值和打印与结构体类似,例如:

#include <stdio.h>#include <string.h>//共用体类型的定义union A{short a;char b[3];char c[5];};int main(void){union A u1;printf("sizeof(union A) = %d\n",sizeof(union A));printf("sizeof(u1) = %d\n",sizeof(u1));printf("sizeof(u1.a) = %d\n",sizeof(u1.a));printf("sizeof(u1.b) = %d\n",sizeof(u1.b));printf("sizeof(u1.f) = %d\n",sizeof(u1.c));#if 0/*************************************/u1.b = 12.34;strcpy(u1.c,"hello");u1.a = 123;printf("u1.a = %d\n",u1.a);printf("u1.b = %f\n",u1.b);printf("u1.c = %s\n",u1.c);/*************************************/strcpy(u1.c,"hello");u1.a = 123;u1.b = 12.34;printf("u1.a = %d\n",u1.a);printf("u1.b = %f\n",u1.b);printf("u1.c = %s\n",u1.c);/*************************************/#endif#if 0u1.a = 123;u1.b = 12.34;strcpy(u1.c,"hello");printf("u1.a = %d\n",u1.a);printf("u1.b = %f\n",u1.b);printf("u1.c = %s\n",u1.c);#endifreturn 0;}
总结:
1》共用体的成员共同使用同一块内存空间
2》在程序中,某一时刻只有一个成员的值有效,即最后被赋值的成员有效
实例:
判断机器的字节序?

#include <stdio.h>#include <string.h>union A{unsigned int word;unsigned char byte;};int main(void){union A u1;u1.word = 0x12345678;if(u1.byte == 0x12)printf("大端序!\n");elseprintf("小端序!\n");return 0;}
三、枚举类型
该类型的本质是整型,为了提高程序额可读性,同时为了人为的程序中的一些数据规定一个取值的范围,而设计出这样的枚举类型,例如
在程序中表示一周的每一天,或者一年中的每个月都可以定义成枚举类型
1、枚举类型的定义
enum <枚举标签>{
枚举常量,
枚举常量,
.....
枚举常量
};
例如:
enum phone_color{
white, //枚举常量
black, //枚举常量
golden //枚举常量
};
默认情况下,枚举常量的值,从第一个开始依次是:0,1,2,3,....
enum phone_color   color;    //color为枚举变量,一般在程序中取枚举常量的值

#include <stdio.h>#include <string.h>enum phone_color{white,//枚举常量black,//枚举常量golden//枚举常量};enum A{a1 = 100,a2,a3,a4 = 99,a5,a6};struct phone{float value;enum phone_color color;};int main(void){printf("white : %d\n",white);printf("black: %d\n",black);printf("golden : %d\n",golden);printf("a1 = %d\n",a1);printf("a2 = %d\n",a2);printf("a3 = %d\n",a3);printf("a4 = %d\n",a4);printf("a5 = %d\n",a5);printf("a6 = %d\n",a6);struct phone  apple = {5000,white};return 0;}
四、地址对齐
1、自然对齐
在数据分配空间时,如果该数据的起始地址能够被它的长度整除,则就是自然对齐
2、数据的M值
如果该数据的长度小于机器字长,则M值为该数据的长度
如果该数据的长度大于等于机器字长,则M值为机器字长。
3、适当对齐
在数据分配空间时,如果该数据的起始地址能够被它的M值整除,则就是适当对齐
4、不同类型数据的对齐
1》基本类型数据
按M值适当对齐
2》数组:
按元素的M值对齐
4》共用体:
按共用体变量的M值对齐,即:成员中M值最大的
5》结构体:
按结构体变量的M值对齐,即:成员中M值最大的

五、LinuxC语言中的一些特殊函数
1、递归函数
如果一个函数体内部,调用它自己,则该函数称为递归函数,例如:

#include <stdio.h>#if 0void fun(int x,int y){printf("%d\n",x+y);}void test(void){int a = 3,b = 5;fun(a,b);}#elsevoid test(int i){printf("i = %d\n",i++);if(i < 5)test(i);}#endifint fun(int n){if(n == 1)return 1;else if(n > 1)return n*fun(n-1);elsereturn 1;}int main(void){int n;scanf("%d",&n);printf("%d\n",fun(n));return 0;}
2、变参函数
调用时,可以传不同类型的参数或者传不同个数的参数,这样的函数称为变参函数。
 int printf(const char *format, ...);
#include <stdio.h>#include <stdarg.h>void myprint(int n,...){va_list p;int i,t;va_start(p,n);  //对p初始化for(i = 0; i < n; i++){t = va_arg(p,int);printf("%d\t",t);}printf("\n");va_end(p);}int main(void){myprint(5,1,2,3,4,5);myprint(5,111,222,333,444,555);myprint(10,1,2,3,4,5,6,7,8,9,10);return 0;}
3、回调函数
指的是函数调用的一种方式,简单来说:间接调用的函数称为回调函数,例如:


4、内联函数









原创粉丝点击