计算机图形学上机报告(一)

1.回顾总结C++的基础操作以及Visual Studio2022的使用方法;

2.回顾C++有关函数方面的知识,实现在一个函数中调用另一个函数;

3.回顾C++中基本运算符的用法,实现两个数的加减乘除;

4.学习C++ math.h库中的各种常见数学函数,并实现数学函数的调用;

5.学习C++ algorithm库中定义的sort函数的用法,并利用其对数组中的元素进行排序;

6.回顾C++循环语句的知识,并编写函数求x的n次方;

7.回顾C++中有关运算符、逻辑变量及循环语句、条件语句的知识,编写程序实现寻找并输出11~999之间的数m,使它满足m,m^2,m^3均为回文数;

8.学习C++ string库的知识,并进行字符串的定义及初始化,读取字符串;

9.学习C++ algorithm库中定义的fill函数的用法,并利用其为数组指定元素赋值;

10.学习C++ cstdio库中定义的_countof函数的用法,并利用其求数组元素个数;

11.回顾赋值时左值和右值的含义,以及其在内存层面的深层操作;

12.回顾指针变量,指针的内存存储方式以及指针的作用;

13.实现不同类型指针的算术运算,并显示指针指向的位置及表示的值;

14.回顾C++类和对象的知识,学习了类的成员、方法、构造函数和析构函数,建立.h头文件的方法,以及this指针的使用,深入理解了面向对象的程序设计;

15.利用类实现一个顺序表;

16.进一步学习类的继承、派生、多态;指向类的指针;拷贝构造函数;类的静态成员;类模板有关知识。

Visual Studio 2022版

Windows 10/11

1.函数的定义及函数的调用,以及在一个函数中调用另一个函数

通过声明及在函数语句中输入相应代码可以写出一些能够实现不同功能的函数,这些函数在主函数中可以被调用。

而对于自定义的函数,也可以在一个函数中调用另一个函数,来实现相应的功能。

2.实现两个数的加减乘除

输入两个双精度数值,通过最简单的加减乘除运算符实现两个数之间的加减乘除运算,并输出这两个数加减乘除的结果。

需要注意的事项是在进行除法运算时,如果两个数据的类型都是整型,其除法结果也为整型输出,若想得到精确数值,两个参与运算的数据类型都应该设为双精度。

3.数学函数的调用

在主函数中调用C++ math.h库中的各种常见数学函数完成相应运算。

其中,分为取绝对值,向上、向下取整,乘方和开方,求对数(语句为log(a)/log(b),a为真数、b为底数),三角函数和反三角函数的各种运算等等。

注意在进行三角函数运算时,涉及到角度值应该将角度制数字其乘以π ,再除以180,转化为弧度制进行计算。

4.对数组中的元素进行排序

在主函数中调用C++ algorithm库中定义的sort函数实现对于数组的排序。

algorithm意为"算法",是C++的标准模版库(STL)中最重要的头文件之一,提供了大量用于访问元素的函数,所谓访问元素指的就是可以通过迭代器或指针访问容器内部任何对象的序列,容器就是指许多数据的集合,而迭代器就是访问容器中任一数据的工具。所以显而易见,数组就是访问元素的一种,其包含许多数值数据,并且可以通过指针访问任一数据。

sort函数可以对数组中给定区间所有元素进行排序。在进行调用时,它有三个参数,分别为sort(begin,end,cmp),其中begin为指向排序数组的第一个元素的指针,end为指向排序数组的最后一个元素的下一个位置的指针,cmp参数为排序准则。如果不写cmp参数的话,默认从小到大进行排序。如果想要从大到小排序可以将cmp参数写为greater<int>(),这就是对整型数组进行排序,<>中也可以写double、long、float等数据类型,分别对应不同数据类型的待排序数组。如果需要按照其他的排序准则,那么就需要自己定义一个bool类型的函数来传入sort函数。

为了实现数组元素的排序,调用两次sort函数,输入不同的排序准则,分别对同一数组进行从小到大和从大到小的排序。 

5.求x的n次方

求x的n次方本质上就是求n个x累乘的数值,利用循环来实现。

首先设定结果的初始值为1,接着进行n次循环,每次循环在结果上乘以一个x,最终得到x的n次方的数值。

需要注意的是在while语句中的括号中可以直接输入n--,含义是n大于0时进行循环。

6.寻找并输出11~999之间的数m,它满足m,m^2,m^3均为回文数

首先编写函数判断一个数是否为回文数,判断回文数的条件就是一个数按照从最高到最低的数位排列和按照从最低到最高的数位排列的两个数数值相同,可以构建这样两个数并判断其是否相等来判断这两个数是否为回文数,可以将数的本体由最低数位向最高数位取位,接着根据取位的结果由高数位向低数位构建本体的回文数,最后判断两个数是否相等。

