结构作为函数参数:

  声明了一个结构就有了一种自定义的数据类型,这个数据类型和int、float、double一样,int等基本类型可以作为函数的参数,那么这种个自定义的结构类型也应该可以作为函数参数,比如:

int numberofDays(struct date d);函数numberofDays的参数就是一种结构变量。

  整个结构是可以作为参数的值传入函数的,这时是在函数内新建一个结构变量,并复制调用者的结构的值,这和数组是完全不一样的。结构除了可以作为参数,也可以作为返回值,例如下述程序中,直接将结构变量d传给另外两个函数:

 #include <stdio.h>
#include <stdbool.h> struct date{
int month;
int day;
int year;
}; bool isLeap(struct date d); //判断是否闰年 ,若是返回true,否则返回false
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)){ //如果today不是这个月的最后一天,那么明天就是今天加1,年和月不变
tomorrow.day=today.day +;
tomorrow.month=today.month;
tomorrow.year=today.year;
}else if(today.month == ){ //如果today是这个月的最后一天,且月份是12月份,那么第二天就是新的一年,月日都是1,年加1
tomorrow.day=;
tomorrow.month=;
tomorrow.year=today.year+;
}else{ //如果today不是这个月的最后一天,且月也不是12月,那么明天就是下个月,月加1,day是1,year不变。
tomorrow.day=;
tomorrow.month=tomorrow.month+;
tomorrow.year=today.year;
} printf("Tomorrow's date is %i-%i-%i.\n'",tomorrow.year,tomorrow.month,tomorrow.day); return ;
} int numberofDays(struct date d){
int days;
const int daysPerMonth[]={,,,,,,,,,,,};//每个月有多少天
if(d.month==&&isLeap(d)) //如果是2月且是闰年,days是29天
days=;
else
days=daysPerMonth[d.month-];//否则直接输出该月的天数,之所以减1是因为数组是从0开始下标的
return days; //单一出口
} bool isLeap(struct date d){
bool leap=false;
if((d.year%== && d.year%!=)||d.year%==)
leap =true;
return leap;
}

输入结构:

  int等基础类型可以%d直接使用scanf和printf进行输入输出,但没有一个直接的方式可以一次scanf一个结构,如果打算写一个函数来读入结构:

 #include <stdio.h>
struct point{
int x;
int y;
};
void getStruct(struct point); //做了一个函数getStruct,参数是一个结构
void output(struct point);
int main(void){
struct point y={,}; //定义一个结构变量y
getStruct(y); //将这个结构变量y给函数getStruct,
output(y);
return ;
} void getStruct(struct point p){ //作为参数接收到结构变量y的值 ,p是和y相同值的结构变量
scanf("%d",&p.x);
scanf("%d",&p.y); //在函数内给p的x和y做了赋值
printf("%d,%d\n",p.x,p.y); //赋值后输出出来
} void output(struct point p){
printf("%d,%d\n",p.x,p.y);
}

  编译和运行上述代码,并输入数据4 和5.结果如下:

4 5
4,5
0,0 --------------------------------
Process exited after 2.377 seconds with return value 0
请按任意键继续. . .

  在getStruct函数中输入4和5之后,该函数内部输出4和5,但是回到main中,y的值依然是0和0.在getStruct中的变量p只是得到y的值,p和y并没有联系。这一点和数组不一样,C语言里在函数调用时是传值的,所以在getStruct函数中的p与main中的y是不同的,在函数getStruct读入了p的数值之后,没有任何东西回到main,所以y还是{0,0}.

解决方案一 将结构变量作为函数返回值:

  所以,把一个结构传入了函数,然后在函数中操作,但是没有返回回去,问题在于传入函数的是外面那个结构的克隆体,而不是指针,传入结构和传入数组是不同的,那么怎么解决这个问题呢?一种方案是在这个输入函数中,完全可以创建一个临时的结构变量,然后把这个结构返回给调用者,也就似乎可以把上述程序改成这个样子:

 #include <stdio.h>
