当前位置:网站首页>C语言程序设计笔记(浙大翁恺版) 第十一周:结构类型
C语言程序设计笔记(浙大翁恺版) 第十一周:结构类型
2022-08-09 14:23:00 【CS_Lee_】
按照中国大学MOOC上浙江大学翁恺老师主讲的版本所作,B站上也有资源。原课程链接如下:
https://www.icourse163.org/course/ZJU-9001
由于是大三抽空回头整理的,所以可能前五章会记的内容比较简略。此外,作为选学内容的A0:ACLLib的基本图形函数和链表两章也没有做。西电的考试是机试,理论上学到结构体就能够应付考试了,但为了以后的学习考虑建议全学。
其他各章节的链接如下:
结构类型
枚举
枚举
常量符号化
用符号而不是具体的数字来表示程序中的数字
枚举
用枚举而不是定义独立的const int 变量
枚举是一种用户定义的数据类型,它用关键字enum以如下语法来声明:enum 枚举类型名字 { 名字0, ..., 名字n };
枚举类型名字通常并不真的使用,要用的是在大括号里的名字,因为它们就是常量符号,它们的类型是int,值依次从0到n。如:enum colors { red, yellow, green };就创建了三个常量,red的值是0,yellow是1,而green是2
当需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量值名字
示例:
#include <stdio.h>
enum color {
red, yellow, green };
void f(enum color c);
int main(void)
{
enum color t = red;
scanf("%d", &t);
f(t);
return 0;
}
void f(enum color c)
{
printf("%d\n", c);
}
枚举量可以作为值
枚举类型可以跟上enum作为类型
但是实际上是以整数来做内部计算和外部输入输出的
套路:自动计数的枚举
示例:
#include <stdio.h>
enum COLOR {
RED, YELLOW, GREEN, NumCOLORS};
int main(int argc, char const *argv[])
{
int color = -1;
char *ColorNames[NumCOLORS] = {
"red", "yellow", "green",
};
char *colorName = NULL;
printf("输入你喜欢的颜色的代码:");
scanf("%d", &color);
if ( color >= 0 && color < NumCOLORS) {
colorName = ColorNames[color];
} else {
colorName = "unknown";
}
printf("你喜欢的颜色是%s\n", colorName);
return 0;
}
这样需要遍历所有的枚举量或者需要建立一个用枚举量做下表的数组的时候就很方便了
枚举量
声明枚举量的时候可以指定值
示例:
#include <stdio.h>
enum COLOR {
RED=1, YELLOW, GREEN=5, NumCOLORS};
int main(int argc, char const *argv[])
{
printf("code for YELLOW is %d\n", YELLOW);
return 0;
}
code for YELLOW is 2
枚举只是int
即使给枚举类型的变量赋不存在的整数值也没有任何warning或error
示例:
#include <stdio.h>
enum COLOR {
RED=1, YELLOW, GREEN=5, NumCOLORS};
int main(int argc, char const *argv[])
{
enum COLOR color = 0;
printf("code for GREEN is %d\n", GREEN);
printf("and color is %d\n", color);
return 0;
}
code for GREEN is 5
and color is 0
虽然枚举类型可以当作类型使用,但是实际上不好用
如果有意义上排比的名字,用枚举比const int方便
枚举比宏(macro)好,因为枚举有int类型
结构
结构类型
声明结构类型
和本地变量一样,在函数内部声明的结构类型只能在函数内部使用。所以通常在函数外部声明结构类型,这样就可以被多个函数所使用了
示例:
#include <stdio.h>
struct date
{
int month;
int day;
int year;
};
int main(int argc, char const *argv[])
{
struct date today;
today.day = 07;
today.month = 31;
today.year=2014 ;
printf("Today's date is %i-%i-%i.\n",
today.year,today.month,today.day);
return 0;
}
Today's date is 2014-31-7.
声明结构的形式
struct point {
int x;
int y;
};
struct point p1,p2;
struct {
int x;
int y;
} p1,p2;
p1和p2并不是类型的名字,而是前面这种无名结构类型的两个变量
struct point {
int x;
int y;
} p1,p2;
声明结构pointer,并且定义这种结构的两个变量p1和p2
对于第一种和第三种形式,都声明了结构point。但是第二种形式没有声明point,至是定义了两个变量
结构变量
struct date today;
today.month=06;
today.day=19;
today.year=2005;