在实现回文数判断函数的构建后,对11-999之间的数进行遍历,直接调用相应函数判断m,m^2,m^3是否均为回文数并输出满足条件的数。

7.读取字符串

这个算法需要实现输入姓名和城市两个变量并将其输出。

在C++程序中,输入时可以用cin>>或getline函数实现输入,而当cin读取数据时,一旦它接触到第一个非空格字符即开始阅读,当它读取到下一个空白字符时,它将停止读取,所以一旦输入的字符串中间有空字符,cin只能读取空字符前的部分;而getline函数可以读取整行输入字符串,包括中间的空格,并将其存储在输入流对应的字符串对象中。

string库内部包含一系列对于字符串变量的操作,包括替换、删除、比较、连接等等,这个程序里用于定义字符串。

getline函数的用法为getline(cin,string),其中第一个参数是正在读取的输入流,第二个参数是接收输入字符串的string变量的名称。

在实现功能方面,首先将姓名和城市两个变量进行初始化,接着利用getline函数输入相应字符串变量作为两个初始化字符串变量的值,最后对两个变量进行输出。

8.为数组指定元素赋值

这个算法主要是改变数组指定位置元素的值,首先定义一个数组并利用循环输入数组中的每一个值进行初始化,接着改变数组某一指定范围的数值,接着输出赋值之后的数组。

实现这个功能需要用到C++ algorithm库中定义的fill函数,其用法为fill(begin,end,value),其中第一个参数是赋值的首位置,第二个参数是赋值的尾位置,第三个参数是首位置到尾位置范围内所赋的值,且同一位置所赋的值可以被后来所赋的值覆盖。

9.求数组元素个数

这个算法主要为了求取给定数组中的元素个数,需要先定义一个数组,接着使用C++ cstdio库中定义的_countof函数对数组包含的元素个数进行计算。

_countof(数组名)函数主要功能是求取指定数组包含的元素个数并输出。

10.实现不同类型指针的算术运算,并显示指针指向的位置及表示的值

这个算法主要是显示字符型指针及整型指针的算术运算的结果,指针的自增是指向指针对应数据类型在内存中的下一个存储空间,由于每一个字符型数据占用一个内存地址,每一个整型数据占用四个内存地址,所以字符型指针每次自增移动一个地址,而整型指针每次自增移动四个地址。

进行赋值时,赋值运算符左侧的变量叫做左值,左值是用于标识特定数据对象的名称或表达式,而数据对象指的是用于存储值的数据区域,可以理解为内存地址;而赋值运算符右侧的变量叫做右值,是能赋值给可修改左值的量,右值对应的类型需要与左值一致。赋值运算符实现的操作就是将右值的值赋给左值数据对象所对应的值的区域。

&(取址符)运算符是取一个数据元素所在的地址,可以通过&运算符查看某一个数据元素对应的地址;*(间接运算符)运算符是针对指针的运算符,可以显示一个内存地址对应的值。

在这个程序中,字符数组的内存地址是连续的,需要先建立一个指向数组首地址的字符型指针,再建立一个指向数组首地址整型指针,可以通过赋值的方式实现,并分别对其移动,接着输出其指向位置的值。

11.交换两个整数的值

对于交换两个整数的值,如果使用普通的整型变量作为函数的参数,根据第10条中介绍的赋值原理,虽然在函数内部两个变量的值发生了交换,但是两个参数对应的内存地址并没有发生变化,所以在函数外部两个变量的值不会发生交换,还是与初始的值相同,这样不能达到算法目的。

而如果使用指针类型的变量作为函数的参数,那么在函数中由于指针指向的内存地址会发生变化,所以实际上交换的是两个指针指向的位置,这样在函数外部两个变量的地址依然是交换的,所以可以达到算法相应的目的。

12.求数组中间位置的数值及地址

首先定义一个指针指向数组的第一个元素,接着定义一个指针指向数组的最后一个元素,通过这两个指针的算术运算求出数组的元素个数,接着判断数组的长度是否为奇数,若为奇数,可以利用数组长度除以2计算中间元素的位置,并利用指向第一个元素的指针加上中间元素的位置求得中间元素的地址。解引用即获取指针地址所对应的值,所以可以使用间接运算符加指针可以得到数组中间位置的元素值,也可以采用数组下标的方法获取。

13.利用类实现一个顺序表

C++最大的特点就是面向对象的程序设计,对象指定就是具体的事物,而类就是相同类型对象的一个抽象集合,而对象就是类的具体表现。一个类的定义包含两部分的内容,一是该类的属性,另一部分是它所拥有的方法,这两个部分都叫做类的成员。类的本质就是进行封装,类的成员具有访问权限,默认为private私有成员,在类的外部是不可访问的,甚至是不可查看的,只有类和友元函数可以访问私有成员;protected保护成员在子类中可以进行访问;public公有成员在类的外部也可以进行访问。

