C++基础编程实践10例

写在前面

这篇Blog是基于哈工大(威海)刘东明老师所讲述课程及所给程序写就,用于C++大题考前复习。侧重于在实践中提高代码能力,需要注意的细节,以及许多库函数的使用。很少涉及语法知识,如有需要可以看另一篇Blog:还没上传。这是去往bing的url。

让我们开始吧(●’◡’●)

Demo1 带符号的大数运算:顺序程序,函数封装,头文件的调用

题目描述:
给定一个输入,如果是数字,计算其平方并输出,否则显示“input error!”。其中数字可能带符号,或很大(超过int类型能容纳的最大值)。其中大数运算的类函数文件在此给出。

题目解答:

#include <iostream>
#include <string> 
#include <sstream>
#include "bignum.cpp"// 大数运算类 
using namespace std;

bool IsDigit(string& str)
{
	bool flag=true;
	int i;
	// 判断第一位是否是正负号 
	if(str[0]=='+'||str[0]=='-')
		i=1;
	else
		i=0;
	for(i=i;i<str.length();i++)
	{
		while(!isdigit(str[i])
		{
			flag=false;
			break;
		}
	}
	return flag;
}

//求大数的平方 
void square(string s)
{
	BigNum ss(1);
	ss=ss.str2Num(s);
	ss=ss*ss;
	ss.print();
}

int main()
{
	string s;
	cout<<"input a number:";
	cin>>s;
	if(IsDigit(s))
	{
		square(s);
	}
	else
	{
		cout<<"input error!"<<endl;
	}
	system("pause");
	return 0;
}

题目收获:

  • 引入外部文件时,<>会在系统路径进行寻找,""会在链接库和本地文件进行查找
  • sizeof()size()length()
    • sizeof()的功能是计算一个数据类型的大小,这个类型可以是数组、函数、指针、对象等,单位为字节,它的返回值是size_t类型,也就是unsigned int类型,是一个无符号整数。特别注意两点:1. 其会将空字符\0计算在内。2. sizeof()不是一个函数,它是一个运算符,所以它不需要包含任何头文件。
    • size()length()是c++中string的类的方法,只有string类的对象才可以用该方法,而字符串数组不可用,size()length() 完全等同,遇到空字符不会被截断,可以返回字符串真实长度,它们结束的标志都是null-termination也就是\n,需要包含头文件#include<string>
    • strlen(),源于C语言,遇到空字符会截断,从而无法返回字符串真实长度,需要include<string.h>
  • C++ 头文件里的:isalpha、islower、isupper、isalnum、isblank、isspace函数
  • str2NumBigNum类中自己写的方法,如果需要自己实现,通常使用下面的代码:
    int str2num(string s)
    {
       stringstream ss;
       double i;
       ss<<s;
       ss>>i;
       return i;
    }
    

Demo2 抽奖程序:对象思想,动态分配,随机数的使用

题目描述:
给定总人数和要抽奖的人数,利用数组实现抽奖程序。

题目解答:

#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;

class select
{
private:	
	int n,m; 
public:	
	select(int nn,int mm)
	{
		n=nn;m=mm;
	}
	void prize()
	{
		int i,temp;
		int* a=new int[n];// 动态数组 
		// int a[n];  不稳定,有些编译器不支持 
		for(i=0;i<n;++i)
		{
			a[i]=0;
		}
		for(i=0;i<m;++i)
		{
			while(true)
			{
				temp=rand()%n;
				if(a[temp]==0)
				{
					cout<<"the people of num "<<temp+1 << "is selected!"<<endl;
					a[temp]=1;
					break;
				}
			}
		}
		delete [] a;//释放动态数组 
	}
};

int main()
{
    srand(time(0));
	select s(30,3);
	s.prize();
	return 0;
}

题目收获:

Demo3 父类有重载的构造函数:重载,默认构造函数,继承,覆盖

#include <iostream>
using namespace std;

class A
{
protected:
    int m;

public:
    A()
    {
        m = 10;
        cout << "A's default constructor is called!" << endl;
    }
    A(int mm)
    {
        m = mm;
    }
    void output()
    {
        cout << "m=" << m << endl;
    }
};

class B : public A
{
protected:
    int n;

public:
	// 自动调用父类的默认构造函数
    B(int nn)
    {
        n = nn;
    }
    // 调用指定的父类构造函数
    B(int mm, int nn) : A(mm)
    {
        n = nn;
    }
    void output()
    {
        cout << "n=" << n << endl;
    }
    void test()
    {
        // 调用父类的函数
        A::output();
        // 默认被覆盖
        output();
    }
};

int main()
{
    B b(2);
    b.test();
    return 0;
}

Demo4 构造一个类:友元函数,运算符重载

题目描述:
构造一个类,分别完成输入输出,双目(一个加号,一个赋值),单目运算符(一个前增,一个后增)的重载。

#include <iostream>
using namespace std;

class A
{
private:
	int m;
public:
	A(int mm){m=mm;}
	
	// 使用友元函数使得类外可以访问类内private和protect!
	friend istream &operator>>(istream &os, A &a);
	friend ostream &operator<<(ostream &os, A a);
	
	// 双目运算符一般有两个参数,但在类内重载时往往省略第一个参数,默认即为this指向的当前对象
	A operator+(A a)
	{
		A temp(0);
		temp.m = m + a.m;
		return temp;
	}
	// 如果缺少显示的返回值类型时,编译器假定为int类型
	// operator=(point p)
    // {
    //     x = p.x;
    //     y = p.y;
    // }
    // 当然也可以写成下面的形式
	A &operator=(A &a)
	{
        this->m = a.m;
        a.m = 9;
        /* 其实此处的返回值并没有意义,因为譬如调用a1=a2,此时双目运算符的两个操作数为this(a1), A &a(a2)。
        而返回值是整个表达式的值,而不会赋值给this。只有当用于a3=a1=a2时返回才具有意义,即对于连续的操作很重要。
        */
        return p;
    }
	
	// ++A,前自增运算符,返回加后引用
	A &operator++()
	{
		++m;
		return *this;
	}
	// A++,后自增运算符,返回加之前的值,此处的(int n)没有实际意义,只是用来区分。而返回一个会因函数退出而销毁的引用值被认为是不规范的。
	A operator++(int n)
	{
		A old(*this);
		++(*this);
		return old;
	}
};
// 类外是不能加friend关键字的,流对象禁止复制所以传引用,输入流必须使用应用以赋值到实参,输出流往往使用const A a
istream &operator>>(istream &os, A &a)
{
	cin >> a.m;
	return os;
}
ostream &operator<<(ostream &os, A a){
	cout << a.m;
	return os;
}

int main()
{
    A a1(10), a2(20);
    a2 = a1++;
    cin >> a1;
    cout << a2;
    A a3(0);
    a3 = a1 + a2;
    cout << a2;
    return 0;
}

Demo5 身高排序:宏定义,简单容器,迭代器,函数指针,计时器

题目描述:
随机生成一组(个数由宏定义决定)学生身高,使用vector和迭代器完成对学生身高的排序和遍历。使用库函数输出平均值,最大值及运行时间。

题目解答:

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
#include <numeric>
#define NUM 10
using namespace std;
class test
{
private:
    vector<int> a;
    vector<int>::iterator p;

public:
    test()
    {
        srand(time(0));
        for (int i = 0; i < NUM; ++i)
        {
            a.push_back(rand() % 55 + 150);
        }
    }
    // 函数名即是函数地址。使用静态函数,从而下面的函数指针无须使用对象.方式即可访问
    static bool cmp(int num1, int num2)
    {
        return num1 > num2;
    }
    void mysort()
    {
        sort(a.begin(), a.end(), cmp);
    }
    void browse()
    {
        for (p = a.begin(); p != a.end(); ++p)
        {
            cout << *p << endl;
        }
    }

    void output()
    {
        cout << "mean" << accumulate(a.begin(), a.end(), 0) / (double)NUM << endl;
        cout << "max:" << *max_element(a.begin(), a.end()) << endl;
    }
};
int main()
{
    clock_t t0 = clock();
    test t;
    t.mysort();
    t.browse();
    t.output();
    cout << "running costs time:" << clock() - t0 << "ms" << endl;
}
Demo5.1 map使用:容器练习2
#include <iostream>
#include <cstdlib>
#include <map>
using namespace std;
struct S
{
    int number;
    int score;
};

class test
{
private:
    map<int, S> a;
    map<int, S>::iterator p;
    int n, i;

public:
    test(int nn)
    {
        n = nn;
        srand(time(0));
        S t;
        for (i = 0; i < n; ++i)
        {
            t.number = rand();
            t.score = rand();
            // map底层是根据key值的hash-tree来存储的,所以key为int型时,无须重载小于号。key为结构体时,需要重载<但无须重载==,包括后面的find,利用的是(!a<b & !b<a)
            a.insert(pair<int, S>(i, t));
        }
    }
    void browse()
    {
        for (p = a.begin(); p != a.end(); ++p)
        {
        	// map中迭代器的用法
            cout << p->first << "-" << p->second.number << "-"
                 << p->second.score << endl;
        }
    }
    void find()
    {
        int temp;
        cout << "input key:";
        cin >> temp;
        p = a.begin();
        // map中find是根据key值进行查找的!
        p = a.find(temp);
        if (p != a.end())
        {
            cout << p->first << "-" << p->second.number << "-"
                 << p->second.score << endl;
        }
        else
        {
            cout << "no record!" << endl;
        }
    }
};

int main()
{
    test t(100);
    t.browse();
    t.find();
    return 0;
}
Demo5.2 寻找元素:容器练习3
#include <iostream>
#include <cstdlib>
#include <list>
#include <ctime>
#include <functional>
#include <algorithm>
using namespace std;
struct S
{
    int number;
    int score;
    bool operator==(S s)
    {
        return score == s.score;
    }
};
class test
{
private:
    int num;
    S t;
    list<S> a;
    list<S>::iterator p;

public:
    test(int num)
    {
        this->num = num;
        for (int i = 0; i < num; ++i)
        {
            t.number = rand() % 100;
            t.score = rand() % 100;
            a.push_back(t);
        }
    }
    void find1(int nn)
    {
        t.score = nn;
        p = a.begin();
        while (1)
        {
            p = find(p, a.end(), t);
            if (p != a.end())
            {
                cout << p->number << "-" << p->score << endl;
                ++p;
            }
            else
                break;
        }
    }
    static bool find_fun(S s)
    {
        return s.score == s.number;
    }
    void find2(int nn)
    {
        t.score = nn;
        p = a.begin();
        while (p != a.end())
        {
 /*
 template<class InputIterator, class Predicate>  
 	InputIterator find_if ( InputIterator first, InputIterator last, Predicate pred )  
  {  
  		for ( ; first!=last ; first++ ) 
  			if ( pred(*first) ) break;  
    	return first;  
  }
    */        
    		p = find_if(p, a.end(), find_fun);
        }
    }
    static void display(S s)
    {
        cout << s.number << "-" << s.score << endl;
    }

    void foreach ()
    {
        for_each(a.begin(), a.end(), display);
    }
};
int main()
{
    srand(time(0));
    test t(50);
    t.find1(23);
    cout << "==================================" << endl;
    t.find2(23);
    cout << "==================================" << endl;
    t.foreach ();
    cout << "==================================" << endl;
    return 0;
}
		

题目收获:

Demo6 秒表计时器:键盘交互,界面控制,伪多线程

basic.cpp:

//光标移动到指定坐标处
void gotoxy(int x, int y)
{
    COORD c;  //结构体,坐标值
    c.X = x;
    c.Y = y;
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); //句柄,对象的索引
    SetConsoleCursorPosition(h, c);
}

