持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情
1. 结构运算
#include <stdio.h>
struct date {
int month;
int day;
int year;
};
int main (int argc, char const *argv [] ) {
struct date today;
today = (struct date) {
07, 31, 2014
};
struct date day;
day = today;
printf ("Today's date is %i-%i-%i. \n",
today.year, today.month, today.day);
printf ("The day's date is %i-%i-%i. \n",
day.year, day.month, day.day) ;
return 0;
}
分析:
- 输出的两个结果都是一样的
- 添加上:day.year = 2023;结果会变成:
- 所以说day和today是两个完全不同的结构的变量。
- 在做:day = today;过程中,day得到了today里所有成员的值
2. 结构指针
- 和数组不同,结构变量的名字并不是结构变量的地址,必须使用&运算符
- struct date*pDate=&today;
- 可以用这条语句定义一个指向结构体的指针,让它取了结构的地址
- 若去掉了&,编译器会报错,所以结构的名字并不是地址
3. 结构与函数
- 声明了结构就有了自定义的数据类型,可以作为函数的参数
3.1 结构作为函数参数
例如:
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.day = today.day + 1;
tomorrow.month = today.month;
tomorrow.year = today.year;
} else if ( today.month == 12) {
//月尾年尾:日需要加一,月份变成1月,年份需要加一
tomorrow.day = 1;
tomorrow.month = 1;
tomorrow.year = today.year + 1;
} else {
//月尾非年尾:日变成一号,月加一,年份不变
tomorrow.day = 1;
tomorrow.month = today.month + 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))
//闰年,2月份
days = 29;
else
//非闰年的2月份
days = daysPerMonth [d.month - 1];
//这里需要减一是因为d.month=2,只有减一才能取到28
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;
}
分析:
- 这是一个通过输入日期判断明天的日期的程序
- isLeap这个函数是判断是否是闰年
- &today.year取成员优先级高,先取成员,再取地址
- numberOfDays符合单一出口原则
3.2 输入结构
- 结构没有直接的方式可以一次scanf一个结构
- 如果我们打算直接写一个函数来读入结构
#include <stdio.h>
struct point {
int x;
int y;
};
void getStruct (struct point);
void output (struct point);
int main () {
struct point y = {0, 0};
getStruct(y);
output (y);
}
void getStruct (struct point p) {//接收到了y结构变量的数值
scanf ("%d", &p.x);
scanf ("%d", &p.y);
printf ("%d, %d\n", p.x, p.y);
}
void output (struct point p) {
printf ("%d, %d\n", p.x, p.y);
}
分析:
- 这个函数输出两组值,一组是用户输入的数值,一组是初始化时赋的0,0
- p只是有y的值,跟y没有任何联系,所以在函数里对y做任何操作,y都不会有任何改变
- 但是读入的结构如何送回来呢?
- 记住c在函数调用时是传值的
- 所以函数中的p与main中的y是不同的
- 在函数读入了p的数值之后,没有任何东西回到main,所以还是{0,0}
3.3 解决的方案
- 之前的方案,把一个结构传入了函数,然后在函数中操作,但是没有返回回去
- 问题在于传入函数的是外面那个结构的克隆体,而不是指针
- 传入结构和传入数组是不同的在这个输入函数中,完全可以创建一个临时的结构变量,然后把这个结构返回给调用者
#include <stdio.h>
struct point {
int x;
int y;
};
struct point getStruct (void);
void output (struct point);
int main (int argc, char const *argv[]) {
struct point y = {0, 0};
y = getStruct();
output(y);
}
struct point getStruct (void) {
struct point 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);
}
分析:
- 不传入任何值,返回一个结构变量
- 通过结构变量赋值,覆盖掉y原来的值 总结:
- 在传一个结构给函数这种方式当中,不传结构,传结构的指针,这是一种更被推荐的方式
- K&R说过(p.131)
- “If a large structure is to be passed to afunction, it is generally more efficient to pass a pointer than to copy the whole structure”
- c语言结构的传递时值的传递,既费空间,又费时间