在编程实现时,类的定义包含四个要素:类名,数据成员,函数成员,访问限定符。类的数据成员只能在类的内部定义,定义方法和变量一致,而类的函数成员则在类的内外部都可以定义。在定义成员函数时,可以使用this指针去调用本类中的成员数据。在类外定义函数时需要注意为了表明函数是类的成员,需要添加前缀“类名::”。

而为了避免程序过于冗杂,难以查看,可以将类的定义、成员定义、主函数分别放在不同的程序文件中,类的定义放在.h后缀的头文件中,成员定义放在.cpp后缀的源文件中,主函数定义放在.cpp后缀的源文件中,并在其中引用包含类名的头文件。

为了实现一个顺序表,首先在头文件中定义一个顺序表类,对顺序表中存储空间基址的整型指针变量,线性表当前长度及线性表分配的存储容量进行的整型变量进行定义,并对成员函数:顺序表的初始化、插入、删除、重置、销毁、输出、判断是否为空进行声明,所有成员的访问权限均设置为public即可。在同名cpp文件中实现以上成员函数的定义,这里各个函数的实现算法原理在《数据结构上机报告(三)》中已经进行了具体阐述,此处不再赘述。在Visual Studio 2022版中,可以直接使用类向导构建一个类的头文件和源文件,直接向类和源文件中填充相应的程序语句即可。

最后,在主函数中首先引用各个头文件,包括类对应的头文件,再调用相应类的成员函数,实现相应功能。这里,在主函数中构建的具体物体就可以看做所构建类的对象。

 

  • 上机代码

1.函数的定义及函数的调用,以及在一个函数中调用另一个函数

//头文件

#include<iostream>

using namespace std;

//函数声明

    void deep();

    void deeper();

//函数定义

    void deep()

    {

        cout << "I am now inside the function deep.\n";

        deeper();  // Call function deeper

        cout << "Now I am back in deep. \n";

    }//deep函数定义,可以在函数中调用deeper函数

    void deeper()

    {

        cout << "I am now inside the function deeper.\n";

    }//deeper函数定义

//主函数

int main(){

    cout << "I am starting in function main.\n";

    deep(); // 调用deep函数

    cout << "Now I am back in function main again.\n";

    system("pause");

    return 0; 

}

2.实现两个数的加减乘除

//头文件

#include <iostream> 

using namespace std;

//主函数

void main()

{

    double a, b, sum, dif, mult, div; //定义双精度变量a、b、sum、dif、mult、div

    cout << "请输入参与运算的a与b的值:";

    cin >> a >> b;  // 输入a和b的值

    sum = a + b; // a、b相加

    dif = a - b; //a、b相减

    mult = a * b;//a、b相乘

    div = a / b;//a、b相除

    cout << "sum = " << sum << endl;//输出相加结果

    cout << "dif = " << dif << endl;//输出相减结果

    cout << "mult = " << mult << endl;//输出相乘结果

    cout << "div = " << div << endl;//输出相除结果

    system("pause");

}

3.数学函数的调用

#define CRT_SECURE_NO_WARNINGS  //避免vs中使用strcpy, scanf等一些老的函数时警告和报错的问题

#define PI 3.1415926535//定义全局变量圆周率pi的数值

//头文件,这里包含了C++中的数学符号库

#include <iostream>

#include <math.h>

using namespace std;

//主函数

int main() {

    // abs()在某些C++版本中只能返回整型,而fabs()可以返回浮点型,在2022版本中abs函数也可以返回浮点类型的绝对值

    cout << "abs(-100.01) = " << abs(-100.01) << endl;//绝对值   

    cout << "fabs(-10.11) = " << fabs(-100.11) << endl;//绝对值

    //对数据取整

    cout << "floor(15.99) = " << floor(15.99) << endl;// 向下取整

    cout << "ceil(32.01) = " << ceil(32.01) << endl;// 向上取整

    //乘方和开方

    cout << "pow(2,10) = " << pow(2, 10) << endl;// 乘方

    cout << "sqrt(4) = " << sqrt(4) << endl;// 开平方

    //对数

    cout << "log(100) / log(10) = " << log(100) / log(10) << endl; // 求以自然对数为底的对数

    //三角函数

    cout << "sin(90) = " << sin(90 * PI / 180) << endl;// 正弦,需要将其转化为弧度值   

    cout << "cos(60) = " << cos(60 * PI / 180) << endl;// 余弦,需要将其转化为弧度值

    cout << "tan(45) = " << tan(45 * PI / 180) << endl; // 正切,需要将其转化为弧度值

    cout << "asin(1) = " << asin(1) << endl;// 反正弦   

    cout << "acos(0) = " << acos(0) << endl;// 反余弦

    cout << "atan(1) = " << atan(1) << endl;// 反正切

    system("pause");

    return 0;

}