//隐藏光标
void hide_cursor()
{
    HANDLE h_GAME = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO cursor_info;
    GetConsoleCursorInfo(h_GAME, &cursor_info);
    cursor_info.bVisible = false; //不显示光标
    SetConsoleCursorInfo(h_GAME, &cursor_info);
}

//显示光标
void show_cursor()
{
    HANDLE h_GAME = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO cursor_info;
    GetConsoleCursorInfo(h_GAME, &cursor_info);
    cursor_info.bVisible = true; //显示光标
    SetConsoleCursorInfo(h_GAME, &cursor_info);
}

//设置文本颜色
void color(int a)
{
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), a);
}

main.cpp:

//秒表计时器
#include <windows.h>
#include <iostream>
#include <ctime>
#include <list>
// 格式化输出头文件
#include <iomanip> 
#include "basic.cpp"
using namespace std;

class test
{
private:
    int n, x, y;
    clock_t t,t2;

public:
    test()
    {
        n = 0;
        t = clock();
        t2 =clock();
        x = 10;
        y = 10;
        hide_cursor();
    }
    void draw()
    {
	    gotoxy(x, y);
	    // 格式化输出
	    cout << setw(3) << setfill('0') << n;
    }
    void erase()
    {
    	gotoxy(x, y);
    	cout << "   ";
    }
    void move1()
    {
    	// 注意此处的数必须是1000,因为1000ms=1s对应题目中的秒表计时器
        if (clock() - t > 1000)
        {
 			draw();
            ++n;
            t = clock();
        }
    }
    void move2()
    {
    	if(clock() - t2 > 50)
    	{
    		erase();
    		if (GetAsyncKeyState(VK_ESCAPE))
    			exit(0);
    		if (GetAsyncKeyState(VK_UP))
    			--y;
    		if(GetAsyncKeyState(VK_DOWN))
    			--x;
    		if (GetAsyncKeyState(VK_RIGHT))
                ++x;
            draw();
            t2 = clock();
    	}
    }
    void move()
    {
        while (true)
        {
            move1();
            move2();
        }
    }
    ~test()
    {
        show_cursor();
    }
};
int main()
{
    test t;
    t.move();
    return 0;
}

