C语言基础之结构与函数

  • Post author:
  • Post category:其他



结构作为函数参数

int numberOfDays(struct date d)
{
}

◆ 整个结构可以作为参数的值传入函数

◆ 这时候是在函数内新建一个结构变量,并复制调用者的结构的值

◆ 也可以返回一个结构

◆ 这与数组完全不同

【例】给定日期,计算明天的日期:

#include <stdio.h>

struct date                                                    //日期的结构体
{
	int month;
	int day;
	int year;
};

bool isLeap(struct date d);                                    //是否闰年
int numberOfDays(struct date d);                               //本月有多少天

int main(int argc, const char* 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不是本月最后一天
	{
		tomorrow.day = today.day + 1;
		tomorrow.month = today.month;
		tomorrow.year = today.year;
	}
	else if (today.month == 12)                                //today是12月的最后一天
	{
		tomorrow.day = 1;
		tomorrow.month = 1;
		tomorrow.year = today.year + 1;
	}
	else                                                       //today是非12月的最后一天
	{
		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))                             //d日期是2月且闰年
	{
		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() 一个结构

◆ 如果我们打算写一个函数来读入结构:

【错误的代码】

如下的程序,getStruct() 无法获取到main() 中的struct point y本身,只是得到了它的“值”:

#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);
	return 0;
}

void getStruct(struct point p)
{
	scanf("%d", &p.x);
	scanf("%d", &p.y);
	printf("p.x = %d, p.y = %d\n", p.x, p.y);
}

void output(struct point q)
{
	printf("q.x = %d, q.y = %d\n", q.x, q.y);
}

可以看到,执行之后的结果,main() 中的struct point y并没有被修改,这是因为传参而不是将结构体本身传入函数,因此getStruct() 函数并没有去动main() 中的y的内容,导致在output(y) 时,output() 函数仍然得到的是 { 0, 0 }。

◆ 记住C在函数调用时是传值的

★ 所以getStruct() 函数中的p与main() 中的y是不同的,没有任何关系

★ 在函数读入了p的数值之后,没有任何东西回到main(),所以y还是{0 , 0}


解决的方案

◆ 之前的方案,把一个结构传入了函数,然后在函数中操作,但是没有返回回去

★ 问题在于传入函数的是外面那个结构体的克隆体,而不是指针

→ 传入结构和传入数组是不同的

◆ 在这个输入函数中,完全可以创建一个临时的结构变量,然后把这个结构返回给调用者

#include <stdio.h>

struct point
{
	int x;
	int y;
};

struct point inputPoint(void);
void output(struct point);

int main(int argc, char const* argv[])
{
	struct point y = inputPoint();
	output(y);
	return 0;
}

struct point inputPoint(void)
{
	struct point p;
	scanf("%d", &p.x);
	scanf("%d", &p.y);
	return p;
}

void output(struct point q)
{
	printf("q.x = %d, q.y = %d\n", q.x, q.y);
}

◆ 结构指针作为参数

★ K&R说过:“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”


指向结构的指针

struct date
{
    int month;
    int day;
    int year;
} myday;

struct date* p = &myday;

(*p).month = 12;           //两行代码语义是等价的
p->month = 12;             //“->”是一个运算符

◆ 用“->”表示指针所指的结构变量中的成员

#include <stdio.h>

struct point
{
	int x;
	int y;
};

struct point* inputPoint(struct point*);
void output(const struct point*);

int main(int argc, char const* argv[])
{
	struct point y = { 0, 0 };
	output(inputPoint(&y));                   //函数的执行进行串接
	return 0;
}

struct point* inputPoint(struct point* p)     //一个小套路,传入的指针p在写回函数的返回值
{
	scanf("%d", &(p->x));
	scanf("%d", &(p->y));
    return p;
}

void output(const struct point* q)           //参数写为const struct*类型以保证不修改q指向的内容 
{
	printf("q->x = %d, q->y = %d\n", q->x, q->y);
}



版权声明:本文为lilejin322原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。