4.对数组中的元素进行排序

//头文件,其中包含了algorithm头文件

#include<iostream>

#include<algorithm> //algorithm意为"算法",其中定义了许多应用于范围元素(即数组等)的函数,是C++的标准模版库中重要头文件

using namespace std;

//主函数

int main()

{//sort函数第三个参数采用默认从小到大

    int a[] = { 45,12,34,77,90,11,2,4,5,55 };//定义数组a

    int b[] = { 45,12,34,77,90,11,2,4,5,55 };//定义数组b

    sort(a, a + 10);//对数组a进行排序(默认由小到大)

    sort(b, b + 10, greater<int>());//对数组b进行排序(输入由大到小的排序准则)

    for (int i = 0; i < 10; i++)

         cout << a[i] << " ";//输出排序后的数组a

    cout << endl;

    for (int i = 0; i < 10; i++)

         cout << b[i] << " ";//输出排序后的数组b

    cout << endl;

    system("pause");

    return 0;

}

5.求x的n次方

(1)代码1

//头文件

#include<iostream>

using namespace std;

double power(double x, int n)

{

    double val = 1.0;//定义结果初始值为1

    while (n--) //首先判断n的值,当大于零时进入循环,并且每次循环n自减一

         val *= x;//每次循环累乘一个x的值,共循环n次

    return val;//返回最终结果

}//计算x的n次方的power函数

//主函数

int main()

{

    cout << "2 to the power 10 is " << power(2, 10) << endl;//计算2的10次方并输出

    system("pause");

    return 0;

}

(2)代码2

//头文件

#include<iostream>

using namespace std;

double power(double x, int n)

{

    double val = 1.0;//定义结果初始值为1

    while (n>0)//首先判断n的值,当大于零时进入循环

    {val *= x;//每次循环累乘一个x的值,共循环n次

         n--;//每次循环n自减一

    }

    return val;//返回最终结果

}//计算x的n次方的power函数

//主函数

int main()

{

    cout << "2 to the power 10 is " << power(2, 10) << endl;//计算2的10次方并输出

    system("pause");

    return 0;

}

6.寻找并输出11~999之间的数m,它满足m,m^2,m^3均为回文数

#include<iostream>

using namespace std;

bool symm(int n)//判断n是否为回文数

{

    int i = n;//i用于n的取位

    int m = 0;//m是n的回文数

    while (i > 0)//循环用来取n的所有位数

    {

         m = m * 10 + i % 10;//从最小位开始构建n的回文数

         i /= 10;//对n进行从小到大的取位

    }

    return m == n;//如果构建的回文数与原数相等,返回真值

}

//主函数

int main()

{

    for (int m = 11; m <= 999; m++)//遍历11到999之间的数

    {

         if (symm(m) && symm(m * m) && symm(m * m * m))//判断m、m * m、m * m * m均为回文数的情况

         {

             cout << "m=" << m<<" ";

             cout << "m*m=" << m * m<<" ";

             cout << "m*m*m=" << m * m * m << endl;//输出相应的m、m * m、m * m * m的数值

         }

    }

    system("pause");

    return 0;

}

7.读取字符串

//头文件,包含string库,其中有大量用于处理字符串的函数

#include <iostream>

#include <string> // 使用字符串对象所需的头文件

using namespace std;

//主函数

int main() {

    string name;//定义姓名name变量 

    string city;//定义城市city变量

    cout << "Please enter your name: ";//提示语句 

    getline(cin, name);//读取name字符串。getline函数第一个参数是正在读取的输入流,第二个参数是接收输入字符串的 string 变量的名称。

    cout << "Enter the city you live in: ";

    getline(cin, city);//读取city字符串

    cout << "Hello, " << name << endl;//输出name

    cout << "You live in " << city << endl;//输出city

    system("pause");

    return 0;

}

8.为数组指定元素赋值

//头文件,包含algorithm库,其中的fill函数用于为数组指定位置元素赋值

#include <iostream>

#include <algorithm>

using namespace std;

//主函数