Demo7 寻找子串:字符串

题目描述:
给定一个长字符串和一个短字符串,输出所有包含的子串的头、尾位置和找到的子串。

题目解答:

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s = "abcdbce";
    string s1 = "bc";
    string::size_type n1, n2 = 0;
    while (s.find(s1, n2) != string::npos)
    {
        // 从0位置开始查找
        n1 = s.find(s1, n2);
        n2 = n1 + s1.size() - 1;
        cout << "n1=" << n1 << endl;
        cout << "n2=" << n2 << endl;
        cout << "substr=" << s.substr(n1, n2 - n1 + 1) << endl;
    }
    return 0;
}

题目收获:

Demo8 英汉词典查询:文本文件读取,字符串

题目描述:
给定一个文件“英汉词典.txt”。编写方法实现一次性读入。再编写方法实现精准查询。其中,文件的读的打开方式为以传参+构造函数方法打开

题目解答:

#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class test
{
private:
    ifstream f1;
    string s = "#";

public:
    void read_from_file(string filename)
    {
        // C++11之前,只能接受c_str()类型
        ifstream f(filename.c_str(), ios::in);
        if (!f)
        {
            cout << "open file error!" << endl;
            exit(0);
        }
        else
        {
            string ss = "";
            while (!f.eof())
            {
                getline(f, ss);
                s = s + ss + "#";
            }
        }
    }
    void dict()
    {
        string word;
        cout << "input a word:";
        cin >> word;
        // int pos = 0;
        int n1, n2, n3 = 0;
        while (s.find(word, n3) != string::npos)
        {
            n1 = s.find(word, n3);
            // 为实现全词匹配,需要找到该词前面最近的“#”
            n1 = s.rfind("#", n1);
            n2 = s.find(" ", n1 + 1);
            string dicword = s.substr(n1 + 1, n2 - n1 - 1);
            // 不断让s3推移,以防止模糊匹配未进if的情况,程序有出口的前提是每个分支都有出口!
            n3 = s.find("#", n2);
            // 如果想实现模糊查询,只需把该判断条件去掉即可,即只要部分包含该词,就取前后两个##之间字符串进行打印
            if (dicword == word)
            {
                string exp = s.substr(n1 + 1, n3 - n1 - 1);
                cout << exp << endl;
            }
        }
    }
};
int main()
{
    string filename;
    cout << "input filename:";
    cin >> filename;
    test t;
    t.read_from_file(filename);
    t.dict();
}
Demo8.1 英汉词典查询:文本文件,容器

