前言
作为新手,模仿+理解+运用是学习的三个阶段
本文以理解代码段为学习目标
一、数据类型描述
三元组Triplet的定义:
ADT Triplet{
数据对象:D={e1, e2, e3|e1, e2, e3属于ElemType(定义了关系的某个集合)}
数据关系:R={<e1, e2>|<e2, e3>}
基本操作:
initTriplet(&T, v0, v1, v2)
初始条件:
操作结果:构造三元组T,元素e1, e2和e3分别被赋予参数v1, v2, v3的值。
destroyTriplet(Triplet T)
初始条件:三元组T已经存在。
操作结果:销毁三元组T。
printTriplet(T)
初始条件:三元组T已经存在。
操作结果:显示三元组T。
getElem(T, i, &e)
初始条件:三元组T已经存在, 1 <= i <= 3。
操作结果:用e返回三元组T的第i(1~3)个元素的值。
putElem(&T, I, e)
初始条件:三元组T已经存在, 1 <= i <= 3。
操作结果:用e的值取代三元组T的第i(1~3)个元素的值。
getMax(T, &e)
初始条件:三元组T已经存在。
操作结果:用e返回三元组T的最大值。
getMin(T, &e)
初始条件:三元组T已经存在。
操作结果:用e返回三元组T的最小值。
isAscending(T)
初始条件:三元组T已经存在。
操作结果:如果T的三个元素按升序排序,则返回OK,否则返回ERROR。
isDescending(T)
初始条件:三元组T已经存在。
操作结果:如果T的三个元素按降序排序,则返回OK,否则返回ERROR。
Add(T1, &T2)
初始条件:存在三元组T1, T2。
操作结果:用T2带回操作结果。
mulCoef(&T1, coef)
初始条件:三元组T1已经存在。
操作结果:用T1带回乘系数之后都结果。
}ADT Triplet
二、源代码(扩展名.cpp)
1.引入库
代码如下(示例):
# include<stdio.h> //标准的输入输出函数库
# include<stdlib.h> //使用动态分配内存必须引入的函数库
# define OK 1 //宏定义,下同
# define ERROR 0
# define OVERFLOW -2
typedef int Status; //给int起了个别名(Status),下同
typedef float ElemType;
typedef ElemType *Triplet; //声明Triplet为指向任意类型(此处为ElemType)的指针
//三元组的初始化//
void initTriplet(Triplet &T, ElemType v0, ElemType v1, ElemType v2)
{
//动态分配内存
T = (ElemType *)malloc(3*sizeof(ElemType));
/*
说明:malloc函数后的()给指针分配大小;
malloc函数前的()给指针分配方向。
(类型说明符 *)表示将返回值强制转化为该类型的指针,
而此时需要指向ElemType类型,而Triplet为指向ElemType的指针
所以也可写为T = (Triplet)malloc(3*sizeof(ElemType));
*/
if (!T)
{
printf("分配内存失败!");
exit(OVERFLOW);
}
T[0] = v0;
T[1] = v1;
T[2] = v2;
}
//销毁三元组//
void destroyTriplet(Triplet &T)
{
free(T);
printf("分配内存已释放!");
exit(0);
}
//销毁三元组//
void destroyTriplet_2(Triplet &T)
{
delete []T;
printf("分配内存已释放!");
exit(0);
}
//显示三元组
void printTriplet(Triplet T)
{
printf("调用初始化函数后,T的三个值为:%.1f,%.1f,%.1f\n", T[0], T[1], T[2]);
}
// 用e获取T的第i(1~N)个元素的值//
Status getElem(Triplet T, int i, ElemType &e)
{
if (i < 1 || i > 3)
return ERROR;
else e = T[i-1];
return OK;
}
// 置T的第i元的值为e
Status putElem(Triplet &T, int i, ElemType e)
{
if (i < 1 || i > 3)
return ERROR;
else T[i-1] = e;
return OK;
}
//用e返回值指向T的最大元素的值
ElemType getMax(Triplet T, ElemType &e)
{
if (T[0] > T[1])
e = T[0];
else
e = T[1];
if (T[2] > e)
e = T[2];
printf("三元组T的最大元素的值为:%4.2f\n",e);
return e;
}
//用e返回值指向T的最小元素的值
ElemType getMin(Triplet T, ElemType &e)
{
if (T[0] < T[1])
e = T[0];
else
e = T[1];
if (T[2] < e)
e = T[2];
printf("三元组T的最小元素的值为:%4.2f\n",e);
return e;
}
//如果T的三个元素按升序排序,则返回1,否则返回0//
void isAscending(Triplet T)
{
if (((T[0] <= T[1]) && (T[1] <= T[2] )) != ERROR)
printf("T的三个元素按升序排序\n");
else printf("T的三个元素不是按升序排序");
}
//如果T的三个元素按降序排序,则返回1,否则返回0//
void isDescending(Triplet T)
{
if (((T[0] >= T[1]) && (T[1] >= T[2])) != ERROR)
printf("T的三个元素按降序排序\n");
else printf("T的三个元素不是按降序排序");
}
//两个三元组相加
void add(Triplet T, Triplet &T2)
{
int i;
for (i = 0; i < 3; i++)
T2[i] += T[i];
}
//三元组的各分量同乘比例系数
void mulCoef(Triplet &T, float coef)
{
int i;
for (i = 0; i < 3; i++)
T[i] *= coef;
}
int main()
{
Triplet T, T2;
ElemType v0, v1, v2, e, coef;
int funNum, i;
printf("----三元组操作主菜单----\n");
printf("----1.三元组初始化----\n");
printf("----2.显示三元组----\n");
printf("----3.用e获取T的第i(1~N)个元素的值----\n");
printf("----4.置T的第i个元素的值为e----\n");
printf("----5.是否升序排列----\n");
printf("----6.是否降序排列----\n");
printf("----7.取最大值----\n");
printf("----8.取最小值----\n");
printf("----9.输入另一个三元组相加----\n");
printf("----10.三元组的各分量同乘比例系数----\n");
printf("----11.退出系统----\n");
while (1)
{
printf("请输入你想完成的功能编号:\n");
scanf("%d", &funNum);
switch (funNum)
{
case 1: printf("请输入三元组的每个元素:\n");
scanf("%f %f %f", &v0, &v1, &v2);
initTriplet(T, v0, v1, v2);
break;
case 2: printTriplet(T);
break;
case 3: printf("请输入要获取第几个元素的值:\n");
scanf("%d", &i);
getElem(T, i, e);
printf("第%d个元素的值为:%4.2f\n", i, e);
break;
case 4: printf("请输入要更改的位置和要输入的值:\n");
scanf("%d %f", &i, &e);
putElem(T, i, e);
printf("新的三元组为:\n");
printTriplet(T);
break;
case 5: isAscending(T);
break;
case 6: isDescending(T);
break;
case 7: getMax(T, e);
break;
case 8: getMin(T, e);
break;
case 9: printf("请输入另一个三元组的每个元素\n");
scanf("%f %f %f", &v0, &v1, &v2);
initTriplet(T2, v0, v1, v2);
add(T, T2);
printf("相加之后的三元组的值为:\n");
printTriplet(T2);
break;
case 10: printf("请输入所乘的系数\n");
scanf("%f", &coef);
mulCoef(T, coef);
printf("每项乘系数之后的三元组为:\n");
printTriplet(T);
break;
case 11: destroyTriplet(T);
destroyTriplet(T2);
break;
default: printf("没有你想完成的功能\n");break;
}
}
return 0;
}
2.读入数据
代码如下:
代码段的理解
上文的源代码中,基本每段代码之后都有程序注释,作为新手,程序注释更是我们检验理解能力的"一杆秤“。
除程序注释,以下方面是对整片代码的理解:
1.指针问题
c中指针内容没掌握好的同学,(例如我),刚开始会对上述代码会有疑惑,全文中只有开头typedef ElemType *Triplet;中带有出现指针定义的间接访问运算符”*“,好像与下面代码显得格格不入
而理解代码的话,你会惊奇的发现,下面代码基本全部使用了指针,每一个变量T都是指针型变量,“指针无处不在”。
上面指出typedef ElemType *Triplet;是在声明Triplet为指向任意类型(此处为ElemType)的指针,所以,下面每一个Triplet数据类型的变量,全都是指向ElemType类型的指针变量,
在子函数中,会发现许多T[0]的用法,其实这就是指针的便捷之处,如果我们用结构体的话,必须 使用类似T.e[0]的形式,才能做一系列操作,但如果上面定义指针类型的话,直接使用T[0]即可。
T[0]的用法有些类似数组,对于数组而言,数组名[]可对数组中的元素操作,而对于指针变量同样适用,指针变量名T[]即可对指针指向的内容操作。(注意,不是指针本身的内容(或者说指针指向的方向))。
2.引用问题
上述代码我们使用了c++中的“引用”,(这也就是为什么源代码的扩展名要为.cpp),引用通俗来讲,就是给变量a又取了一个名字为变量b,所以引用并没有给b分配内存空间,而是让b与a共用同一块内存空间,此处与指针不同
在上述代码的参数传递中,我们多次使用了引用"&T",对于什么时候需要使用来说,如果你要改变某个实参的值,就对某个实参使用引用,反之,则不用。
3.针对上文使用的动态内存分配问题
本实验要求动态内存分配,其实对于三元组来说,并没有把动态内存分配的功能发挥的淋漓精致,但也简单的让我们看到了其强大功能的一二。
动态内存分配需要使用指针,指针的强大上文已经略有细说,我们慢慢体会。
动态分配内存要养成及时把需要释放的内存给释放掉的好习惯,对于大量的程序代码段,有助于提升系统的效率,减少所占内存。
写在最后
上文多次写了我对指针的理解,比如说两个特性,方向与大小,
但只是配和理解,真正应该以配合理解去使理解专业化,而不应该停留在配合理解或者被其框架所束缚。
浮游乎万物之祖,物物而不物于物。