int main() {

    int array[8];//定义一个有8个元素的数组

    cout << "=======begin=======" << "\n";

    cout << "请输入数组元素值:" << "\n";

    for (int i = 0; i < 8; i++)

        cin >> array[i];//输入数组的元素值

    for (int i = 0; i < 8; i++)

        cout  << array[i] << ' ';//显示初始定义的数组 

    cout << '\n' << '\n';

    fill(array, array + 4, 5);  //利用fill函数赋值。第一个参数是赋值的首位置,第二个参数是赋值的尾位置,第三个参数是所赋的值

    fill(array + 3, array + 6, 8);//利用fill函数赋值,赋的值可以覆盖。

    cout << "=======after fill=======" << "\n";

    for (int i = 0; i < 8; i++)

        cout << array[i]<< ' ' ;//输出赋值后的数组

    cout << '\n' << '\n';

    system("pause");

    return 0;

}

9.求数组元素个数

//头文件,包含cstdio库,其中有_countof函数

#include <iostream>

#include <cstdio>  //提供与物理设备进行交互的输入输出流操作

using namespace std;

//主函数

int main() {

    int arr[] = { 11,12,13,14,15 };//定义数组arr

    cout << _countof(arr) << endl; //_countof用于输出数组里面元素个数

    system("pause");

    return 0;

}

10.实现不同类型指针的算术运算,并显示指针指向的位置及表示的值

//头文件

#include <iostream> 

using namespace std;

//主函数

int main(void)

{

    char array1[20] = "abcdefghijklmnopqrs";//定义一个包含20个字符字符数组array1,每个字符的地址是连续的

    char* ptr1 = array1;//定义指针ptr1,使其指向数组array1的首地址

    int* ptr2 = (int*)ptr1;//定义指针ptr1,并将ptr1转化为int*类型的指针,指向字母对应整型的地址,并将其作为右值赋给左值ptr1的数据对象对应的值

    ptr1++;//使ptr1指向其下一个地址,char*型每次移动一个存储空间

    ptr2++;//使ptr2指向其下一个地址,int*型每次移动四个存储空间

    cout << &array1 << endl;//输出数组array1的首地址

    cout << *ptr1 << endl;//输出数组ptr1移动后对应的值

    cout << ptr2 << endl;//输出数组ptr2移动后指向的地址

    cout << *(char*)ptr2 << endl;//将ptr2转化为char*类型的指针,并输出其对应的值

    system("pause");

    return 0;

}

11.交换两个整数的值

(1)函数变量为整型

//头文件

#include <iostream> 

using namespace std;

void swap(int x, int y);//swap函数声明

//主函数

int main(void)

{

    int  a, b;

    cout << "Please enter the value of a and b:"<<endl;

    cin >> a >> b;//输入两个整数a,b

    if (a < b)//判断当a<b时进行交换

         swap(a, b);//调用swap函数,对a、b进行交换,注意输入变量需要是指针类型

    cout << "a,b=" << a << "," << b <<endl;//输出交换后a和b的值

    system("pause");

    return 0;

}

void swap(int x, int y)

{

    int t;

    t = x;//使指针x指向t对应的地址

    x = y;//使指针y指向x对应的地址

    y = t;//将t的值赋给y地址对应的数值

}//swap函数定义

(2)函数变量为指针类型

//头文件

#include <iostream> 

using namespace std;

void swap(int* x, int* y);//swap函数声明

//主函数

int main(void)

{

    int  a, b;

    cout << "Please enter the value of a and b:"<<endl;

    cin >> a >> b;//输入两个整数a,b

    if (a < b)//判断当a<b时进行交换

         swap(&a, &b);//调用swap函数,对a、b进行交换,注意输入变量需要是指针类型

    cout << "a,b=" << a << "," << b <<endl;//输出交换后a和b的值

    system("pause");

    return 0;

}

12.求数组中间位置的数值及地址

void swap(int* x, int* y)

{

    int t;

    t = *x;//使指针x指向t对应的地址

    *x = *y;//使指针y指向x对应的地址

    *y = t;//将t的值赋给y地址对应的数值

}//swap函数定义

//头文件

#include <iostream>

using namespace std;

//主函数

int main() {

    int a[7] = { 1,2,3,4,5,6,7 };//建立有七个元素的整型数组

    int* sp = &a[0];//定义整型指针sp,使其指向数组首地址

    int* ep = &a[6];//定义整型指针ep,使其指向数组尾地址

    int Num = (ep - sp) + 1;//计算数组的长度

    int mid = 0;//设定中间位置的初始值

    if (Num % 2 != 0)//判断数组长度是否为奇数

    {

        mid = Num / 2;//计算中间数的位置

        cout << "中间数是:" << a[mid] << " 中间地址是:" << sp + mid << " 解引用:" << *(sp + mid) << endl;//输出中间数的值,以及中间数的地址,中间数指针对应的数值

    }

    system("pause");

    return 0;

}

13.利用类实现一个顺序表

(1)头文件内容如下:

#pragma once

typedef int Status;

typedef int ElemType;

class SqList

{public:

    ElemType * elem;//存储空间的基础地址