题目描述:
给定一个文件“英汉词典.txt”。编写方法实现按行读入并存储进容器。再编写方法实现精准查询。将最终查询结果写入“results.txt”。

题目解答:

#include <iostream>
#include <string>
#include <fstream>
#include <map>
#include <algorithm>
using namespace std;
class test
{
private:
    ifstream f1;
    ofstream f2;
    string s, s1, word;
    string::size_type n;
    map<string, string> a;
    map<string, string>::iterator p;

public:
    test()
    {
        f1.open("./英汉词典.txt", ios::in);
        f2.open("results.txt", ios::app);
        if (!f1)
        {
            cout << "open file error!" << endl;
            exit(0);
        }
        else
        {
            while (!f1.eof())
            {
                getline(f1, s);
                n = s.find(" ", 0);
                s1 = s.substr(0, n);
                a.insert(pair<string, string>(s1, s));
            }
        }
    }
    void dict()
    {
        cout << "input a word:";
        cin >> word;
        p = a.find(word);
        if (p != a.end())
        {
            cout << p->second << endl;
            f2 << p->second << endl;
        }
        else
        {
            cout << "no word!" << endl;
            f2 << "no word!" << endl;
        }
    }
    ~test()
    {
        f1.close();
        f2.close();
    }
};
int main()
{
    test t;
    t.dict();
    return 0;
}
Demo8.2 便签合成:二进制文件

