C++基础

C++基础

一、输入与输出

在编写C++程序的时候,如果使用输入输出,需要包含头文件iostream,包含了输入和输出的对象,比如cin是标准的输入,cout是标准的输出,cerr是标准错误输出。
iostream:input output stream,输入输出流
cout和cin是C++的内置对象不是关键字。
cout的使用方式:cout后面跟<<左移,再拼接需要输出的内容,比如表达式等。 cout << 表达式1 << 表达式2…;
cin的使用方式:cin后面跟>>右移,再拼接变量即可,就可以将输入的内容保存到变量中。cin>>变量1>>变量2…;
endl:end of line 代表结束一行,也就是换行操作。

代码示例:

#include <iostream>
// 使用std命名空间,就可以在以下代码中直接使用cout endl等内容
using namespace std;
int main()
{
	// 输入两个数字,打印其中的最小值
	int number1, number2;
	cin >> number1 >> number2;
	cout << (number1 < number2 ? number1 : number2) << endl;
	return 0;
}

二、动态内存空间

1、 new和delete

new

new来进行动态内存空间开辟:单个内存 new 类型名(初始值);多个连续内存 new 类型名[整型];

delete

delete来释放new出来的动态空间:不是数组类型的连续空间,就直接使用delete 指针名; 如果是连续空间,就需要使用delete[] 指针名;

代码演示:

#include <iostream>
using namespace std;
int main()
{
	int* p1, * p2;
	// 申请单独的int空间
	p1 = new int(100);
	// 申请一块5个int类型的空间
	p2 = new int[5];

	//// 获取p1指向的内存中的值
	//cout << *p1 << endl;
	////释放单个空间
	//delete p1;
	//p1 = NULL;

	int* p = p2;
	for (int i = 0; i < 5; i++)
	{
		/*p2[i] = i + 100;*/
		// *(p2 + i) = i + 100;
		*p2 = i + 100;
		p2++; // 注意p2的位置移动
	}

	for (int i = 0; i < 5; i++)
	{
		cout << p[i] << endl;
	}
	// 将连续的空间给释放掉
	delete[] p;
	return 0;
}

2、malloc和free

​ 和C语法中的使用方式相同。

代码演示

#include <iostream>
using namespace std;

// 定义一个函数来翻转数组,要求实现两种情况,第一种直接在原数组上进行翻转,第二种是不改变原数组,会将翻转后的结果保存到一个新的数组中,返回给函数的调用者
void reverse1(int* p, int len)
{
	for (int i = 0, j = len - 1; i < j; i++, j--)
	{
		int temp = p[i];
		p[i] = p[j];
		p[j] = temp;
	}
}

int* reverse2(int* p, int len)
{
	// 动态开辟的空间不会随着函数的调用结束而被自动释放。
	int* newArr = new int[len];
	int j = 0;
	for (int i = len - 1; i >= 0; i--)
	{
		newArr[j] = p[i];
		j++;
	}
	return newArr;
}

int main()
{
	int arr[5] = { 10,20,30,40,50 };
	// reverse1(arr, 5);
	int*p = reverse2(arr, 5);
	for (int i = 0; i < 5; i++)
	{
		cout << p[i] << " ";
	}
	cout << endl;
	delete[] p;
	/*int* p = (int*)malloc(sizeof(int) * 5);
	for (int i = 0; i < 5; i++)
	{
		if (p != NULL)
		{
			p[i] = 100 + i;
		}	
	}
	
	for (int i = 0; i < 5; i++)
	{
		if (p != NULL)
		{
			cout << p[i] << endl;
		}
	}

	free(p);*/
	return 0;
}

三、引用

​ 概念:引用就是对已有变量起别名的一种机制,一般主要用在函数的形参和返回值上
​ 作用:给变量起别名
​ 语法:数据类型&别名 = 原名;
​ 注意事项:
​ 1、引用必须要进行初始化
​ 2、引用初始化之后不可以改变