struct point{
int x;
int y;
}; struct point getStruct(void); //做了一个函数getStruct,没有参数,返回一个结构变量
void output(struct point);
int main(void){
struct point y={,};
y=getStruct(); //调用函数getStruct时,使用y接收该函数的返回值
output(y);
return ;
} struct point getStruct(void){
struct point p; //做一个本地结构变量p,这个变量在离开这个函数时会消失掉
scanf("%d",&p.x);
scanf("%d",&p.y);
printf("%d,%d\n",p.x,p.y);
return p;
} void output(struct point p){
printf("%d,%d\n",p.x,p.y);
}

  在输入函数getStruct返回一个结构变量,而没有传入参数,在函数内新建一个本地结构变量p,给p赋值,然后将p返回给main,结果如下,这时y的值就发生了变化:

4 5
4,5
0,0 --------------------------------
Process exited after 2.377 seconds with return value 0
请按任意键继续. . .

解决方案二 结构指针作为函数参数:

  在将一个结构传递给函数时,一般不传结构,而是传递结构的指针,这也是比较推荐的方式。在C语言的经典教材K & R说过(p.131):

If a large structure is to be passed to a function, it is generally more efficient to pass a pointer than to copy the whole structure.

  因为在C语言中结构的传递方式是值的传递,也就是说需要在被调用的函数里建立一个和调用函数里一模一样的一个结构变量,然后把每一个变量成员的值都拷贝过去,这是一个即费空间(需要建立一个空间存放新的结构变量)又费时间(需要花费时间拷贝)的事情。所以早在K&R的书中就说过,更好的方式是传指针。

  因为结构变量名字不是地址,所以需要使用&符号取得地址赋值给一个结构指针,那么使用结构指针怎么获取变量的成员?有两种方式,一般使用->箭头指向的方式:

struct date{
int month;
int day;
int year;
} myday; struct date *p = &myday; (*p).month =12; //*p就表示myday,但是这种书写起来麻烦
p->month =12; //一般使用这种,一般说成p所指的month成员

  所有有了这种方式,getStruct就可以改造成下面的样子:

 #include <stdio.h>
struct point{
int x;
int y;
};
struct point* getStruct(struct point*); //做了一个函数getStruct,参数是一个结构
void output(struct point);
void print(const struct point *p);
int main(int argc, char const *argv[]){
struct point y={,}; //定义一个结构变量y
getStruct(&y); //将这个结构变量y给函数getStruct,
output(y);
output(*getStruct(&y)); //对getStruct函数的返回值进行*运算符,取出函数返回值的结构地址里的值。
print(getStruct(&y)); //将getStruct函数的返回值返回给print,打印出来 getStruct(&y)->x =; //甚至可以对返回值赋值
*getStruct(&y)=(struct point){,};
return ;
} struct point * getStruct(struct point *p){ //作为参数接收到结构变量y的值 ,p是和y相同值的结构变量
scanf("%d",&p->x);
scanf("%d",&p->y); //在函数内给p的x和y做了赋值
printf("%d,%d\n",p->x,p->y); //赋值后输出出来
return (struct point *)p; //常用套路, 传进函数一个指针,对该指针做了一定处理后,再传出去 。好处是可将该返回值潜在其他函数里。
} void output(struct point p){
printf("%d,%d\n",p.x,p.x);
}
void print(const struct point *p){ //传递一个point指针,只是输出所以const,不修改point
printf("%d,%d",p->x,p->y);
}