题目描述:
打开一个二进制文件,读出其中内容,以二进制方式写入另一个二进制文件。

题目解答:

#include <iostream>
#include <fstream>
using namespace std;

class test
{
private:
	fstream f1,f2;
	string s;
	string::size_type n;
public:
	test()
	{
		f1.open("test.txt",ios::in|ios::out|ios::binary);
		f2.open("test1.txt",ios::out|ios::binary);
		if(!f1||!f2) cout<<"打开文件错误!"<<endl;
	}
	~test()
	{
		if(f1&&f2) {f1.close();f2.close();}
	}
	void turn()
	{
		f1.seekg(0,ios::end);
		n=f1.tellg();
		s.resize(n);
		f1.seekg(0,ios::beg);
		f1.read((char*)s.c_str(),n);

		f2.seekp(0,ios::beg);
		f2.write((char*)s.c_str(),n);
		cout<<"处理结束!"<<endl;
	}
};

int main()
{
	test t;
	t.turn();
	return 0;
}

题目收获:

  • 文件打开类型
  • ios::app和ios::ate的区别
  • 二进制文件常用操作:
    二进制文件常用操作
    • seekg/p():其中偏移量为负,向前;偏移量为正,向后。ios::beg为0,ios::end为eof,也就是最后一个字符的后一位(C++也遵从左闭右开的法则)。关于偏移量的问题点这里。
    • read(n, sizeof(n)):先向后移动sizeof(n)字节,如果读到了eof,不论sizeof(n)大小,则会返回上一次成功读取的内容。
  • 二进制文件和文本文件的差别:无论是什么文件,本质上都是存储的二进制。
    • 文本文件是以编码后的格式,如一个文件以ASCII码存储,则如int类型15将会被以1的ASCII码+5的ASCII码存储,共2个字节。
    • 二进制文件,则会按照数据类型存储4个字节,内容为0…001111,但人打开文件时会发现其不可读,因为文件展示的都是其按照编码集编码过后的字符。

Demo9 :模板,虚函数,异常

题目描述:

题目解答:

题目收获:

Demo10 直接上代码啦:零散知识点

  • 键盘事件:
c=getch();
system("pause");
if(kbhit()) break;
  • 分配空间:
int a = new int;
delete a;
int b = new int[5];
delete []b; // 会依次释放每一个元素
  • 指针与数组:
int* a,b[5],i;
a=new int[5];
cout<<"a="<<a<<endl;
cout<<"&a="<<&a<<endl;
cout<<"&a[0]="<<&a[0]<<endl;
cout<<"&a[1]="<<&a[1]<<endl;
cout<<"=============="<<endl;
cout<<"b="<<b<<endl;
cout<<"&b="<<&b<<endl;
cout<<"&b[0]="<<&b[0]<<endl;
cout<<"&b[1]="<<&b[1]<<endl;

 /* 
 a=0x1031688
 &a = 0x60fe88 
 &a[0] = 0x1031688 
 &a[1] = 0x103168c 
 == == == == == == ==
 b = 0x60fe74 
 &b = 0x60fe74 
 &b[0] = 0x60fe74 
 &b[1] = 0x60fe78 
 */
  • 引用:
int a=0;
int &p =a;
a= 99;	// 同时改变
p =88;	// 同时改变
int &p3 = p; // 引用可以被引用,因为此刻代表的是变量啦
cout << p3;

const int &p1 = a; // 一个变量允许多引用。
p1=77; // ERROR! 常引用,和int const一个效果,不许修改。

int &p1=b; // ERROR! 必须有对象。必须从一而终。
  • 字符串:
string.erase(pos, n);

还没写完,有时间再补充…

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值