结构的初始化
#include <stdio.h>
struct date
{
int month;
int day;
int year;
};
int main(int argc, char const *argv[])
{
struct date today = {
07,31,2014};
struct date thismonth = {
.month=7, .year=2014};
printf("Today's date is %i-%i-%i.\n",
today.year,today.month,today.day);
printf("This month is %i-%i-%i.\n",
thismonth.year,thismonth.month,thismonth.day);
return 0;
}
Today's date is 2014-7-31.
This month is 2014-7-0.
结构成员
结构和数组有点像,数组用[]运算符和下标访问其成员,结构用.运算符和名字访问其成员(如:today.day,student.firstName,p1.x,p1.y)
结构运算
要访问整个结构,直接用结构变量的名字
对于整个结构,可以做赋值、取地址,也可以传递给函数参数
示例:
p1 = (struct point){
5, 10}; // 相当于p1.x = 5; p1.y = 10;
p1 = p2; // 相当于p1.x = p2.x; p1.y = p2.y;
结构指针
和数组不同,结构变量的名字并不是结构变量的地址,必须使用&运算 如:struct date *pDate = &today;
结构与函数
结构作为函数参数
int numberofDays(struct date d)
整个结构可以作为函数的值传入函数,这时候是在函数内新建一个结构变量,并复制调用者的结构的值
也可以返回一个结构
这与数组完全不同
示例:
#include <stdio.h>
#include <stdbool.h>
struct date {
int month;
int day;
int year;
};
bool isLeap(struct date d);
int numberofDays(struct date d);
int main(int argc, char const *argv[])
{
struct date today, tomorrow;
printf("Enter today's date (mm dd yyyy):");
scanf("%i %i %i", &today.month, &today.day, &today.year);
if( today.day != numberofDays(today) ) {
tomorrow.month = today.month;
tomorrow.day = today.day+1;
tomorrow.year = today.year;
} else if ( today.month == 12 ) {
tomorrow.month = 1;
tomorrow.day = 1;
tomorrow.year = today.year+1;
} else {
tomorrow.month = today.month+1;
tomorrow.day = 1;
tomorrow.year = today.year;
}
printf("Tomorrow's date is %i-%i-%i.\n",
tomorrow.year, tomorrow.month, tomorrow.day);
return 0;
}
int numberofDays(struct date d)
{
int days;
const int daysPerMonth[12] =
{
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if( d.month == 2 && isLeap(d) )
days=29;
else
days=daysPerMonth[d.month-1];
return days;
}
bool isLeap(struct date d)
{
bool leap = false;
if ( (d.year %4 ==0 && d.year %100 !=0) || d.year%400 == 0 )
leap=true;
return leap;
}
输入结构
没有直接的方式可以一次scanf一个结构
示例:
如果我们打算写一个函数来读入结构
#include <stdio.h>
struct point {
int x;
int y;
};
void getStruct(struct point);
void output(struct point);
int main(int argc, char const *argv[])
{
struct point y = {
0, 0};
getStruct(y);
output(y);
}
void getStruct(struct point p)
{
scanf("%d", &p.x);
scanf("%d", &p.y);
printf("%d, %d", p.x, p.y);
}
void output(struct point p)
{
printf("%d, %d", p.x, p.y);
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OzQU7Bn7-1659891264609)(C语言程序设计.assets/image-20220731221957755.png)]](/img/88/0aa6b1b3c1d40c49a06f83be5d56fa.png)
C在函数调用时是传值的,所以函数中的p与main中的y是不同的,在函数读入了p的数值之后,没有任何东西回到了main,所以y还是{0,0}
解决的方案
之前的方案,把一个结构传入了函数,然后在函数中操作,但是没有返回回去。问题在于传入函数的是外面那个结构的克隆体,而不是指针。传入指针和传入数组是不同的
在这个输入函数中,完全可以创建一个临时的结构变量,然后把这个结构返回给调用者
示例:
void main()
{
struct point y = {
0, 0};
y = inputPoint();
output(y);
}
struct point inputPoint()
{
struct point temp;
scanf("%d",&temp.x);
scanf("%d",&temp.y);
return temp;
}
指向结构的指针
用->表示指针所指的结构变量中的成员
示例:
struct date {
int month;
int day;
int year;
} myday;
struct date *p = &myday;
(*p).month = 12;
p->month = 12;
示例2:
void main()
{
struct point y = {
0, 0};
inputPoint(&y);
output(y);
}
struct point* inputPoint(struct point *p)
{
scanf("%d",&(p->x));
scanf("%d",&(p->y));
return p;
}
示例3:
#include <stdio.h>
struct point {
int x;
int y;
};
struct point* getStruct(struct point*);
void output(struct point);
void print(const struct point *p);
int main(int argc, char const *argv[])
{
struct point y = {
0, 0};
getStruct(&y);
output(y);
output(*getStruct(&y));
print(getStruct(&y));
getStruct(&y)->x = 0;
*getStruct(&y) = (struct point){
1,2};
}
struct point* getStruct(struct point *p)
{
scanf("%d", &p->x);
scanf("%d", &p->y);
printf("%d, %d", p->x, p->y);
return p;
}
void output(struct point p)
{
printf("%d, %d", p.x, p.y);
}
void print(const struct point *p)
{
printf("%d, %d", p->x, p->y);
}
结构中的结构
结构数组
struct date dates[100];
struct date dates[] = {
{
4,5,2005},{
2,4,2005};
}
示例:
#include <stdio.h>
struct time {
int hour;
int minutes;
int seconds;
};
struct time timeUpdate(struct time now);
int main(void)
{
struct time testTimes[] = {
{
11,59,59}, {
12,0,0}, {
1,29,59},
{
23,59,59}, {
19,12,27}
};
int i;
for ( i=0; i<5; ++i ) {
printf("Time is %.2i:%.2i:%.2i",
testTimes[i].hour, testTimes[i].minutes,
testTimes[i].seconds);
testTimes[i] = timeUpdate(testTimes[i]);
printf(" ...one second later it's %.2i:%.2i:%.2i\n",
testTimes[i].hour, testTimes[i].minutes,
testTimes[i].seconds);
}
return 0;
}
struct time timeUpdate(struct time now)
{
++now.seconds;
if( now.seconds == 60 ) {
now.seconds = 0;
++now.minutes;
if( now.minutes == 60 ) {
now.minutes = 0;
++now.hour;
if ( now.hour == 24 ) {
now.hour = 0;
}
}
}
return now;
}
结构中的结构
struct dateAndTime {
struct date sdate;
struct time stime;
};
嵌套的结构
示例:
struct point {
int x;
int y;
};
struct rectangle {
struct point pt1;
struct point pt2;
};
struct rectangle r;
r.pt1.x = 2;
r.pt2.y = 3;
struct rectangle r,*rp;
rp = &r;
// 下面的四种形式是等价的
r.pt1.x = 2;
rp->pt1.x = 2;
(r.pt1).x = 2;
(rp->pt1).x = 2;
结构中的结构的数组
示例:
#include <stdio.h>
struct point {
int x;
int y;
};
struct rectangle {
struct point p1;
struct point p2;
};
void printRect(struct rectangle r)
{
printf("<%d, %d> to <%d, %d>\n",
r.p1.x, r.p1.y, r.p2.x, r.p2.y);
}
int main(int argc,char const *argv[])
{
int i;
struct retangle rects[] = {
{
{
1, 2}, {
3, 4}},
{
{
5, 6}, {
7, 8}}
}; // 2 rectangle
for ( i=0; i<2; i++ ) {
printRect(rects[i]);
}
}
联合
类型定义
自定义数据类型(typedef)
C语言提供了一个叫做typedef的功能来声明一个已有的数据类型的新名字。比如:typedef int Length; 使得Length成为int类型的别名。这样,Length这个名字就可以代替int出现在变量定义和参数声明的地方了:Length a,b,len;,Length numbers[10];
typedef
声明了新的类型的名字,新的名字是某种类型的别名,改善了程序的可读性