听翁恺老师mooc笔记(11)--结构和函数的更多相关文章

  1. 听翁恺老师mooc笔记(12)--结构中的结构

    结构数组: 和C语言中的int,double一样,一旦我们做出一个结构类型,就可以定义这个结构类型的变量,也可以定义这个结构类型的数组.比如下面这个例子: struct date dates[100] ...

  2. 听翁恺老师mooc笔记(10)--结构

    定义结构: 在程序里,如果想要表达一个数据就需要一个变量,而每个变量又都需要一个类型,之前学过C语言中有int.double.float.char等这些基础类型,还有指针.数组等.如果你要表达的数据比 ...

  3. 听翁恺老师mooc笔记(16)--程序设计与C语言

    问题1:计算机遍布生活的各个方面,若你需要一个功能可以下载APP,我们需要的大部分功能都可以找到对应的APP,如果没有可以自己写一个软件,但是很少人需要这么做,那么我们为什么学习计算机编程语言? 学习 ...

  4. 听翁恺老师mooc笔记(15)--文件的输入与输出

    <>重定向 如果使用标准的printf输出,有一个比较简便的方法,可以将程序的结果写入一个文件.使用<和>符号,将程序运行结果重定向到文件中去,具体使用到的代码如下: ./te ...

  5. 听翁恺老师mooc笔记(13)--类型定义和联合

    typedef 虽然我们知道使用struct这个关键字定义一个结构类型,然后可以使用该结构类型定义变量.但是每次要使用的时候都需要带着struct这个关键字,那么如何摆脱这个关键字哪?C语言提供了一个 ...

  6. 听翁恺老师mooc笔记(8)--字符串2

    字符串的赋值 字符串的输入与输出 对C语言的基础类型,比如int.double等类型,scanf.printf有专门的格式转换,而对字符串,scanf.printf使用%s格式字符进行输入与输出.当使 ...

  7. 听翁恺老师mooc笔记(14)--格式化的输入与输出

    关于C语言如何做文件和底层操作: 文件操作,从根本上说,和C语言无关.这部分的内容,是教你如何使用C语言的标准库所提供的一系列函数来操作文件,最基本的最原始的文件操作.你需要理解,我们在这部分所学习的 ...

  8. 听翁恺老师mooc笔记(9)--枚举

    枚举类型的定义 用符号而不是具体的数字来表示程序中的数字,这么表示的好处是可读性,当别人看你的程序,看到的是单词,很容易理解这些数字背后的含义,那么用什么符号来表示名字哪?需要const int常量的 ...

  9. 听翁恺老师mooc笔记(7)--字符串1

    C语言中字符串的定义 如果定义一个字符数组word,并使用大括号对其初始化,如下图所示: 但是这个不是C语言的字符串,只是字符数组,不是字符串,因为不能使用字符串的方式进行计算.那么C语言的字符串长什 ...

随机推荐

  1. Array.from()

    es6 Array.from() 方法将两类对象转为真正的数组 用法:用于将两类对象转为真正的数组:类似数组的对象和可遍历(iterable)的对象(包含ES6新增的数据结构Set和Map); 说明: ...

  2. 异常-----freemarker.core.InvalidReferenceException问题解决

    案例一 1.1.错误描述 五月 28, 2014 9:56:48 下午 freemarker.log.JDK14LoggerFactory$JDK14Logger error 严重: Template ...

  3. 微信小程序滚动动画,点击事件及评分星星制作!

    前言 小程序上线刷爆了朋友圈,但是最近渐渐消沉了,很少有动静!最近公司项目需要,体验了一下微信小程序,制作了几个功能,布局感觉很简单,但是交互和动画等写起来确实很费劲,主要是因为他不能操作DOM,只能 ...

  4. 【Luogu1273】有线电视网(动态规划)

    [Luogu1273]有线电视网(动态规划) 题面 题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端, ...

  5. 【CJOJ1090】【洛谷1967】【NOIP2013】货车运输

    题面 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆 ...

  6. XCTF(77777-2)

    题目链接:http://47.52.137.90:20000 这道题目和前面的那道题目大致一样,只不过是过滤的函数不一样 检查过滤函数的方式就不写了,直接来解题 检查函数发现过滤了ord ascii ...

  7. IT连创业系列:新的一年,先淫文一篇!

    办公室窗外,有鸟声〜〜 在IT连创业走过的日子里,这是我第一次听见鸟声. 也许,是曾经的忙碌,封锁了自己的心眼. 岁月秒秒: 当初燃烧的火焰,从红,烧成了蓝. 曾经的内心湃澎,化成了平淡坚持. 但这, ...

  8. Java求最大公约数和最小公倍数

    最大公约数(Greatest Common Divisor(GCD)) 基本概念 最大公因数,也称最大公约数.最大公因子,指两个或多个整数共有约数中最大的一个.a,b的最大公约数记为(a,b),同样的 ...

  9. A Proof of Stake Design Philosophy - PoS权益证明设计理念

    之前在EthFans上看到了关于PoS(权益证明)的相关文章(原文链接),本着学习的态度,对这篇文章进行了翻译.第一次翻译关于区块链的文章,有些单词及句子的措辞还不是很准确,如果发现有翻译的不恰当的地 ...

  10. Linux/Unix 资源

    Linux/Unix笔记本 初窥Linux 之 我最常用的20条命令 Linux Shell脚本教程