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;
}
26万+

被折叠的 条评论
为什么被折叠?