    int length;//线性表当前长度

    int listsize;//当前分配的存储容量(以sizeof(ElemType)为单位)

    //成员函数

    Status InitList_Sq(SqList & L);

    // 操作结果:构造一个空的线性表L

    Status DestoryList_Sq(SqList & L);

    // 初始条件:线性表L已存在

    // 操作结果:销毁线性表L

    Status ListInsert_Sq(SqList & L, int i, ElemType e);

    // 初始条件:线性表L已存在,1≤i≤ListLength(L)+1

    // 操作结果:在线性表L中第i个位置之前插入新的元素e

    Status ListDelete_Sq(SqList & L, int i, ElemType& e);

    // 初始条件:线性表L已存在且非空,1≤i≤ListLength(L)

    // 操作结果:在顺序线性表中删除第i个元素,并用e返回其值

    void PrintList_Sq(SqList L);

    // 初始条件:线性表L已存在

    // 操作结果:输出线性表信息

    Status ClearList_Sq(SqList & L);

    // 初始条件:线性表L已存在

    // 操作结果:将L重置为空表

    Status ListEmpty_Sq(SqList L);

    // 初始条件:线性表L已存在

    // 操作结果:若L为空表,则返回TURE,否则返回FALSE

};

(2)源文件内容如下:

#include<iostream>

#include<stdio.h>

#include<malloc.h>

#include "SqList.h"

using namespace std;

//函数结果状态代码

#define TRUE 1

#define FALSE 0

#define OK 1

#define ERROR 0

#define INFEASIBLE -1

#define OVERFLOW -2

//线性表的动态分配顺序存储结构

#define LIST_INIT_SIZE 100// 线性表存储空间的初始分配量

#define LISTINCREMENT 10// 线性表存储空间的分配增量

Status SqList::InitList_Sq(SqList & L) {

    // 构造一个空的线性表L

    L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));

    if (!L.elem)

         exit(OVERFLOW);// 存储分配失败

    L.length = 0;// 空表长度为0

    L.listsize = LIST_INIT_SIZE;// 初始存储容量

    return OK;

}// InitList_Sq

Status SqList::DestoryList_Sq(SqList & L) {

    // 销毁线性表L

    if (!L.elem)

         return ERROR;// 判断elem是否已空

    free(L.elem);// 销毁线性表

    L.elem = NULL;//销毁指针

    return OK;

}//DestoryList_Sq

Status SqList::ListInsert_Sq(SqList & L, int i, ElemType e) {

    // 在顺序线性表L中第i个位置之前插入新的元素e

    // i的合法值为1≤i≤ListLength(L)+1

    if (i<1 || i>L.length + 1 || L.elem == NULL)

         return ERROR;

    if (L.length >= L.listsize) {

         //当前分配的存储空间已满,需要继续分配新的空间

         ElemType* newbase;

         newbase = (ElemType*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));

         if (!newbase)

             exit(OVERFLOW);//存储空间分配失败

         L.elem = newbase;//新基址

         L.listsize += LISTINCREMENT;//增加存储容量

    }

    for (int j = L.length; j >= i - 1; j--)// 插入位置之后的元素右移

         L.elem[j] = L.elem[j - 1];

    L.elem[i - 1] = e;// 插入e

    L.length++;// 表长加1

    return OK;

}// ListInsert_Sq

Status SqList::ListDelete_Sq(SqList & L, int i, ElemType& e) {

    // 在顺序线性表中删除第i个元素,并用e返回其值

    // i的合法值为1≤i≤ListLength(L)

    if (i<1 || i>L.length || L.elem == NULL)

         return ERROR;

    e = L.elem[i - 1];// 被删除的元素赋给e

    for (int j = i - 1; j < L.length - 1; j++)// 删除位置之后的元素左移

         L.elem[j] = L.elem[j + 1];

    L.length--;// 表长减1

    return OK;

}// ListDelet_Sq

void SqList::PrintList_Sq(SqList L) {

    // 输出线性表信息

    if (!L.elem)

         exit(INFEASIBLE);// 判断elem是否已空

    cout << "线性表中元素有:";

    for (int i = 0; i < L.length; i++)

         cout << L.elem[i] << " ";

    cout << endl << "线性表长度为:" << L.length << endl;

    cout << "线性表容量为:" << L.listsize << endl;

}// PrintList_Sq

Status SqList::ClearList_Sq(SqList & L) {

    // 重置线性表L

    if (!L.elem)

         return INFEASIBLE;// 判断elem是否为空

    free(L.elem);// 释放指针

    if (InitList_Sq(L))

         return OK;

}//ClearList_Sq