#include <iostream>
using namespace std;
int main()
{
	//int a = 100;
	//int d = 200;
	//// 数据类型& 别名 = 原名;
	//int& b = a;

	//cout << "a = " << a << endl;
	//cout << "b = " << b << endl;

	//b = 1000;
	//cout << "a = " << a << endl;
	//cout << "b = " << b << endl;


	//// 引用必须要进行初始化
	//// int& c;
	//int& c = a;
	//// c = b;
	//// 引用初始化之后不可再作为别的变量的别名使用
	//// int& c = d;
	//c = d;
	//cout << "a = " << a << endl;
	//cout << "b = " << b << endl;
	//cout << "c = " << c << endl;

	// 引用的本质就是指针常量
	int a = 10;
	// 会自动转化为int* const ref = &a,指向不可以修改,但是值是可以的。
	int& ref = a;

	// 内部发现ref是引用,会自动将其转化为*ref = 20
	ref = 20;

	// 常引用
	// 在C++ 如果不想改变指向,也不想改变值,就可以使用常引用
	const int& test = a;
	// 本质就是const int* const test = &a
	// test = a;

	//char ch1[10] = "12345";
	//char ch2[5] = "abc";

	//strcpy_s(ch1, strlen(ch2)+1, ch2);

	//cout << ch1 << endl;
	return 0;
}

四、函数的重载

​ 概念:在C++中可以定义多个同名函数,只要他们的形参个数或者形参类型不完全相同即可,编译程序会根据形参的匹配情况,来自动选择调用哪一个函数来完成执行。函数的类型(函数的返回值类型)不能作为函数重载的依据的。

#include <iostream>
using namespace std;
void print(int number)
{
	cout << "正在调用int形参的函数" << endl;
	cout << number << endl;
}
void print(int number1, int number2)
{
	cout << "正在调用两个int形参的函数" << endl;
	cout << number1 << "," << number2 << endl;
}
void print(double number)
{
	cout << "正在调用double形参的函数" << endl;
	cout << number << endl;
}
void print(char ch)
{
	cout << "正在调用char形参的函数" << endl;
	cout << ch << endl;
}


// 函数的类型不能作为函数重载的依据
int getNum()
{
	return 100;
}

//double getNum()
//{
//	return 200.22;
//}


// 设定一组函数,可以获取两个int类型、三个int、两个double、一个double一个int、两个char类型等内容的最小值

int getMin(int a, int b)
{
	return a < b ? a : b;
}

int getMin(int a, int b, int c)
{
	return a < b ? (a < c ? a : c) : (b < c ? b : c);
}

double getMin(double a, double b)
{
	return a < b ? a : b;
}

double getMin(double a, int b)
{
	return a < b ? a : b;
}

double getMin(int b, double a)
{
	return a < b ? a : b;
}

char getMin(char a, char b)
{
	return a < b ? a : b;
}
int main()
{
	/*print(1000);
	print(1000,2000);
	print(10.22);
	print('A');*/

	cout << getMin(100.1, 10) << endl;
	cout << getMin(10, 100.1) << endl;
	return 0;
}

1、函数的形参类型

// 练习:自己定义一个字符串拼接的函数 stringCat,不要使用本身自带strcat函数。
void stringCat(char* str1, char* str2)
{
	// 先让指针指向str1结束标识的位置
	char* p = str1;
	p = p + strlen(str1);
	int len = strlen(str2);

	//while (*str2 != '\0')
	//{
	//	*p = *str2;
	//	p++;
	//	str2++;
	//}
	// 将str2的字符依次遍历赋值给str1后续的位置,str2和str1的地址在赋值的同时要向后移动,直到str2所有的字符赋值完成
	for (int i = 0; i < len; i++)
	{
		*p = *str2;
		p++;
		str2++;
	}
}
int main()
{
	char ch1[100] = "abcdef";
	char ch2[100] = "12345";
	stringCat(ch1, ch2);
	cout << ch1 << endl;
	int a = 100, b= 200;
	// 值作为函数的形参,形参可以是变量、值、表达式。
	swap1(a, b);
	swap1(10, 20);
	swap1(10 + 20, 100 + 200);

	//// 引用作为参数,形参只能是变量名,不能是值或者是表达式等情况。
	//swap3(a, b);
	////swap3(10, 20);
	////swap3(10 + 20, 100 + 200);
	//cout << "a = " << a << "\tb = " << b << endl;
	return 0;
}
值传递

​ 值传递不会改变实参的值,因为实参和形参在内存中的空间不同,并且实参的类型可以是值、变量名或者表达式等等
​ 例:

// 值传递
// 变量作为形参,不会改变实参的值,因为形参和实参分别使用的是不同的内存空间
void swap1(int x, int y)
{
	cout << "交换之前的x和y的值是:" << "x = " << x << "\ty=" << y << endl;
	int tmp;
	tmp = x;
	x = y;
	y = tmp;
	cout << "交换之后的x和y的值是:" << "x = " << x << "\ty=" << y << endl;
 }
地址传递

​ 指针作为形参,会改变实参的值
​ 例

// 地址传递
// 指针作为参数,会改变实参的值,因为形参获取的是实参的地址
void swap2(int* x, int* y)
{
	cout << "交换之前的x和y的值是:" << "x = " << *x << "\ty=" << *y << endl;
	int tmp;
	tmp = *x;
	*x = *y;
	*y = tmp;
	cout << "交换之后的x和y的值是:" << "x = " << *x << "\ty=" << *y << endl;
}

​ 引用作为形参,会改变实参的值,因为引用是一种别名机制,对于形参的操作实际上就是对实参的操作,实参的类型只能是变量名,不能是表达式或者值等内容。
​ 例

// 引用作为函数的参数,也会改变实参的值。
void swap3(int& x, int& y)
{
	cout << "交换之前的x和y的值是:" << "x = " << x << "\ty=" << y << endl;
	int tmp;
	tmp = x;
	x = y;
	y = tmp;
	cout << "交换之后的x和y的值是:" << "x = " << x << "\ty=" << y << endl;
}

2、内联函数inline

​ 一些比较小规模的并且被频繁调用的函数,可以将其定义为内联函数,以提高程序的执行效率,内联函数不是在调用的时候发生资源的消耗的,而是在编译的时候直接将被调用的函数嵌入到每一个函数调用处,节省函数调用的开销。
​ 图示
在这里插入图片描述

内联函数的定义
inline 类型说明符 函数名(形参列表);

注意点:
并非所有的函数都可以指定为内联函数,如果嵌入函数比较复杂,比如循环、分支、即是定义了内联函数,编译器也会将其当做普通函数来进行处理。
虽然内联函数是可以减少调用函数的时候开销,但是会导致编译后的程序变大,所以也并不是完美的。

3、函数的默认参数

概念:在定义函数的时候,可以预先为函数的参数来指定默认值,在函数调用的时候,如果给出实参,就采用实参值,如果没有给出实参,就使用默认参数。

注意:要求默认形参值必须按照由右向左的顺序进行定义,如果某个参数有默认值,则其右侧的参数必须都有默认值
如果函数的定义和声明是分开的,默认参数只能在一个地方来说明,一般在声明函数的时候说明默认参数即可

#include <iostream>
using namespace std;
inline int getSum(int a, int b)
{
	return a + b;
}

//// 定义一个带默认参数的函数
//void print(int a, int b = 200, int c = 100)
//{
//	cout << "a = " << a << "\tb = " << b  << "\tc = " << c << endl;
//}

// 练习:使用默认参数来实现求x的n次方,如果没有传递实参,默认计算的是10的2次方
// 如果函数的定义和声明是分开的,默认参数只能在一个地方来说明,一般在声明函数的时候说明默认参数即可。
int power(int x = 10, int n = 2);
int main()
{
	cout << power(5,3) << endl;
	cout << power() << endl;
	return 0;
}

int power(int x, int n)
{
	int i, s = 1;
	for (i = 0; i < n; i++)
	{
		s *= x;
	}
	return s;
}

4、命名空间

​ 概念:当我们程序大到一定程度的时候,可能会被拆分成多个子项目,每一个子项目都由不同的人或者小组来完成和维护,所以程序必须要小心处理标识符的命名问题。为了避免标识符的冲突问题,C++引入了一个新的机制,就是命名空间(也叫做名称空间)

​ 命名空间定义 namespace 命名空间名{…}

注意点:
命名空间只能在全局范围定义,但是命名空间可以嵌套。
一个命名空间可以作为另外一个命名空间的别名来使用

使用命名空间的方式
使用using来进行声明:using 命名空间名::标识符;
使用using namespace 命名空间名的方式来使用

