有3个学生,每个学生的数据包括学号、姓名、性别、C语言的成绩, 用average函数求每个人的平均分,最后打印学生数据及平均成绩。
你这题目的C语言的成绩只有一个啊,咋求平均分呢
刚刚好在写项目,看到了就自己写了一点,我运行起来是没啥毛病的,给你做个参考,希望能帮到你。
参考如下:
#include <stdio.h>
#include <string.h>
#define N 3
struct Student
{
int id; // 学号
char name[50]; // 姓名
char gender; // 性别
float score; // C语言成绩
};
float average(struct Student stus[], int n)
{
int i;
float sum = 0;
for (i = 0; i < n; i++)
{
sum += stus[i].score;
}
return sum / n;
}
int main() {
struct Student s[N] = {{101, "Tom", 'M', 90.4},{102, "Jerry", 'M', 80.2},{103, "Huazie", 'M', 85.3}};
int i;
printf("学生信息\n");
for (i = 0; i < N; i++)
{
printf("学号 %d, 姓名 %s, 性别 %c, C语言成绩 %.2f\n", s[i].id, s[i].name, s[i].gender, s[i].score);
}
printf("平均分 : %.2f\n", average(s, N));
return 0;
}
不知道你这个问题是否已经解决, 如果还没有解决的话: 这里我希望先通过实现求平均值函数的这个过程让大家明白,可变参数列表究竟是怎么一回事。
(注意:我是在VC 6.0编译器32位环境下调试运行的,因为VC 6.0作为早期编译器它的函数封装较为简单,在查看标准函数库函数时不会产生不必要的干扰)
下面是average函数的代码,因为下面大家将要遇到很多以前没有见过的代码,我放出最终代码能让大家能够有一个对全局的概念,这样更容易理解我接下来的解析:
#include <stdio.h>
#include <stdarg.h>
int average(int number, ...)
{
va_list arg;
int i = 0;
int sum = 0;
va_start(arg, number);
for (i = 0; i < number; i++)
{
sum += va_arg(arg, int);
}
va_end(arg);
return sum / number;
}
int main()
{
int ave = average(3, 2, 3, 7);
printf("%d\n", ave);
return 0;
}
想必大家看过这段代码后都一脸懵逼吧,average函数里面出现的va_list,_crt_va_start,_crt_va_arg,_crt_va_end都是些什么????
(我觉得这些问号都无法解释你们满头的疑问)
不过不要紧,接下来我会给大家逐步讲解这段代码,以及大家不认识的代码的作用。
首先我们看函数定义部分:
int average(int number, ...)
上面的函数返回值类型(int),函数名(average),函数第一个参数(int number)相信大家都理解且写函数时经常写到。但是函数第二个参数位置确实一串 … ,这个可不读“省略号”!
它其实是表示除了函数的第一个参数,后面的参数的个数和类型是未知。有了它,我们就可以编写接下来函数的实现内容了。
va_list arg;
我知道,下面函数中的这句代码大家还是看不懂(笑)。不要紧,我们可以在编译器中双击va_list然后右击它,选择转到定义(Go to definition)选项,我们可以看到这么一句话:
大家见到上图红框中的代码一定不陌生吧?
没错,这是在重定义char* 这个类型,将他重定义成va_list,所以这里:
va_list arg; //相当于 char* arg;
有了这个思路,那么我相信大家对下面不认识的代码也就不那么畏惧了,只要查看对应代码的定义就可以很好的理解他们的作用。
再看下面的代码,我们要求几个数的平均值,要想简便的写出代码,循环是不可少的一步,所以,这里定义了一个循环体条件变量 i ,以及中间变量 sum (用于求几个变量的和)。
int i = 0;
int sum = 0;
紧接着下一句代码我们可能又不认识,没关系,继续转到定义:
va_start(arg, number);
哎?看到这段代码,大家有没有发现,原来这个va_start居然是一个宏,为了便于理解这段代码的意思,我们首先将这段代码替换到我们的代码中去,这样便于我们理解:
这里的 _INTSIZEOF我们还是不认识,我们接着转到它的定义:
哦?它也是个宏,这里的这个宏我们就不进行替换了,否则替换后不会便于我们理解这段代码。
在这里,我为了让大家不那么痛苦的理解这个宏的作用,我不妨告诉大家,这个宏的作用是将传入的数字转化为4的整数倍输出,也就是说如果传入的是 1,2,3,4 它会输出 4 ,如果传入的是 5,6,7,8 它会输出 8 。是不是很有意思,大家肯定很想知道为什么需要这个宏呢?
我们接着退出 _INTSIZEOF宏的定义,看替换后的代码,在main函数调用这个函数时,我们给average这个函数传递的第一个参数是 3 ,而这个number将 3 传入_INTSIZEOF宏,则_INTSIZEOF宏返回 4 ,而前面的 ( char * )&number将整形变量number的地址转化为char *指针,然后 + _INTSIZEOF宏返回值 4 。这个是什么意思呢?
我们看下面的示意图,相信看过我栈帧的创建与销毁这篇文章的小伙伴应该会有(卧槽)的感叹吧?
这个va_start宏的作用现在是不是有一点眉目了?哦~ 它的作用是将arg指针指向未知参数中的第一个参数去。这样我们就有了遍历其余未知参数的条件了!
那么有了未知参数,让我们开始循环将他们相加,然后除以参数个数输出吧:
循环体里我们又遇到了一个类似的代码va_arg,我们转到它的定义:
可见va_arg也是一个宏,那么我们将它替换到原来的代码中:
这段代码替换后可能有些难以理解,我们进行逐步分析,首先看红框中的代码,我们已经知道_INTSIZEOF宏的作用,将int类型传给他后,因为int类型定义的变量大小为 4 个字节,那么他将返回 4 个字节。我们再将_INTSIZEOF宏替换为 4 。这样是不是就容易看懂一点了?
(将arg这个指针所指向的内容加 4 ,然后将[arg - 4]的值转化成 int * 类型再用解引用操作符解引用,得到这片空间的值)如果大家对这段话很不能理解的话,可以看我下面的示意图,希望对你们的理解有帮助:
这段代码很优雅,它在使arg这个指针指向下一个未知参数的同时读取了原来位置上的参数。希望经过我的示意图以及这两段加粗的文字,大家能理解这段代码的意思。
这个循环体使得va_arg这个宏每取到一个值,就加到中间变量sum中去。
循环结束后,下面是我们最后看到的不熟悉的代码:
va_end(arg);
做法照旧,我们依然转到它的定义:
这里的va_end依然是一个宏,((va_list)0)相信大家知道这是在将整形 0 转化为字符型指针,然后赋值给arg。也就是使指针arg指向0x00000000地址处,这条语句相当于:
OK,讲到这里,我相信大家都能稍微理解可变参数列表了吧?
试着运行一下这段代码吧,看看效果:
注意:如果大家在其他版本的编译器上查看va_list等代码的定义时,转到定义时改选项是灰色的。这里有两种可能:
1.在你的编译器版本下va_start更名为_crt_va_start,需要使用这个宏并引出他们的头文件。
2.有可能是编译器的问题,这里你需要关闭解决方案,删除掉这个工程下的sdf文件,然后再打开这个文件。
3.如果这两种方法都无法解决你的问题的话,请重装电脑(笑),开个小玩笑,如果上面两种方法无法解决的话,你就上网请求帮助吧~
问题标题: 打印学生数据和平均成绩,使用结构语句和average函数
问题内容: 你好,我可以为你提供以下解决方案,帮助你使用结构语句和average函数打印学生数据和平均成绩。
struct student {
int num;
char name[20];
char sex;
float score;
};
struct student stu[3];
for (int i = 0; i < 3; i++) {
printf("请输入第%d个学生的学号,姓名,性别和C语言成绩:\n", i+1);
scanf("%d%s %c%f", &stu[i].num, &stu[i].name, &stu[i].sex, &stu[i].score);
}
float sum = 0, average;
for (int i = 0; i < 3; i++) {
sum += stu[i].score;
printf("学号:%d,姓名:%s,性别:%c,C语言成绩:%.2f,平均成绩:%.2f\n", stu[i].num, stu[i].name, stu[i].sex, stu[i].score, stu[i].score/1.0);
}
average = sum/3.0;
printf("班级平均成绩为:%.2f", average);
代码如下:
#include <stdio.h>
struct student {
int num;
char name[20];
char sex;
float score;
};
int main() {
struct student stu[3];
for (int i = 0; i < 3; i++) {
printf("请输入第%d个学生的学号,姓名,性别和C语言成绩:\n", i+1);
scanf("%d%s %c%f", &stu[i].num, &stu[i].name, &stu[i].sex, &stu[i].score);
}
float sum = 0, average;
for (int i = 0; i < 3; i++) {
sum += stu[i].score;
printf("学号:%d,姓名:%s,性别:%c,C语言成绩:%.2f,平均成绩:%.2f\n", stu[i].num, stu[i].name, stu[i].sex, stu[i].score, stu[i].score/1.0);
}
average = sum/3.0;
printf("班级平均成绩为:%.2f", average);
return 0;
}