Status SqList::ListEmpty_Sq(SqList L) {

    if (!L.elem)

         return INFEASIBLE;// 判断elem是否已空

    if (L.length == 0)

         return TRUE;

    return FALSE;

}//ListEmpty_Sq

(3)主函数内容如下:

#include<iostream>

#include<stdio.h>

#include<malloc.h>

#include "SqList.h"

using namespace std;

int main() {

    SqList L;

    L.InitList_Sq(L);

    L.PrintList_Sq(L);

    // 插入测试

    L.ListInsert_Sq(L, 1, 2);// 插入2

    L.PrintList_Sq(L);

    L.ListInsert_Sq(L, 2, 3);// 插入3

    L.PrintList_Sq(L);

    L.ListInsert_Sq(L, 3, 4);// 插入4

    L.PrintList_Sq(L);

    L.ListInsert_Sq(L, 1, 5);// 插入5

    L.PrintList_Sq(L);

    // 删除测试

    ElemType e;

    L.ListDelete_Sq(L, 2, e);// 删除第二个位置的元素

    L.PrintList_Sq(L);

    cout << "删除的元素为:" << e << endl << endl;

    // 重置测试

    L.ClearList_Sq(L);

    L.PrintList_Sq(L);

    system("pause");

    // 销毁测试

    L.DestoryList_Sq(L);

    L.PrintList_Sq(L);// 表销毁会以INFEASIBLE值退出

    return 0;

    system("pause");

}

1.函数的定义及函数的调用,以及在一个函数中调用另一个函数

 

2.实现两个数的加减乘除

 

 

3.数学函数的调用

 

4.对数组中的元素进行排序

 

5.求x的n次方

(1)代码1

 

(2)代码2

 

6.寻找并输出11~999之间的数m,它满足m,m^2,m^3均为回文数

 

7.读取字符串

 

8.为数组指定位置元素赋值

 

9.求数组元素个数

 

10.实现不同类型指针的算术运算

 

11.交换两个整数的值

(1)函数变量为整型

 

(2)函数变量为指针类型

 

12.求数组中间位置的数值及地址

 

13.利用类实现一个顺序表

 

本次上机实验实现了对C++基础操作的全流程回顾,过程循序渐进、由易到难,利用一些典型案例及算法,让我们快速回顾大一大二所学的C++知识,并直接上手编程实践,深化了我们的理解和操作能力。

首先,从最简单的数据类型,到C++运算符,再到函数,还回顾了选择结构和循环结构的知识,并且回顾了指针变量及结构体变量,以及指针变量内在的内存关系,还回顾了面向对象的程序设计和类。

接着,我们还学习了C++中自带的一些头文件库,如math.h库、algorithm库、string库、cstdio库等,并了解了其功能以及内部包含的一些函数,体会到了C++中各种库良好的封装性,这些库对于C++的功能有着极大的拓展,避免了对一些简单内部函数的重复编写,有助于利用C++实现更为复杂的编程。其中,math.h库主要包含一些数学中的基本函数,如三角函数、反三角函数、对数函数、乘方和开方函数、取整函数等,只要引用了math.h头文件,就可以直接使用这些函数。algorithm库包含了大量用于访问元素的函数,其中就包括了最典型的访问元素——数组,本次程序中使用了sort函数和fill函数,分别用于对数组中指定元素进行排序,对数组中指定的元素进行赋值,这个头文件中还有交换两个元素的函数swap、交换一定范围的函数reverse、输出全排列中的其他序列next_permutation,也可以求得数组中元素的最大值、最小值和整个数组的绝对值。String.h库主要用于处理字符串变量,可以对字符串进行初始化,可以利用数学运算符对字符串进行拼接,本次实验实现算法的过程中使用getline对字符串进行了初始化,另外也可以使用compare函数对不同字符串进行对比,使用substr函数获取子串,使用back和front函数修改第一个字符和最后一个字符,使用erease函数对某个字符进行删除。而cstdio.h库主要用于控制输入输出流,这里涉及到库中的函数为_countof函数,主要用于对数组包含的元素个数进行计算,刚好可以满足算法需求。

