Created
October 3, 2015 14:43
-
-
Save htfy96/9e9260f2c8562212a88f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cstddef> //size_t类型在cstddef中被定义 | |
#include <cassert> //assert宏在cassert中被定义 | |
#include <cstring> //strlen函数 | |
using namespace std; | |
const size_t SLEN=30; | |
/* 这一行定义了一个值为30,类型是int的名叫SLEN的常量 | |
* 正确的定义方式是 | |
* const int SLEN = 30; | |
* 而不是 | |
* const intSLEN=30; | |
* | |
* 出于区分常量和非常量的考虑,常量一般会用全大写字母来命名。 | |
* 由于下述的原因,类型改为size_t | |
*/ | |
struct Student{ //一般来说类型名首字母大写! student -> Student | |
char fullname[SLEN]; | |
char hobby[SLEN]; | |
int ooplevel; | |
}; | |
/* | |
* 从这里可以看出,SLEN充当的是字符数组定义时的维度的作用。 | |
* 这样做,我是不赞同的,原因有二: | |
* 1) 这样的定长数组,一旦实际存储内容超过SLEN,就会发生溢出,很难处理。如果存储内容远远小于SLEN,则不仅浪费了空间,在拷贝的时候也浪费时间。 | |
* 2) 这样的数组长度应该使用内置的size_t类型,类型与实际意义相符 | |
* | |
* 因此: | |
* 1) 应该使用标准的std::string类型来存储字符串,省时省力。 | |
* 当然在这里本身就是为了训练基本技巧的时候故意使用char数组,但请注意,在实际生产中大多数时候char数组是一个非常拙劣的注意。 | |
* 2) 把SLEN改为size_t | |
*/ | |
int getinto(Student pa[],int n); | |
void display1(Student st); | |
void display2(const Student* ps); | |
void display3(const Student pa[],int n); | |
/*在C++中,传递数组的方式有不少: | |
* 1) (Student arg[]) | |
* 2) (Student* arg) | |
* 3) (Student arg[100]) | |
* 这三者是完全等价的,写在参数表的时候本质上都是接受一个Student*的内容,下标约束(100)并没有任何作用 | |
* | |
* 然而,数组和指针本质上是两种类型,为什么: | |
* Student arr[200]; | |
* Student* ptr_stu = new Student[class_size]; | |
* arr和ptr_stu一个是数组,一个是指针,却都能够调用display2(...)呢? | |
* 原因在于,数组在这个时候会隐式地转换成一个指针,丢失掉它所携带的维度信息,变成一个Student*。 | |
* 这种转换被称作decay,是优先级相当高的一种转换。 | |
* 出于这种转换的原因,我们默认情况下很难知道一个数组的维数,所以一般需要传一个辅助量n人为告知它的维数 | |
* | |
* 这个时候我们要想在编译期获得一个数组的维度,应该采取如下做法: | |
* | |
#include <iostream> | |
#include <cstddef> | |
using namespace std; | |
template<size_t si> | |
void foo(int (*pt)[si]) | |
{ | |
cout << "The size of this array is" << si <<endl; | |
} | |
int main() | |
{ | |
int a[20]; | |
foo(&a); | |
} | |
*/ | |
int main() | |
{ | |
cout<< "Enter class size:"; | |
int class_size; | |
cin>>class_size; | |
while (cin.get() !='\n'); | |
/* continue;*/ // 这个continue是不需要的 | |
assert(class_size>0); | |
//这里class_size不是表明一个size吗?为什么不用size_t类型而是使用int类型? | |
//答:这里我们是希望在输入负数class_size的时候崩溃,而不是尝试开一个很大的数组勉强运作下去(size_t 一般就是unsigned int类型,在输入负数的时候会溢出变成一个大正数,有可能将错就错运行下去;而new int[负数] 会直接崩溃,当然这只是一个很差的弥补方法) | |
//这是软件设计中的一个原则:如果不正确,越早崩溃越好,而不是让它产生新的问题。 | |
//这里可以#include <cassert>库后调用assert(class_size>0)语句,该条语句表示如果class_size 非正则会自动结束程序。这是最好的解决方案 | |
Student* ptr_stu=new Student[class_size]; | |
// 改为Student* ptr_stu | |
// | |
for (int i=0; i<class_size; ++i) | |
{ | |
ptr_stu[i].ooplevel= 0; | |
ptr_stu[i].hobby[0]='\0'; | |
ptr_stu[i].fullname[0]= '\0'; | |
} //因为new出来的东西都是未定义内容的,所以一定要初始化! | |
//接下来应该读取内容了 | |
for (int i=0; i<class_size; ++i) | |
{ | |
cin>>ptr_stu[i].fullname >> ptr_stu[i].hobby>> ptr_stu[i].ooplevel ; | |
cout<<ptr_stu[i].fullname << ptr_stu[i].hobby<< ptr_stu[i].ooplevel ; | |
} | |
int entered=getinto(ptr_stu,class_size); | |
//!这里有大问题,刚刚new出来的ptr_stu 内容是未定义的,你不应该尝试读取里面有什么,正常情况下应该读入到ptr_stu中去 | |
for(int i=0;i<entered;i++) | |
{ | |
display1(ptr_stu[i]); | |
display2(&ptr_stu[i]); | |
//这一段演示了值传参和指针传参两种方式,在C++引用出现之前,C语言只能用这两种方式传参。因而要么忍受display1拷贝大对象的痛苦,要么像display2一样被迫加入一个中间层指针和语法上不自然的&。之后引用的出现解决了这个问题。 | |
} | |
display3(ptr_stu,entered); | |
delete []ptr_stu; | |
/* cout <<"DONE\n";*/ | |
cout<< "DONE" << endl;//\n很不好,因为不是所有系统的换行符都是\n | |
return 0; | |
} | |
int getinto(Student pa[],int n) | |
{ | |
int sum=0; | |
for(int i=0;i<n;i++) | |
{ | |
/* if(pa[i] !={" ";" "; }) */ // ??? 不能读取刚new出来的ptr_stu的内容!而且也不能这么比较大小 | |
if ( strlen(pa[i].fullname) && strlen(pa[i].hobby) && pa[i].ooplevel ) //有姓名,有爱好,而且ooplevel不为0 | |
sum=sum+1; | |
else | |
break; | |
} | |
return sum; | |
} | |
void display1(Student st) //这里应该使用const Student& st比较妥当 | |
{ | |
cout<<"This student's fullname is:"<<st.fullname; //输出时可以直接输出一个char数组 | |
} | |
void display2(const Student*st) | |
{ | |
cout<<"This student's hobby is:"<<(*st).hobby; //同上 | |
} | |
void display3(const Student pa[],int n) | |
{ | |
//for(int i=0;i<n;n++) //不是n++,是i++! | |
for(int i=0; i<n; i++) | |
{ | |
cout<<"This student's ooplevel is:"<<pa[i].ooplevel; | |
} | |
} | |
/* | |
* Testcase: | |
* a aa 1 | |
* b bb 2 | |
* c cc 0 | |
* d dd 0 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment