全国计算机等级考试二级教程-C语言程序设计_第14章_结构体、共用体和用户定义类型
函数的返回值是结构体类型
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> struct info
{
char name[];
int num;
}; struct info getstruct(char *p, int num)
{
struct info info1;//创建结构体
printf("%x\n", &info1);
info1.num = num;//进行赋值
strcpy(info1.name, p);//复制字符串
printf("%d,%s\n", info1.num, info1.name);
return info1;//返回结构体,return有副本机制,保存了info1到另外一段内存
} main()
{
struct info MM = getstruct("hello", ); printf("%d,%s\n", MM.num, MM.name); system("pause");
};
什么时候传值,什么时候传址呢?
内容很少,可以传值。内容很多,最好传地址,节约时间与空间,因为复制浪费时间和空间。
改变一个变量,需要传入地址,改变一个结构体,需要传入结构体的地址
向函数传递整个结构体变量中的数据,传值
传递结构体变量的地址,传址
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> struct info
{
char name[];
long long phone;
}; //函数的副本机制,函数的参数新建了一个变量接收值
//形参改变,不影响实参
void showinfo(struct info info1)
{
printf("%x\n", &info1); strcpy(info1.name, "gao yuan yuan");
info1.phone = ; printf("%s,%lld\n", info1.name, info1.phone);
} //因为函数的副本机制,所以改变一个外部变量,需要变量的地址
void change(struct info *p)
{
printf("%x\n", &p); strcpy((*p).name, "gao yuan yuan");
(*p).phone = ; printf("%s,%lld\n", (*p).name, (*p).phone);
} main()
{
struct info lady = { "tang wei", }; printf("%x\n", &lady); printf("%s,%lld\n", lady.name, lady.phone); change(&lady); printf("%s,%lld\n", lady.name, lady.phone); system("pause");
}
//函数的参数,会对数组传地址,不会有副本机制
//为了节约内存,数组传递的是指针
//数组作为函数参数,退化成指针
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> struct csdn
{
char user[];
char password[];
char email[];
}; //函数的参数,会对数组传地址,不会有副本机制
//为了节约内存,数组传递的是指针
//数组作为函数参数,退化成指针
//void find(struct csdn cdata[5], char *str)
void find(struct csdn *cdata, char *str)
{
printf("find结构体数组有%d个元素\n", sizeof(cdata));//结构体数组作为参数,有4个字节
printf("find结构体元素有%d个元素\n", sizeof(struct csdn)); int i; for (i = ;i < ;i++)
{
if (strcmp(cdata[i].user, str) == )
{
printf("找到%s,%s,%s\n", cdata[i].user, cdata[i].password, cdata[i].email);
}
}
} main()
{
struct csdn cdata[]=
{
{"microsoft","","microsoft@google.com"},
{ "google","","google@google.com"},
{ "baidu","","baidu@google.com"},
{ "ali","","ali@google.com"},
{ "tencent","","tencent@google.com"}
}; printf("main结构体数组有%d个元素\n", sizeof(cdata));
printf("main结构体元素有%d个元素\n", sizeof(struct csdn)); int i; for (i = ;i < ;i++)
{
printf("%s %s %s\n", cdata[i].user, cdata[i].password, cdata[i].email);
} find(cdata, "google"); system("pause");
}
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> #define DB double *
typedef double * db; main()
{
DB dp1, dp2;//double *dp1, dp2; db dp3, dp4;//double *dp3, *dp4 printf("%d,%d\n", sizeof(dp1), sizeof(dp2)); printf("%d,%d\n", sizeof(dp3), sizeof(dp4)); system("pause");
}
#define DB double//替换 #define 被替换的内容 替换的内容
typedef double db;//别名 typedef 原来的类型名 新的别名
//#define 一般加上;,如果加上;,会把;一起替换
//typedef 需要;
结构体字节对齐机制
结构体变量占据的内存单元的个数应当大于等于其内部所有数据成员占据内存单元数的和。
1、C语言引入了字节对齐机制,一般来说,不同的编译器字节对齐机制有所不同,但还是有以下3条通用准则:
(1)结构体变量的大小能够被其最宽基本类型成员的大小所整除;
(2)结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
(3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
2、说明: 字节对齐第3条准则提及最宽基本类型的概念,所谓基本类型是指像char、short、int、float、double这样的内置数据类型。“数据宽度”就是指其sizeof的大小。诸如结构体、共用体和数组等都不是基本数据类型
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> struct mystruct
{
short sh;
char str[];
};//2+11=14 struct info
{
char ch;
char str[];
};//1+10=11 struct tel
{
int tel;
char name[];
};//4+32=36 struct data
{
char c;
double db;
char str[];
};//8+8+16=32 struct data1
{
short sh;
double db;
char str[];
};//8+8+16=32 struct data2
{
short sh;
int ch;
char str[];
};//4+4+20=28 main()
{
printf("%d\n", sizeof(struct mystruct)); printf("%d\n", sizeof(struct info)); printf("%d\n", sizeof(struct tel)); printf("%d\n", sizeof(struct data)); printf("%d\n", sizeof(struct data1)); printf("%d\n", sizeof(struct data2)); system("pause");
};
输出结果:
14
11
36
32
32
28
请按任意键继续. . .
共用体大小必须至少包含最大的成员数据,同时可以整除最小成员数据
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> union data
{
double db;//
char str[];//
};// union data1
{
int i;//
char str[];//
};// main()
{
printf("%d\n", sizeof(union data)); printf("%d\n", sizeof(union data1)); system("pause");
};
输出结果:
16
12
请按任意键继续. . .
结构体定义
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> struct//第3种方法,无名结构体,限量版发行
{
char email[];
char name[];
char add[];
int num;
int bignum;
char tel[];
char phone[];
double RMB;
}d1, d2, d3;//第3种方法,无名结构体,限量版发行 //#define DD struct dangdang//第2种方法
//
//DD
//{
// char email[50];
// char name[50];
// char add[100];
// int num;
// int bignum;
// char tel[20];
// char phone[20];
// double RMB;
//};
//DD d1, d2, d3;//第2种方法 //struct dangdang//第1种方法
//{
// char email[50];
//char name[50];
//char add[100];
//int num;
//int bignum;
//char tel[20];
//char phone[20];
//double RMB;
//};
//struct dangdang d1, d2, d3;//第1种方法 main()
{ system("pause");
};
//指针访问结构体2种形式
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> struct info
{
int num;
float score;
}; main()
{
struct info info1;
printf("%d,%f\n", info1.num = , info1.score = );
struct info *p1 = &info1; printf("%d,%f\n", (*p1).num, (*p1).score);
printf("%d,%f\n", p1->num, p1->score);//指针访问结构体2种形式 struct info *p2 = (struct info*)malloc(sizeof(struct info));
p2->num = ;
p2->score = 19.8; printf("%d,%f\n", (*p2).num, (*p2).score);
printf("%d,%f\n", p2->num, p2->score); system("pause");
}
结构体变量有副本机制,结构体数组没有,结构体变量内部的数组(如果有数组)也有副本。
为什么需要结构体?
为了表示一些复杂的事物,而普通的基本类型无法满足实际需求。
什么叫结构体?
把一些基本类型数据组合组合在一起形成的一个新的数据类型,这个叫做结构体。
14.2.2结构体类型的变量、数组和指针变量的定义
可以用以下四种方式定义结构体类型的变量、数组和指针变量,推荐用第三种方式。
#include<stdio.h> struct date
{
int year, month, day;
}; /* (1)紧跟在结构体类型说明之后进行定义。不推荐,因为只能够定义一次此类型结构体变量 */
struct student
{
char name[];
char sex;
struct date birthday;
float sc[];
}std, pers[], *pstd; /* (2)在说明一个无名结构体类型的同时,直接进行定义。不推荐,因为只能够定义一次此类型结构体变量 */
struct
{
char name[];
char sex;
struct date birthday;
float sc[];
}std, pers[], *pstd; /* (3)先说明结构体类型,再单独进行变量定义。推荐 */
struct student
{
char name[];
char sex;
struct date birthday;
float sc[];
};
struct student std, pers[], *pstd; /* (4)使用typedef说明一个结构体类型名,再用新类型名来定义变量 */
typedef struct
{
char name[];
char sex;
struct date birthday;
float sc[];
}STREC;
STREC std, pers[], *pstd; main()
{ }
14.2.3给结构体变量、数组赋初值
#include<stdio.h> struct student
{
int age;
float score;
char sex;
}; main()
{
struct student st = { , 66.6, 'F' }; struct student st2;
st2.age = ;
st2.score = ;
st2.sex = 'F'; printf("%d %f %c\n", st.age, st.score, st.sex);
printf("%d %f %c\n", st2.age, st2.score, st2.sex);
}
14.2.4引用结构体变量中的数据
#include<stdio.h> struct student
{
int age;
float score;
char sex;
}; main()
{
struct student st = { , 66.6, 'F' };
struct student * pst = &st; st.age = ; /* (1)通过结构体变量引用 */
pst->age = ; /* (2)通过指针变量引用,更常用 */
(*pst).age = ; /* (3)通过指针变量引用 */
}
结构体变量不能相加,不能相减,也不能相互乘除。
允许相同类型的结构体变量之间进行整体赋值。
#include<stdio.h> struct student
{
char name[];
int num;
}per1, per2 = { "YANGGM", }; main()
{
per1 = per2;
}
写一个程序,输入学生的个数,并根据学生的成绩,进行降序排序。
#include<stdio.h> struct student
{
int age;
char name[];
float score;
}; void getdata(struct student * parr, int len)
{
int i; for (i = ;i < len;++i)
{
printf("请输入第%d个学生的信息:", i + ); printf("age=");
scanf("%d", &parr[i].age); printf("name=");
scanf("%s", parr[i].name); printf("score=");
scanf("%f", &parr[i].score);
}
} void outdata(struct student * parr, int len)
{
int i; for (i = ;i < len;++i)
{
printf("age=%d,name=%s,score=%f\n", parr[i].age, parr[i].name, parr[i].score);
}
} void sort(struct student * parr, int len)
{
int i, j;
struct student t; for (i = ;i < len - ;++i)
{
for (j = ;j < len - - i;++j)
{
if (parr[j].score < parr[j + ].score)
{
t = parr[j];
parr[j] = parr[j + ];
parr[j + ] = t;
}
}
}
} main()
{
int len;
struct student * parr;
struct student t; printf("请输入学生的个数:");
scanf("%d", &len);
parr = (struct student *)malloc(len * sizeof(struct student)); getdata(parr, len); printf("\n输入的信息如下:\n");
outdata(parr, len); sort(parr, len); printf("\n根据学生的成绩排序,使用降序\n");
outdata(parr, len);
}
枚举
什么是枚举?
把一个事物所有可能的取值一一列举出来
枚举型常量,可以将数据限定在一定的范围之内,不会出现越界错误,并且刨除多余的数据
枚举的优缺点:
代码更安全
书写麻烦
#include<stdio.h> enum weekday
{
mon, tue, wed, thu, fri, sat, sun
}; void fun(enum weekday i) /* 本函数目的只是期望接受0-6之间的数字,将形参i定义为枚举 */
{
switch (i)
{
case :printf("mon\n");
break;
case :printf("tue\n");
break;
case :printf("wed\n");
break;
case :printf("thu\n");
break;
case :printf("fri\n");
break;
case :printf("sat\n");
break;
case :printf("sun\n");
break;
}
} main()
{
fun(fri);
}
数组
优点:
存取速度快
缺点:
需要一个连续的很大的内存
插入和删除元素的效率很低
链表
优点:
插入删除元素效率高
不需要一个连续的很大的元素
缺点:
查找某个位置的元素效率低
专业术语:
首节点:
存放第一个有效数据的节点
尾节点:
存放最后一个有效数据的节点
头结点:
头结点的数据类型和首节点的数据类型一模一样
头结点是首节点前面的那个节点
头结点并不存放有效数据
设置头结点的目的是为了方便对链表的操作
头指针:
存放头结点地址的指针变量
例14.2
对比向函数传递结构体数组名和向函数传递结构体变量名的区别。
#include<stdio.h> typedef struct
{
int num;
double mark;
}REC; void sub1(REC x)
{
x.num = ;
x.mark = 81.5;
} void sub2(REC y[])
{
y[].num = ;
y[].mark = 77.5;
} main()
{
REC a = { ,90.0 }, b[] = { ,90.0 };
sub1(a);
printf("A)%d,%5.1lf\n", a.num, a.mark);
sub2(b);
printf("B)%d,%5.1lf\n", b[].num, b[].mark);
}
输出结果:
A)16, 90.0
B)12, 77.5
请按任意键继续. . .
例14.3
通过函数返回结构体类型的值。
#include<stdio.h> typedef struct
{
int a;
char b;
}ST; ST fun(ST x) /* 函数的返回值类型是结构体类型ST */
{
x.a = ;
x.b = 'S';
return x;
} main()
{
ST y;
y.a = ;
y.b = 'A';
printf("y.a=%d,y.b=%c\n", y.a, y.b);
y = fun(y);
printf("y.a=%d,y.b=%c\n", y.a, y.b);
}
输出结果:
y.a=0,y.b=A
y.a=99,y.b=S
请按任意键继续. . .
例14.4
通过函数的返回值返回指向结构体变量的指针。
#include<stdio.h> typedef struct
{
int a;
char b;
}ST; ST * fun(ST x) /* 函数的返回值类型是ST *类型 */
{
ST * px;
x.a = ;
x.b = 'C';
px = &x;
return px;
} main()
{
ST y, *p;
y.a = ;
y.b = 'X';
printf("y.a=%d y.b=%c\n", y.a, y.b);
p = fun(y);
printf("(*p ).a=%d (* p).b=%c\n", (*p).a, (*p).b);
}
输出结果:
y.a=999 y.b=X
(*p ).a=100 (* p).b=C
请按任意键继续. . .
例14.5
读入五位用户的姓名和电话号码,按姓名的字典顺序排列后,输出用户的姓名和电话号码。
下面的程序中说明了一个名为 USER 的结构体类型,该结构体包含了两个字符串变量用以存放姓名和电话号码。getdata 函数读入五位用户的姓名和电话号码,放入形参 sp 所指结构体数组中。getsort 函数把结构体数组元素中的数据按姓名的字典顺序排列。outdata 函数输出最后的结果。
#include<stdio.h>
#include<string.h>
#define N 5 typedef struct
{
char name[];
char num[];
}USER; void getdata(USER * sp);
void getsort(USER * sp);
void outdata(USER * sp); main()
{
USER sp[N];
getdata(sp);
getsort(sp);
outdata(sp);
} void getdata(USER * sp)
{
int i;
printf("Enter name & phone number:\n");
for (i = ;i < N;i++)
{
gets(sp[i].name);
gets(sp[i].num);
}
} void getsort(USER * sp)
{
int i, j, k;
USER temp;
for (i = ;i < N - ;i++) /* 按成员 name 的大小重新排列 sp 数组的元素 */
{
k = i;
for (j = i + ;j < N;j++)
{
if (strcmp(sp[k].name, sp[j].name)>)
{
k = j;
}
temp = sp[k]; /* 结构体整体赋值 */
sp[k] = sp[i];
sp[i] = temp;
}
}
} void outdata(USER * sp)
{
int i;
printf("after sorted:\n");
for (i = ;i < N;i++)
{
printf("%s,%s\n", sp[i].name, sp[i].num);
}
}
例14.6
一个简单的链表:
以下程序中所定义的结构体类型 NODETYPE 共有两个成员:成员 data 是整型;成员 next 是指针类型,其基类型为 NODETYPE 类型。
main 函数中定义的变量 a、b、c 都是结构体变量,它们都含有 data 和 next 两个成员;变量 h 和 p 是指向 NODETYUPE 结构体类型的指针变量,它们与结构体变量 a、b、c 中的成员变量 next 类型相同。
#include<stdio.h> struct node
{
int data;
struct node * next;
}; typedef struct node NODETYPE; main()
{
NODETYPE a, b, c, *h, *p;
a.data = ; /* 给变量中的 data 域赋值 */
b.data = ;
c.data = ;
h = &a; /* 将结点相连 */
a.next = &b;
b.next = &c;
c.next = '\0';
p = h;
while (p) /* 移动 p,使之依次指向 a、b、c,输出它们 data 域中的值 */
{
printf("%d", p->data);
p = p->next; /* p 顺序后移 */
}
printf("\n");
}
全国计算机等级考试二级教程-C语言程序设计_第14章_结构体、共用体和用户定义类型的更多相关文章
- 全国计算机等级考试二级教程-C语言程序设计_第4章_选择结构
switch什么时候用break,什么时候不用break 调用break:一次执行一个分支,输入一个数据,对应一个级别 不调用break:连续执行多个分支 if...else 可以处理任何情况,大于小 ...
- 全国计算机等级考试二级教程-C语言程序设计_第8章_地址和指针
面试: unsigned int *p1 = # int *p2 = # #define _CRT_SECURE_NO_WARNINGS #include<std ...
- 全国计算机等级考试二级教程-C语言程序设计_第15章_位运算
位运算,不适用于实数,仅仅适用于整数.字符. C语言的位运算只能操作整数.字符,实数是指数方式表示的,不适用于位运算. #define _CRT_SECURE_NO_WARNINGS #include ...
- 全国计算机等级考试二级教程-C语言程序设计_第9章_数组
四维数组,可用于航天卫星,三维+时间 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> ...
- 全国计算机等级考试二级教程-C语言程序设计_第10章_字符串
字符型指针数组 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> //参数中,int a ...
- 全国计算机等级考试二级教程-C语言程序设计_第5章_循环结构
for循环结构的嵌套 外层循环每循环一次,内层循环会完整循环一次. 外层循环是竖. 内层循环是横. for, do...while, while的选择: 如果有固定次数,如阶乘! ,判断素数,用 fo ...
- 全国计算机等级考试二级教程-C语言程序设计_第3章_顺序结构
1输入两个整数给变量x和y:然后输出x和y:在交换x和y中的值后,在输出x和y. #include <stdio.h> main() { int x, y, t; printf(" ...
- 全国计算机等级考试二级教程-C语言程序设计_第2章_C程序设计的初步知识
正负号与被除数一致. 3 % (-5) == 3 (-3) % 5 == -3 不用求余运算符,求出余数. int x, y; 答:x - x / y * y; const int i = 10; c ...
- 全国计算机等级考试二级教程-C语言程序设计_第7章_函数
函数执行,从右到左执行 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> main() ...
随机推荐
- SpringMVC之数据绑定(转)
到目前为止,请求已经能交给我们的处理器进行处理了,接下来的事情是要进行收集数据啦,接下来我们看看我们能从请求中收集到哪些数据, 1.@RequestParam绑定单个请求参数值: 2.@PathVar ...
- Oracle EBS-SQL (PO-12):检查期间请购单的下达记录数.sql
SELECT DECODE(PRHA.INTERFACE_SOURCE_CODE,'','手工','MRP','自动') 下达方式, PRHA.CREATION_DATE ...
- 浅谈标签构建——TagBuilder
在很多项目中,可能我们需要写一些通用的控件标签,今天来简单的学习一下吧. 在前文中已经学习了 如何自定义MVC控件标签 ,感兴趣的朋友可以去看看. 今天主要还是讲解一下TagBuilder 我们打开源 ...
- 打包静态库.a文件的方法(ar,ranlib,nm命令介绍)
一 常用脚本 1 打包脚本 脚本如下,下面附上ar 和 ranlib命令参考(命令来自于网络) ALLLIB=*.aFILE=`ls *.a`#原来的库解压重命名 for F in $FILEdo ...
- make的命令行选项
make的命令行选项 -b -m 忽略,提供其它版本make兼容性. -B --always-make 强制重建所有规则的目标,不根据规则的依赖描述决定是否重建目标文件. -C DIR --direc ...
- Tengine笔记2:通过IP、域名、端口实现虚拟主机
一.通过端口创建虚拟主机 案例:通过端口访问两个不同的页面 将/usr/local/tengine-2.1.0/html/index.html内的内容改为 Welcom to port1 然后在/op ...
- #include <boost/regex.hpp>
boost C++的正则表达式库boost.regex可以应用正则表达式于C++.正则表达式大大减轻了搜索特定模式字符串的负担,在很多语言中都是强大的功能. boost.regex库中两个最重要的类是 ...
- xml中,button改变背景颜色方法
在画几个设置界面,用到了button控件,对于button空间的背景色在不同状态下的颜色改变方法,做了一下尝试,发现了两种背景颜色改变的方法,就总结了下. 方法一尝试了好多遍才好,要点在于,在sele ...
- C#泛型详解
我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型,但我们没有办法,只能分别写多个方法处理每个数据类型,因为方法的参数类 ...
- LINUX 网络编程 原始套接字
一 原始套接字 原始套接字(SOCK_RAW)是一种不同于SOCK_STREAM.SOCK_DGRAM的套接字,它实现于系统核心.然而,原始套接字能做什么呢?首先来说,普通的套接字无法处理ICMP.I ...