基于这些回顾还有新学习的知识,本次上机实验实现了许多算法功能,也对许多算法和程序进行了一些改进,使其实现了更优化的功能,并探索了一些额外的功能,更加深化了对于C++知识的回顾和全面理解,例如,在调用math.h头文件时还测试了反三角函数的功能;在求x的n次方时设置了许多不同的循环方式,如for循环、while do循环;交换两个值中测试了引用变量和非引用变量的不同结果,由此C++的内部存储结构。通过本次上机实验,对于C++产生了系统的认识,逐渐感觉到C++语言的强大功能,进一步理解了C++的独特之处——指针系统,指针作为C++中的一种数据类型,占用一定的内存地址,并存储其指向变量的内存地址,可以实现深层次的操作,指针变量的类型可以为各种数据类型和数组中的元素,利用指针可以改变数据在内存中的存储结构,进而实现许多功能。C++中还有许多系统自带的头文件,在编写程序时,通过对头文件进行引用,就可以调用其内部集成的函数实现相应操作,C++中有许多的库,每一个库也就是一个头文件,为一个类,这个类的成员函数就是众多系统自带的函数,也就是说C++通过各种各样的库实现了包含了许多系统自带函数,并对其进行分类,在想要实现相应功能时就可以直接查找并且调用相应库中的函数,体现了其作为高级语言与用户进行交互的高度集成性。另外,C++中还有数组、结构体等数据类型,数组是一种访问元素,即可以实现按照下标访问相应位置的元素,也可以利用指针访问相应内存位置的函数。而结构体可以看做是类的简化版本,结构体可以实现对于一个物体属性即成员数据的封装,如果对结构体进行操作则需要在结构体外部进行,另外,结构体中所有的成员数据的权限都是public,所有结构体可以简单地看做一个“病态的”类,其具有类的部分功能,其可以作为面向对象的程序设计的一部分使用。

最后,需要理解面向对象的程序设计,在自然界中,任何一个物体都可以看做一个对象,而类就是相同或者近似对象的一个抽象,类的内部包含着各种成员变量和成员函数,成员变量可以作为类的属性,成员函数可以作为类的方法,属性就是一类事物最本质的特质,方法就是这个事物与外界进行交互和变化的手段,通过这两方面,进行各个对象之间的交互,就可以实现在编程语言中构建万物,实现对于真实世界的模拟。而面向对象的程序设计则是将问题划分为一个个对象,然后将这些对象通过一些方法联系起来,让程序中的一个对象告诉另一个对象要做什么,以此来解决问题。在进行具体编程时,面向对象只是将相关的数据和函数封装起来,成为一个类。这样函数就可以直接访问类中的数据。最后,再通过引用头文件的方式,构建对象,并调用类内部的函数,对具体对象实现相应的功能。而面向对象的程序设计的优点为:程序结构模块清晰,代码复用率高,可继承,扩展,覆盖。设计出的系统耦合度低,便于后期维护。但其对于计算机配置的要求较高,执行效率可能会偏低。

而类还有很多拓展,这些都是实现面向对象程序设计的重要基础,类的继承允许依据一个类来定义另一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。当创建一个类时,不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。可以进行多继承(一个派生类有多个基类)和多层派生(多层继承)。新类可以继承原有类的属性和行为,并且可以添加新的属性和行为,或更新原有类的成员。类的继承根据派生类中成员的权限分为共有继承、保护继承和私有继承。多态是针对函数而言的,是指一个函数可以有多重定义,分为静态多态和动态多态,其中静态多态的函数地址早绑定,编译阶段确定函数地址;动态多态的函数地址晚绑定,运行阶段确定函数地址。函数重载和运算符重载属于静态多态,派生类实现动态多态。C++中也可以使用指针指向类,其可以指向类内部的成员,而访问指向类的指针指向的成员需要使用成员访问运算符—>。对于对象进行赋值操作就需要用到拷贝构造函数,相同类下的两个对象进行赋值首先需要拷贝第一个对象的构造函数,再利用赋值运算符进行赋值。类的静态成员变量和静态成员函数定义,其中类的静态成员变量主要特征如下:静态成员变量属于整个类所有;静态成员变量的生命期不依赖于任何对象,为程序的生命周期;可以通过类名直接访问公有静态成员变量;所有对象共享类的静态成员变量;可以通过对象名访问公有静态成员变量;静态成员变量需要在类外单独分配空间;静态成员变量在程序内部位于全局数据区。而类的静态成员函数的主要特征如下:静态成员函数是类的一个特殊的成员函数;静态成员函数属于整个类所有,没有this指针;静态成员函数只能直接访问静态成员变量和静态成员函数;可以通过类名直接访问类的公有静态成员函数;可以通过对象名访问类的公有静态成员函数。这两个变量的构建需要在变量类型前加上static修饰。

综上所述,通过本次实习对于之前学习的C++编程语言知识进行了系统的复习,并且还学习了许多C++中的新功能,对于指针、赋值、面向对象的程序设计等内容有了更加深刻的理解,也形成了较为完整的C++知识的体系,为后续利用C++语言编写程序处理计算机图形学问题打下了良好的基础。

注意:本上机报告适用于中国地质大学(北京)测绘工程专业计算机图形学课程,其他学校也可以参考使用。这些代码只是起到启发作用,不能完全照搬,具体细节还需要自己斟酌修改。

如有问题欢迎在评论区留言,让我们共同交流,一起进步!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值