最后一个单词是新的名字,出现在typedef和新的名字之间的是原来的类型
示例:
typedef struct {
int month;
int day;
int year;
} Date;
表示不关心struct叫什么,将这样的struct命名为Date。如果没有typedef,表示一个没有名字的struct有一个变量叫Date
示例2:
typedef int Length; // Length就等价于int类型
typedef *char[10] Strings; // Strings是10个字符串的数组的类型
// typedef char* Strings[10]; ?
typedef struct node {
int data;
struct node *next;
} aNode;
typedef struct node aNode; //这样用aNode就可以代替struct node
联合
存储时所有的成员共享一个空间,同一时刻只有一个成员是有效的,union大小是其最大的成员
初始化对第一个成员做初始化
示例:
选择成员是一个int i 还是一个char c

示例2:
用Union得到一个数据内部的各个字节
#include <stdio.h>
typedef union {
int i;
char ch[sizeof(int)];
} CHI;
int main(int argc, char const *argv[])
{
CHI chi;
int i;
chi.i = 1234;
for ( i=0; i<sizeof(int); i++ ) {
printf("%02hhX", chi.ch[i]);
}
printf("\n");
return 0;
}
D2040000
%02hhX表示期望输出16进制,并且就是1个字节不做扩展,显示为2个16进制数字,不足补零
我们现在用的x86 CPU采用小端存储,内存中的一个数据低位在前

边栏推荐
猜你喜欢

*4-2 CCF 2014-12-2 zigzag scan

实践数据湖iceberg 第三十八课 spark sql, Procedures语法进行数据治理(小文件合并,清理快照)

一款翻译机背后的全球经济浪潮

同事的接口文档我每次看着就头大,毛病是真的多多多。。。

半自动爬虫

小程序程序开发怎么做?应以突出功能为主

IK学习笔记(1)——CCD IK

spacedesk-notebook, tablet, extended screen-solve the problem that the tablet font is too small

实践数据湖iceberg 第三十九课 清理快照前后数据文件变化分析

拒绝“重复造轮子”,百度EasyDL让你玩转AI定制开发
随机推荐
【Database】Sqlserver如何定时备份数据库和定时清除
uniapp学习
不要小看一个Redis!从头到尾全是精华,阿里Redis速成笔记太香了
Unity Obi插件修改到支持URP
正则表达式实战:最新豆瓣top250爬虫超详细教程
*5-1 CCF 2015-03-1 Image rotation
Assembly language learning (8)
Fiddler弱网测试
[Video coding learning] - SAD and SATD
frog jumping steps
RHCE Course Summary
刷完这174道Android开发面试题,搞懂所有技术栈
Shell course summary
Analysis of select principle in golang
Recursive implementation of the Tower of Hanoi problem
The RHCE course summary
Shell course summary
Introduction to JUC Containers
shell提取ip地址
下班后用微信工作发病是否属于工伤?法院这样判