函数
函数、输入、传参
在程序中使用函数时,你必须先声明它然后再定义声明的目的是告诉编译器你即将要定义的函数的名字是什么,返回值的类型是什么以及参数是什么而定义则是告诉编译器这个函数的功能是什么。假如我们不声明,那么该函数就不能被其他函数调用通常我们把函数声明叫做函数原型,而把函数定义叫函数实现。
#include<bits/stdc++.h>
using namespace std;
using std::cout;
using std::endl;
void show()
{
int lf = 123;
std::cout << "hello world";
//return lf;
}
void lf(string name, int age)
{
cout << name << age << endl;
}
int count(int a, int b)
{
return a + b;
}
int main()
{
//show();
//std:cout << s << endl;
lf("lf", 12);
cout <<count(1,2) << endl;
int a, b;
cout << "请依次输入两个数字进行求和:"<<endl;
cin >> a; //用a保存接受用户输入
cin >> b;
cout << count(a, b) << endl;
return 0;
}
函数声明
在程序中使用函数时,你必须先声明它然后再定义声明的目的是告诉编译器你即将要定义的函数的名字是什么,返回值的类型是什么以及参数是什么而定义则是告诉编译器这个函数的功能是什么。假如我们不声明,那么该函数就不能被其他函数调用通常我们把函数声明叫做函数原型,而把函数定义叫函数实现。
先声明再调用就不会出现找不到的情况,只要声明了就会保存在内存空间,直到找到函数的实现
#include<bits/stdc++.h>
using namespace std;
void A();
void B();
void A()
{
cout << "A\n";
B();
}
void B()
{
cout << "B\n";
A();
}
int main()
{
A();
B();
return 0;
}
局部变量
只能存活在swap函数之内,swap结束之后,swap函数内的局部变量也就被销毁掉了
因此具体的交换只能反映再swap函数之内,而不能反映在swap函数之外
#include<bits/stdc++.h>
using namespace std;
void swap(int, int);
int main()
{
int x = 3, y = 4;
cout << " main before"<<x << y << endl;
swap(x, y);
cout << " main after" << x << y << endl;
return 0;
}
void swap(int x, int y)
{
cout << "swap before" << x << y << endl;
int c = x;
x = y;
y = c;
cout << "swap after" << x << y << endl;
}
全局变量
#include<bits/stdc++.h>
using namespace std;
void swap(int, int);
int x = 3, y = 4;
int main()
{
int x = 3000, y = 4000;
cout << " main before"<<x << y << endl;
swap(x, y);
cout << " main after" << x << y << endl;
return 0;
}
void swap(int x, int y)
{
cout << "swap before" << x << y << endl;
int c = x;
x = y;
y = c;
cout << "swap after" << x << y << endl;
}
数据的类型
字符型
#include<bits/stdc++.h>
using namespace std;
int main()
{
char ch = 65;
cout << ch << endl;
cout << (int)ch;
for (int i = 32; i < 128; i++)
{
cout << (char)i << endl;
}
return 0;
}
双字节型
#include<bits/stdc++.h>
#include<locale>
using namespace std;
int main()
{
//设置所有的为中文类型
setlocale(LC_ALL,"chs");
wchar_t wt[] = L"中";
//wcout代替cout进行输出,因为cout无法输出宽字节型
wcout << wt;
return 0;
}
整型
#include<bits/stdc++.h>
#include<locale>
using namespace std;
int main()
{
cout << sizeof(int) << endl;
cout << sizeof(short) << endl;
cout << sizeof(long) << endl;
unsigned int a;
cout << sizeof(unsigned int) << endl;
unsigned short b;
cout << sizeof(unsigned short) << endl;
unsigned long c;
cout << sizeof(unsigned long) << endl;
return 0;
}
数据溢出
从该程序中我们看出整型数据溢出后不会报错,而是象汽车里程表那样,到达最大值后,又从最小值开始因此我们需要时刻注意所定义变量的最大取值计数。范围,一定不要超过这个范围进行赋值。
浮点型
使用了头文件iomanip 中的函数 setprecision(),该函数用来设置输出的精度也就是用来设置输出多少位数字,
假如我们将其设置为 15,那么程序就将输出 15 位数字,即使不够,也要凑够15位并输出。
#include<bits/stdc++.h>
#include<iomanip>
using namespace std;
int main()
{
float a = 1.2342421;
cout << setprecision(15) << a;
return 0;
}
枚举型常量
#include<bits/stdc++.h>
#include<iomanip>
using namespace std;
int main()
{
enum num { zero = 1, one, two = 200,three,four };
cout << zero << "\t" << one << "\t" << two << "\t" << three << "\t" << four;
return 0;
}
用enum定义了一个枚举型常量day:它有7个值,每个值对应一个整数从0开始计数,这样星期一(Monday)的值为1,
而星期六(Saturday)的值则为6。
#include<bits/stdc++.h>
#include<iomanip>
using namespace std;
int main()
{
enum day { Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Satuday };
day today;//创建一个变量today
today = Monday;
cout << today; //输出为1
if (today == Satuday || today == Sunday)
{
cout << "休息\n";
}
else
{
cout << "上班\n";
}
return 0;
}
数组
逆序题
交换位置,只需要交换一半的位置就可以了
#include<bits/stdc++.h>
#include<iomanip>
//#include <typeinfo>
using namespace std;
int main()
{
int arr[] = {1,2,3,4,5};
int temp = 0;
int length = sizeof(arr) / sizeof(int);
int end = sizeof(arr) / sizeof(int) - 1;
for (int i = 0; i < length/2; i++)
{
temp = arr[i];
arr[i] = arr[end];
arr[end] = temp;
end--;
}
for (int t : arr) {
cout << t << " ";
}
return 0;
}
二维数组题目
#include<bits/stdc++.h>
#include<iomanip>
//#include <typeinfo>
using namespace std;
int main()
{
//建立二维数组(初始化)
int scores[3][3];
string names[3] = { "张三","李四","王五" };
//赋三科分数
int a = 0;
int b = 0;
int c = 0;
//计数(下标)
int n = 0;
int m = 0;
//总分
int sum[3];
do {
cout << "请分别输入" << names[n] << "的三科成绩:" << endl;
cin >> a >> b >> c;
sum[n] = a + b + c;
scores[n][m++] = a;
scores[n][m++] = b;
scores[n][m] = c;
m = 0;//置为0
n++;
cout << endl;
} while (n < 3);
//输出
for (int i = 0; i < 3; i++) {
cout << names[i] << "的总成绩为" << sum[i] << endl;
}
return 0;
}
面向对象(类)
#include<bits/stdc++.h>
#include<iomanip>
//#include <typeinfo>
using namespace std;
class Human
{
public:
void walk() { cout << "walk\n"; };
void speak() { cout << "speak\n"; };
void run() { cout << "run\n"; };
void eat() { cout << "eat\n"; };
};
int main()
{
Human lf;
lf.walk();
lf.speak();
lf.run();
lf.eat();
return 0;
}
指针
#include<bits/stdc++.h>
using namespace std;
int main() {
int i = 1;
//cout << &i ;
int a = 1;
int* p;
p = &a;
cout << &a << " " << p << " " << *p<<" " << a<<endl;
cout << "--------------------"<<endl;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int main() {
int i = 1;
int* p = 0;
cout << &i <<" " << i <<" " << &p<< " " << p;
return 0;
}
创建堆
C++中使用关键字new创建一个堆并分配内存
#include<bits/stdc++.h>
using namespace std;
typedef unsigned short int ut;
int main() {
int* p = new int;
*p = 4;
cout << *p;
return 0;
}
请不要再次对该指针进行删除,因为它所指向的内存区域已经被释放,如果再进行释放,将会使程序崩溃。不过,假如我们将该指针赋为0的话,那么删除一个空指针将是安全的
#include<bits/stdc++.h>
using namespace std;
typedef unsigned short int ut;
int main() {
int* p = new int;
delete p;
p = 0;
delete p;
}
#include<bits/stdc++.h>
using namespace std;
typedef unsigned short int ut;
int main() {
int* p = new int;
*p = 3600;
cout << *p << endl;
delete p;
cout << *p << endl;
p = 0;
p = new int;
*p = 8;
cout << *p << endl;
delete p;
return 0;
}
内存泄漏
就会造成内存泄露,这是因为,第 1行定义了一个指针p 并使其指向一块内存空间,第2行又将一块新的内存空间的地址赋给了 P。这样第1行所开的那块内存空间就无法再使用了因为指向它的指针现在已经指向了第2块空间。
指针变量p只能保存一个地址,如对它重新赋值,则表示以前的地址被覆盖,假如该地址的内存空间没有被释放,那么你将无法再次通过指针p 访问它是第2块内存的地址
int* p = new int;
delete p;
p = new int;
this指针
学生在发新课本时一般都要将自己的名字写在课本上,以说明该课本是自己的,避免与其他人的混淆。对象也要在属于自己的每个成员身上写下自己的名字,以证明该成员是自己的成员,而不是其他对象的成员。this 变量帮助对象做到这一点this 变量记录每个对象的内存地址然后通过间接访问运算符->访问该对象的成员。例程如下:
#include<bits/stdc++.h>
using namespace std;
class A
{
public:
int get() { return i; }
void set(int x) {
this->i = x;
cout << this << endl;
}
private:
int i;
};
int main() {
A a;
a.set(9);
cout << a.get() << endl;
A b;
b.set(10);
cout << b.get() << endl;
return 0;
}
引用
引用的作用
引用在C++中有以下几个主要作用:
- 别名: 引用允许我们创建变量的别名,可以通过不同的名称来访问同一变量或对象,从而使代码更加灵活易读。
- 函数参数传递: 通过将函数参数声明为引用,函数可以直接修改调用者传递的变量,而无需使用指针或复制数据。这种方式避免了对大型结构体或对象进行值传递时的开销,提高程序效率。
- 返回值: 函数可以返回引用类型,以便调用者可以使用相同的名称访问函数返回的变量或对象。这也可以避免大型结构体或对象复制的开销,提高程序效率。
引用并不是值传递,而是通过地址传递。当我们将一个变量作为引用传递给函数时,函数得到的是该变量的地址,而不是变量的副本。因此,对引用所代表的变量进行的任何修改都会影响到原始变量。与之相反,当我们将变量作为值传递给函数时,函数得到的是该变量的一个副本,对副本的修改不会影响到原始变量
引用和指针的区别
引用和指针都可以用于间接访问变量或对象,但它们之间有以下几个区别:
- 语法: 引用使用&符号进行声明,而指针使用*符号进行声明。
- 空值: 指针可以为NULL或nullptr,表示指向空地址;而引用必须始终指向某个有效的对象。
- 初始化: 在声明时,引用必须被初始化为某个对象,而指针则可以在任何时候被初始化或赋值为一个地址。
- 可更改性: 一旦引用被初始化为某个对象,就不能再更改它的引用对象;而指针可以在任何时候重新分配到另一个对象。
- 所指对象的内存管理: 指针可以进行动态内存分配和释放,因此需要程序员手动管理内存;而引用只是对已经存在的对象的引用,无需手动管理内存。
需要注意的是,引用实际上是通过指针来实现的。当我们创建一个引用时,编译器会为该引用创建一个指针,并将其自动关联到所引用的变量。因此,从内部机制上说,引用和指针是密切相关的。
引用和指针都可以被视为值传递的方式,因为它们传递的是内存地址(即指向实际数据的指针),而不是数据本身。当使用引用或指针时,对该地址上的数据进行更改会影响原始数据。
#include<bits/stdc++.h>
using namespace std;
int main() {
int a;
int& ra = a;
a = 999;
cout << typeid(&a).name() << endl;
cout << typeid(&ra).name() << endl;
cout << &a << endl;
cout << &ra << endl;
return 0;
}
C++ STL 教程
在前面的章节中,我们已经学习了 C++ 模板的概念。C++ STL(标准模板库)是一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量、链表、队列、栈。
C++ 标准模板库的核心包括以下三个组件:
组件 | 描述 |
---|---|
容器(Containers) | 容器是用来管理某一类对象的集合。C++ 提供了各种不同类型的容器,比如 deque、list、vector、map 等。 |
算法(Algorithms) | 算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。 |
迭代器(iterators) | 迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。 |
这三个组件都带有丰富的预定义函数,帮助我们通过简单的方式处理复杂的任务。
下面的程序演示了向量容器(一个 C++ 标准的模板),它与数组十分相似,唯一不同的是,向量在需要扩展大小的时候,会自动处理它自己的存储需求:
实例
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// 创建一个向量存储 int
vector<int> vec;
int i;
// 显示 vec 的原始大小
cout << "vector size = " << vec.size() << endl;
// 推入 5 个值到向量中
for(i = 0; i < 5; i++){
vec.push_back(i);
}
// 显示 vec 扩展后的大小
cout << "extended vector size = " << vec.size() << endl;
// 访问向量中的 5 个值
for(i = 0; i < 5; i++){
cout << "value of vec [" << i << "] = " << vec[i] << endl;
}
// 使用迭代器 iterator 访问值
vector<int>::iterator v = vec.begin();
while( v != vec.end()) {
cout << "value of v = " << *v << endl;
v++;
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
vector size = 0
extended vector size = 5
value of vec [0] = 0
value of vec [1] = 1
value of vec [2] = 2
value of vec [3] = 3
value of vec [4] = 4
value of v = 0
value of v = 1
value of v = 2
value of v = 3
value of v = 4
关于上面实例中所使用的各种函数,有几点要注意:
- push_back( ) 成员函数在向量的末尾插入值,如果有必要会扩展向量的大小。
- size( ) 函数显示向量的大小。
- begin( ) 函数返回一个指向向量开头的迭代器。
- end( ) 函数返回一个指向向量末尾的迭代器