目录

  • 小表弟发来的求助信号
  • 要点
  • 代码文件
    • 头文件Student.h
    • 源文件Student.cpp
    • main.c
    • 执行结果
  • c++数组特性以及数组做形参的特点
    • 数组试验
    • 数组特殊性质
      • 不允许拷贝和赋值
      • 数组是通常被转化成指针使用
    • 数组形参
  • 多种写法
    • 代理模式
    • MVC模式

小表弟发来的求助信号


并补充说要5种写法才算过关。

要点

先不说要几种写法,来说说这个实践的目的,也就是我们常常说的需求。
从题目本身说明是 面向对象程序设计 的考察;源文件和头文件分开,进一步说明是C++ 面向对象程序设计,同时也是C++程序设计的标准工程管理方式(头文件、源文件各自在一个文件中),只是在学习的时候往往一个文件将所有的代码放一个文件中。
类定义,实际上已经指明了类的属性以及需要具备的函数:
成绩要求用数组,是对数组的考察:

  1. 数组的初始、赋值、传递,别小看,容易掉坑里。
  2. 用自己的真实学号,就要求结合实际,可选用string或long类型
  3. 姓名已经明确是string,但对要求用中文其实是命题上的错误,不知道外国留学生是否都有一个中文姓名,唯一的提醒就是中文字符的编码问题,但仅仅在这个作业中还体现不了字符编码。
  4. const 自然是程序中要有用到const的地方
  5. 要求有构造函数,是对构造函数的考察
  6. 求平均数主要在于返回值和平均数的计算
  7. 打印学习成绩,和6一样,可以封装,分装的基础上再代理,后者以mvc的模式定义实体来实现,当然,这对于学生来说,可能稍显超标。

代码文件

不啰嗦了,先上个代码,不然看不到希望。

头文件Student.h

内容如下:

#ifndef STUDENT_H_
#define STUDENT_H_
#include <iostream>
using namespace std;
class Student{private:string name;string no;float scores[3]={0,0,0};
public:Student(const string name,const string no,const float scores[3]);~Student();float Average();void SetName(const string name);void SetNo(const string no);void SetScore(const float scores[3]);void Print();
};
#endif

源文件Student.cpp

内容如下:

#include <iostream>
#include "Student.h" //不行的话,这里换成<Student.h>
using namespace std;Student::Student(const string name,const string no,const float scores[3])
{this->name = name;this->no = no;SetScore(scores);
};Student::~Student(){};
float Student::Average()
{float total = 0;if(this->scores){for(int i = 0;i < 3;i++){total += scores[i];}}return total/3;
};void Student::SetName(const string name)
{this->name = name;
};void Student::SetNo(const string no)
{this->no = no;
};void Student::SetScore(const float scores[3])
{for(int i = 0; i < 3 ; i++){this->scores[i] = *scores;scores++;}
};void Student::Print()
{cout<<"姓名:"<<name<<endl;cout<<"学号:"<<no<<endl;cout<<"成绩"<<endl;cout<<"语文:"<<scores[0]<<endl;cout<<"数学:"<<scores[1]<<endl;cout<<"英语:"<<scores[2]<<endl;cout<<"平均成绩:"<<Average()<<endl;
};

main.c

程序入口,根据需要调用

#include <iostream>
#include "Student.h" //不行的话,这里换成<Student.h>
using namespace std;
int main()
{float scores[] = {78,88,98};Student stu("john","8989898989",scores);stu.Print();return 0;
}

代码在线测试

执行结果

$g++ -o main *.cpp
$main
姓名:john
学号:8989898989
成绩
语文:78
数学:88
英语:98
平均成绩:88

至此代码可以拿走了。

c++数组特性以及数组做形参的特点

这里主要说明一下题目要求使用数组,实际上呢是对数组的一个特点、特性、指针做一个真实的巩固。

数组试验

#include<iostream>
using namespace std;int GetSize(int data[]) {return sizeof(data);//特别注意这里
}
int main() {int array[] = {1,2,3,4,5};int arraySize = sizeof(array);int *pointer = array;int pointerSzie = sizeof(pointer );int size = GetSize(array);cout<<"数组大小sizeof "<<arraySize <<" 指针sizeof "<<pointerSzie <<" 形参sizeof "<<size<<endl;return 0;
}

执行结果