#include <iostream>
//using namespace std;
using std::cout;
using std::endl;
namespace NameSpace1
{
	int a = 100;
	void f1()
	{
		cout << "f1函数调用" << endl;
	}
}

// 将一个命名空间作为另外一个命名空间的别名
namespace ns1 = NameSpace1;

// 命名空间的嵌套
namespace ns2
{
	int fun(int x, int y);
}

namespace ns3
{
	int fun(int x, int y);
	// 在一个命名空间嵌套另外一个命名空间
	namespace ns4
	{
		int fun(int x, int y);
	}
}

// 在命名空间外如何定义空间内的函数
// :: 域运算符
int ns2::fun(int x, int y)
{
	return x + y;
}

int ns3::fun(int x, int y)
{
	return x - y;
}

int ns3::ns4::fun(int x, int y)
{
	return x * y;
}


//using ns2::fun;
// 如果将命名空间直接使用,一定要注意不同的空间中标识符的冲突问题
using namespace ns2;
using namespace ns3;
int main()
{
	cout << ns2::fun(10, 20) << endl;
	// cout << fun(10, 20) << endl;
	cout << ns3::fun(10, 20) << endl;
	cout << ns3::fun(10, 20) << endl;
	cout << ns3::ns4::fun(10, 20) << endl;
	// 命名空间的使用
	// cout << ns1::a << endl;
	// ns1::f1();
	return 0;
}

5、C++多文件组织

概念
在实际的项目中通常会有大量的程序和各种资源文件,这些程序和资源文件要分别放到不同的文件中去,这里只讨论和当前程序密切相关的两个文件,一种是头文件(.h),一种是源文件(.cpp)
头文件:一般存放的都是结构体的定义、函数的原型(声明)、全局常量、后面介绍到的类等。
源文件:存放的是函数的具体实现(定义)、以及其他需要的一些功能等。

综合练习
​ 要求编写一个处理平面图形的程序
​ 设计一个表示点的结构体Point,有两个int类型的成员标识点的坐标
​ 设计一个表示圆的结构体Circle,包含一个Point成员表示圆心,和一个double类型成员表示半径
​ 设计一个矩形的结构体Rectangle,包含一个Point成员表示图形中心,和两个double类型的成员表示矩形的长和宽
​ 要求可以计算两个图形的面积和周长。

​ 文件组成
​ Point.h:Point的结构体定义

#ifndef POINT_H
#define POINT_H
struct Point
{
	int x;
	int y;
};
#endif // !POINT_H

​ Circle.h:Circle的结构体定义,以及和Circle相关的函数原型。

#include "Point.h"
#ifndef CIRCLE_H
#define CIRCLE_H
struct Circle
{
	Point center;
	double radius;
};

// 函数声明
double area(Circle c);
double perimeter(Circle c);
#endif // !CIRCLE_H

​ Circle.cpp:与Circle相关的函数定义

#include "Circle.h"
double area(Circle c)
{
	return c.radius * c.radius * 3.14;
}
double perimeter(Circle c)
{
	return 2 * 3.14 * c.radius;
}

​ Rectangle.h:Rectangle的结构体定义,以及和Circle相关的函数原型。

#include "Point.h"
#ifndef RECTANGLE_H
#define RECTANGLE_H
struct Rectangle
{
	Point center;
	double length;
	double width;
};

double area(Rectangle r);
double perimeter(Rectangle r);
#endif // !RECTANGLE_H


​ Rectangle.cpp:与Rectangle相关的函数定义

#include "Rectangle.h"
double area(Rectangle r)
{
	return r.length * r.width;
}
double perimeter(Rectangle r)
{
	return 2 * (r.length + r.width);
}

​ main.cpp:主函数所在的文件

#include <iostream>
#include "Rectangle.h"
#include "Circle.h"
using namespace std;
int main()
{
	// 创建一个圆的结构体
	Circle c = { {10,20}, 100 };
	cout << "圆的面积是:" << area(c) << endl;
	cout << "圆的周长是:" << perimeter(c) << endl;

	// 创建一个矩形的结构体
	Rectangle r = { {10,20}, 100, 50 };
	cout << "矩形的面积是:" << area(r) << endl;
	cout << "矩形的周长是:" << perimeter(r) << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值