$g++ -o main .cpp
main.cpp: In function ‘int GetSize(int
)’:
main.cpp:5:23: warning: ‘sizeof’ on array function parameter ‘data’ will return size of ‘int*’ [-Wsizeof-array-argument]
return sizeof(data);//特别注意这里
^
main.cpp:4:22: note: declared here
int GetSize(int data[]) {
^
$main
数组大小sizeof 20 指针sizeof 8 形参sizeof 8

  • 数组大小sizeof 20 指针sizeof 8 形参sizeof 8: 大小都是指字节(byte),其中一个int 占4个字节,数组一共5个元素,因此sizeof(array) 是20;
  • int型的指针,是一个内存地址,内存地址一般与计算机系统有关,与 指向的类型没有关系(例如 string *str ,str的sizeof也是8),如果是32位系统,内存寻址大小是4个字节(32bit),64位系统,内存寻址大小8个字节(64bit)。上面结果足以表明测试站点后端的执行系统是64位的,sizeof(pointer )是8;
  • 刚好有个warning ‘data’ will return size of ‘int*’ [-Wsizeof-array-argument],说明 形参数组 将会作为对应类型的指针使用,是指针,sizeof自然就是8。

数组特殊性质

不允许拷贝和赋值

不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值。

int a[] = {0,1,2};    // 含有三个整数的数组
int a2[] = a;         // 错误:不允许使用一个数组初始化另一个数组
a2 = a;

简而言之就是数组之间不能用等号来做赋值操作

数组是通常被转化成指针使用

在C++语言中,指针和数组有非常紧密的联系。使用数组的时候编译器一般会把它转换成指针,通常情况下,使用取地址符来获取指向某个对象的指针,取地址符可以用于任何对象。
数组的元素也是对象,对数组使用下标运算符得到该数组指定位置的元素。再对该元素使用取地址符就能得到指向该元素的指针:

string nums[] = {"one", "two", "three"};  // 数组元素是string对象
string *p = &nums[0];
string *p1 = nums;

在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针

数组形参

因为不能拷贝数组,所以我们无法以 值传递 的方式使用数组参数。因为数组会被转换成指针,所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针。
虽然不能以值传递的方式传毒数组,但是可以把形参写成类似数组的形式:


//形式不同,但这三个print结果是等价的
//每个函数都有一个const int*类型的形参
void print(const int*);
void print(const int[]);
//这里的维度表示我们期望数组含有多少元素,实际不一定就是10
void print(const int[10]);

所以,数组作为形参的函数也必须确保使用数组时不会越界。越界了之后自然就是不是我们预期的结果。

多种写法

前面的写法基于最朴实的面向对象和封装的思想。如果一定还要多种写法,那就变化一下。

代理模式

这种只是代理方式,因此只需要修改main文件

#include <iostream>
#include "Student.h" //不行的话,这里换成<Student.h>
using namespace std;float average(Student *stu){return stu->Average();
}void print(Student * stu){stu->Print();
}int main() {float scores[] = {78,88,98};Student stu = Student("john","8989898989",scores);cout<<"平均成绩:"<<average(&stu)<<endl;cout<<"打印:"<<endl;print(&stu);return 0;
}

输出结果:

$g++ -o main *.cpp
$main
平均成绩:88
打印:
姓名:john
学号:8989898989
成绩
语文:78
数学:88
英语:98
平均成绩88

纳里,这有什么不一样吗,反而还多了两个函数。是的就是多了两个函数,在面向过程的思维前提下,这反而是增加了代码量,但这在实际应用当中很有用,有多个Student的子类的话,这就体现出作用了。

MVC模式

这种模式下 Student 只定义属性,并且有Get和Set函数。没有Print 、Averager函数,这些函数是定义在类之外的,此处还是写在main 之前,合理做法应该是另外再定义一个类。

Student头文件

#include<iostream>
using namespace std;
class Student{private:string name;string no;float scores[3]={0,0,0};
public:Student(const string name,const string no,const float scores[3]);~Student();void SetName(const string name);string GetName();void SetNo(const string no);string GetNo();void SetScore(const float scores[3]);float* GetScores() ;//float Average(); 此类不计算了//void Print(); 此类也不做打印
};

Student源文件

#include<iostream>
using namespace std;
Student::Student(const string name,const string no,const float scores[3]){this->name = name;this->no = no;SetScore(scores);
};Student::~Student(){};void Student::SetName(const string name){this->name = name;
};string Student::GetName(){return this->name;
}
void Student::SetNo(const string no){this->no = no;
};string Student::GetNo(){return this->no;
}float * Student::GetScores(){return scores;
}void Student::SetScore(const float scores[3])
{for(int i = 0; i < 3 ; i++){this->scores[i] = *scores;scores++;}
};

main.cpp

#include <iostream>
#include "Student.h" //不行的话,这里换成<Student.h>
using namespace std;float average(Student *stu){return (stu->GetScores()[0]+stu->GetScores()[1]+stu->GetScores()[2])/3;
};void print(Student * stu){cout<<"姓名:"<<stu->GetName()<<endl;cout<<"学号:"<<stu->GetNo()<<endl;cout<<"成绩"<<endl;cout<<"语文:"<<stu->GetScores()[0]<<endl;cout<<"数学:"<<stu->GetScores()[1]<<endl;cout<<"英语:"<<stu->GetScores()[2]<<endl;cout<<"平均成绩"<<average(stu)<<endl;};int main() {float scores[] = {78,88,98};Student stu = Student("john","8989898989",scores);cout<<"平均成绩:"<<average(&stu)<<endl;cout<<"打印:"<<endl;print(&stu);return 0;
}

输出结果:

$g++ -o main *.cpp
$main
平均成绩:88
打印:
姓名:john
学号:8989898989
成绩
语文:78
数学:88
英语:98
平均成绩88

本文只是给出了模型示例,一般真实项目里面不会这么简单。学习课本可能很难理解后面这两种写法,就请先忽略吧。

C++期末实践程序设计与数组作为参数的注意事项相关推荐

  1. Java单元测试实践-09.Mockito的Stub参数条件

    Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. Mocki ...

  2. c语言设计由数组,C语言程序设计_07数组.ppt

    C语言程序设计_07数组 注意:%S用在SCANF()中控制输入时,输入的字符串不能含有空格或制表符.因为C语言规定,用SCANF()输入字符串是以空格或回车符作为字符串间隔符号:当%S遇到空格或制表 ...

  3. 数组做参数_ES6 系列:你不知道的 Rest 参数与 Spread 语法细节

    Rest 参数与 Spread 语法 在 JavaScript 中,很多内建函数都支持传入任意数量的参数. 例如: Math.max(arg1, arg2, ..., argN) -- 返回入参中的最 ...

  4. Java 一维数组作为参数和返回值

    一维数组作为参数: 传数组的引用 创建数组直接传,本质也是传数组的引用 传null public class Test {//数组作为参数时,可以传递3中形式public void m1(int[] ...

  5. 【C 语言】数组作为参数退化为指针问题 ( 问题描述 | 从编译器角度分析该问题 | 出于提高 C 语言执行效率角度考虑 | 数组作为参数的推荐方案 )

    文章目录 一.问题描述 二.从编译器角度分析该问题 三.数组作为参数的推荐方案 一.问题描述 将 数组 作为 函数参数 , 传递时会 退化为指针 ; 数组的首地址 , 变为指针地址 , 函数中无法判定 ...

  6. Julia程序设计3 数组2 排序、复制、集合运算、字典

    Julia程序设计3 数组2 排序.复制.集合运算.字典 排序 排序算法 查找数组中的元素 复制数组 for语句实现数组的变换与生成 集合运算 字典 创建字典 查阅字典 查看索引 修改字典 添加.删除 ...

  7. Julia程序设计3 数组1 创建、初始化、属性与访问

    Julia程序设计3 数组 创建数组 数组的属性 访问数组中的元素 创建数组 1.按列创建数组:如果用中括号创建数组.元素之间用逗号隔开,创建出来的数组就是列向量的形式:用中括号也可以按列创建多维数组 ...

  8. js ajax传对象数组参数,JS传递对象数组为参数给后端,后端获取

    JS传递对象数组为参数给后端,后端获取. 前端JS代码: var conditons = []; var test1 = new Object(); test1.name="1"; ...

  9. ajax post提交数组6,jQuery的ajax()、post()方法提交数组,参数[] 问题

    当用$.ajax()向后台提交参数时,如果参数中数组的话一般在后台会用List,或Integer[] 等数组对象进行接收. 比如: $.ajax({ type: "POST", u ...

最新文章

  1. linux shell 读取文件 笔记
  2. 和lock一起学beego 博客系统开发为例(五)
  3. python加法怎么写_51NOD 大数加法以及python写法
  4. LARS 最小角回归算法简介
  5. c调用python脚本如何获取结果_使用C++调用Python代码的方法详解
  6. 爬虫推特数据分析的外文文献_13天让你学会爬虫分布式,说到让你做到择推出it届附教程...
  7. 单元测试02:Open-Cover安装与使用
  8. 使用AWS Lambda在Go中构建RESTful API
  9. scala字符串替换_如何在Scala中替换字符串中的正则表达式模式?
  10. C++常用特性原理解析
  11. InnerClass内部类
  12. SQL中实现截取字符串的函数
  13. 如何利用tcpdump抓包?
  14. linux下安装redis-cli
  15. 【算法系列学习】Dijkstra单源最短路 [kuangbin带你飞]专题四 最短路练习 A - Til the Cows Come Home...
  16. 周立功上位机获取CAN通讯数据解析 V2.0
  17. 免费SSL证书和付费SSL证书有什么区别?
  18. Axure8.0使用教程
  19. PHP在线手册 中文版
  20. 《SQL进阶教程》学习

热门文章

  1. dede plus ad js.php,织梦程序中plus文件作用介绍及安全设置
  2. c# 赋值运算符_C#程序演示赋值运算符的示例
  3. 史上最全的延迟任务实现方式汇总!附代码(强烈推荐)
  4. linux内核2.6.35编译过程
  5. std::optional
  6. 利用NCO 3.0 调用SAP中的函数
  7. Win10系统java环境配置
  8. 快速锁屏电脑快捷键_一学就会的8个电脑快捷键一定要掌握!堪称“高效”神器...
  9. tp获取referer里的域名_thinkPHP的redirect跳转和referer使用的问题
  10. java接口如何接受语音参数_Java 是如何优雅地实现接口数据校验的?