C到C++(Num015)
目录
一、bool类型
代码示例:
二、内联函数
代码示例:
三、引用
代码示例:
指针和引用的区别
常量引用(等价于第二个) 代码示例
代码示例:
五、函数缺省参数
代码示例:
六、内存四区
代码示例:
七、动态内存开辟
C语言动态内存开辟:
代码示例(C):
C++动态内存开辟:
代码示例(C++):
八、结构体指针
代码示例:
九、多级指针
代码示例:
指针的使用与赋值:
指针类型的内存开辟:
函数中的使用及引用操作:
十、命名空间
命名空间访问:
代码示例1:
头文件:
源文件:
代码示例2:
头文件:
同名.cpp文件:
源文件:
十一、cin和cout
代码示例:
十二、string类型的使用:
代码示例:
十三、c++11标准:
隐式转换、自动推导、给变量取别名代码示例:
for(auto) 代码示例:
给类型取别名代码示例:
一、bool类型
bool类型常用于判断条件、控制流程和逻辑运算等方面。在条件判断语句(如if语句、while循环等)中,可以根据bool类型的值决定执行不同的代码路径
bool是一种数据类型
取值为true(真)或false(假)
定义:bool isFind=false;
内存大小占1字节
遵循非0为真的原则
代码示例:
#include<stdio.h>int main()
{bool a = false;// 0/1if (a){printf("a的值为真");}else {printf("a的值为假");}return 0;
}
二、内联函数
C++内联函数是一种优化技术,用于减少函数调用的开销。当函数被声明为内联函数时,编译器会将函数的定义插入到每个调用点处,而不是像普通函数调用那样跳转到函数体执行。
这样可以减少函数调用的开销,提高程序的执行效率。
定义:在函数的定义前面加一个inline关键字
inline int getNum(){
return 1;}
代码示例:
#include<stdio.h>inline int sum(int x, int y)
{return x + y;
}int main()
{printf("%d", sum(20, 30));return 0;
}
###如果代码太多那么该函数还是一个普通的函数
使用:
1、函数体代码过长,或者函数体中有循环、递归,不建议使用内联
2、函数体是简单的赋值语句或者返回语句,而且使用频率高,建议使用内联
三、引用
在C++中,引用是一种别名,用于给已存在的对象起一个新的名称。通过引用,可以使用一个对象(或变量)的不同名称进行操作,而无需复制数据本身。
定义一个引用:
int num=10;
int &ref=num; //定义方式
ref=20;//这句可以修改num的值为20
理解:认为ref可以当作num讲行使用,ref是num的别名(也就是引用),对引用的操作
###define是给类型取别名,&是给内存起别名
代码示例:
#include<stdio.h>int main()
{int a = 10;printf("%d\n", a);int& ref = a;ref = 20;printf("%d\n", a);return 0;
}
#include<stdio.h>struct node
{int x;int y;
};int main()
{node n = { 10,20 };printf("%d %d\n", n.x, n.y);node& abc = n;abc.x = 30;abc.y = 40;printf("%d %d\n", n.x, n.y);return 0;
}
指针和引用的区别
在效率上没有太大的区别
引用是别名,不会被分配空间<-------->指针是实体,会被分配空间
引用在定义时必须初始化,而且不是被改变,指针定义时可以不用初始化,也可以改变值
有多级指针<--------->没有多级引用
引用是直接访问<--------->指针是间接访问
#include<stdio.h>
int main()
{int a = 2, b = 3;int& x = a;int* y = &a;return 0;}
常量引用(等价于第二个) 代码示例
const int& z = 1;
int temp = 1;
const int& z = temp;
注意事项:
引用是别名,所以定义引用的时候必需要初始化
在使用引用时候,要注意引用的变量是否存还存在
对引用的操作和对引用对应的变量的操作完全等价
& 在引用这里不是取地址,而是起到标志的作用
引用的类型必须和其所对应的变量的类型相同
引用不是定义新的变量或对象,因此不会为引用开辟新的空间内存
四、函数重载:
函数重载(Function Overloading)是指在同一个作用域内,可以定义多个同名但参数列表不同的函数。
实现函数重载的条件:
函数名必须一致
函数的参数不同,参数不同分为两个情况,
(1)参数个数不同
(2)参数列表对应位置类型不同
函数重载定义和使用:
void fun(int x, int y){}
void fun(int x){}
void fun(double x){}
以上函数构成重载,如果要调用只需要传对应的参数即可
fun(1,2);
fun(1);
fun(1.2);
如果加入int fun()函数的定义,并不能构成重载,函数重载不会按返回值不同来区分函数
代码示例:
#include<stdio.h>
void fun(int x, int y) { printf("这是两个参数的函数\n"); };void fun(int x) { printf("这是一个参数int的函数\n"); };void fun(float x) { printf("这是一个参数double的函数\n"); };int main()
{fun(1, 2);fun(1);fun((int)10.0); //明确调用哪一个int和float都能接收单浮点参数return 0;
}
#include<stdio.h>struct hero1
{int hp;int atk;
};struct monster1
{int hp;int def;int atk;
};struct monster2
{int hp;int def;int atk;
};void atk(hero1& h1, monster1& m1)
{}
void atk(hero1& h1, monster2& m1)
{}
五、函数缺省参数
函数的参数缺省(Default Arguments)是指在函数定义时给函数的参数提供默认值。这意味着在函数调用时,如果没有为该参数传递值,将使用默认值作为参数的值
函数参数的缺省定义:
void fun(int a.int b=2)()
函数调用:
fun(1);
fun(1,3);
这个函数的形参有缺省的值了,那么就可以不用给它传参了,不给它传参,那么形参用的值就是这里默认的值,如果是传参了,就是用的传参了的值
代码示例:
#include<stdio.h>void fun(int a, int b, int c = 20)
{printf("%d %d %d\n", a, b, c);
}int main()
{fun(30, 40);fun(30, 40,60);return 0;
}
函数参数缺省的注意事项:
缺省参数只能由后往前依次缺省
缺省值必须是常量
函数如果只有定义,需在定义的参数列表中指明缺省参数。如果函数有声明和定义,则缺省参数只需在声明中指明即可
六、内存四区
在系统为程序开辟内存时,为了方便分配和管理内存,将程序的内存区域划分为4块
栈区:存放函数的形参、局部变量等。由编译器白动分配和释放,当函数执行完毕时自动释放
堆区:用于动态内存的申请与释放,一般由程序员手动分配和释放若程序员不释放,则程序结束时由操作系统回收。
全局静态常量区(全局区):存放常量(一般是字符串常量和其他常量)、全局变量和静态变量,在程序结束后由操作系统释放。
代码区:存放可执行的代码
代码示例:
#include<stdio.h>int main()
{//c语言中写这个不会报错,但c++会报错,因为它是一个常量字符串//char* p = "que";const char* p = "que";return 0;
}
七、动态内存开辟
动态内存开辟让用户可以根据自己的需要,向系统申请所需大小的内存空间:通过指针进行管理
在什么情况下需要动态内存开辟?
需要的内存数量不确定时
对象的生命周期不确定时
需要大量内存时,堆区内存比栈区内存要大很多
有效的利用内存时,也就是内存大小需要改变
C语言动态内存开辟:
需要包含头文件 #include <stdlib.h>
1、void* malloc (size_t size);
申请指定size个字节内存
2、void* calloc(size_t num, size_t size);
申请指定size个字节内存并初始化为num
3、void* realloc(void* ptr. size_t size);
重新给指针ptr重新分配size个字节内存
4、 void free(void* ptr);
释放指针ptr所指向的堆区内存
代码示例(C):
#include<stdio.h>
#include<stdlib.h>int main()
{int* p = (int*)malloc(sizeof(int)*25);//申请25个int类型的内存for (int i = 0; i < 25; i++){*(p + i) = i + 1;}//p = (int*)calloc(10, sizeof(int));//申请10个大小为4个字节的内存realloc(p, sizeof(int) * 10);for (int i = 0; i < 25; i++){printf("%d\n", p[i]);//p[] = *(p+i)}//p++;//不可以进行指针自增操作,后面释放内存时会造成内存泄漏free(p);//主动释放内存return 0;
}
C++动态内存开辟:
1、申请内存使用new关键字
申请单个内存:int*p=new int;
申请单个内存并初始化:int*p=new int(10);
申请多个连续的内存:int*p=new int [10];
2、释放内存使用delete关键字
释放单个内存:delete p;
释放多个连续的内存:delete []p;
代码示例(C++):
#include<stdio.h>int main()
{//1.//int* p = new int;//*p = 10;//2.//与上面的两条语句等价//int* p = new int(20);/*printf("%d\n", *p);*///delete p;//3.int* p = new int[10];for (int i = 0; i < 10; i++){*(p + i) = i + 1;}int* temp = new int[5];//裁取前五个值for (int i = 0; i < 5; i++){temp[i] = p[i];}delete[]p;for (int i = 0; i < 5; i++){printf("%d\n", temp[i]);}delete []temp;return 0;
}
使用动态内存的注意事项:
没有给指针分配内存,就对该指针解引用赋值//对空指针的解引用
给指针分配内存成功,但是没有初始化就使用
内存分配成功,也初始化了但是操作越界
忘记释放内存,造成内存泄漏
释放内存之后,继续使用
八、结构体指针
所谓的结构体指针就是指向结构体变量的指针
假设有结构体类型为student
student stu; //定义结构体变量
student *p1 &stu; //定义结构体指针指向结构体变量
student*p2=new student; //定义堆区的结构体变量通过p2访问
结构体指针访问成员通过->进行访问
p1->成员;
p2->成员;
*(p1).成员;//先解引用得到地址上面的对象,然后.成员访问
代码示例:
#include<stdio.h>
#include<stdlib.h>struct node
{int x;int y;
};void fun(node* x)
{x->x = 20;x->y = 20;
}int mian()
{node* p = new node;p->x = 20;p->y = 10;printf("%d,%d \n", p->x, p->y);//开辟的内存一定要及时释放出去delete p;p = NULL;//node n = { 1,2 };//node* p = &n;//printf("%d,%d \n", p->x, p->y);//(*p).x亦可return 0;
}
九、多级指针
一个用来保存指针变量地址的指针
定义:
int *pl=new int(10);
int **p2=&p1;
*p2=new int(20); //相当于 p1=new int(20);
printf("%d",*p1);//输出结果为20
代码示例:
指针的使用与赋值:
#include<stdio.h>int main()
{int x = 10;int* p1 = &x;//一级指针管理变量的地址int** p2 = &p1;//二级指针管理一级指针的地址int*** p3 = &p2;***p3 = 20;printf("%d", x);return 0;
}
指针类型的内存开辟:
#include<stdio.h>int main()
{//相当于写了一个二维数组//开辟一块数据类型为int*类型的大小为10的内存int** p = new int* [10];//解引用指针p的指向一块数据类型为int大小为10的内存p[0] = new int[10];p[5] = new int[10];delete[]p;char* pp = new char[100];//强转完再解引用*(int*)(pp + 20) = 10;printf("%d\n", pp[20]);//这里是char类型故后移二十位就可以引用int* pp2 = (int*)pp;printf("%d\n", pp2[5]);//这里是int类型故后移五位就可以引用delete[]pp;return 0;
}
函数中的使用及引用操作:
#include<stdio.h>//1.
//void init(int* p)
//{
// p = new int(10);//这行语句是给形参的赋值与实参没有任何关系所以会报错
//}//2.
void init(int** p)//形参是实参的拷贝
{*p = new int(10);//由此对 主函数中*p的地址 进行解引用获取到*p存放的地址,开辟一个int类型的内存赋值为10//这里对二级指针解引用完本质上获取的是一个一级指针
}//3.
void init(int*& p)//对实参进行引用
{p = new int(10);//这里就可以直接使用指针p了
}int main()
{int* p = NULL;//1.//init(p);//printf("%d", *p);//2.init(&p);//将*p的地址传过去printf("%d", *p);//3.init(p);//传递*p的printf("%d", *p);return 0;
}
十、命名空间
解决同名实体的冲突问题,提供代码的模块化和组织化,并提高代码的可读性和可维护性
namespace 命名空间标识符
{
...命名空间成员
}
命名空间访问:
通过作用域运算符(::)访问命名空间中的成员
1、 using 声明:using 命名空间名称::空间成员名称
放开一个成员的可见性,这一个成员可以在空间外可见(建议使用这种,比较容易避免出现命名污染)
using std::string;
2、 using 指示: using namespace 命名空间名
放开该命名空间的所有权限(所有成员都在空间外可见),适用于该空间的大部分成员都需要经常被使用
using namespace std;
3、命名空间名称::空间成员名称直接访问空间下的某一个成员
std::string;
代码示例1:
头文件:
#pragma once
#include<stdio.h>
//使用这种方式与外部隔离开来,要想使用这个空间中的内容一定要打开该空间
namespace A
{int age = 18;void fun(){printf("%d", age);}
}
源文件:
#include<stdio.h>
#include"tool.h"//声明头文件//1.
//using namespace A;//打开了空间A,使用该空间中的成员需要被经常使用的情况//2.建议使用这种
using A::age;//使用谁就打开谁int main()
{age = 20;//3.最为常用A::fun();//直接调用return 0;
}
tips:头文件中一般不定义变量和函数,对函数只做声明,创建同名.cpp文件,在头文件中声明函数,飘绿色波浪线,选中使用在同名.cpp文件中快速重构即可快速生成。 (快捷操作ALT+ENTER D)
代码示例2:
头文件:
#pragma once
#include<stdio.h>
//有了同名.cpp文件不可以在头文件中定义变量,会报错
namespace A
{void fun();
}namespace B
{void fun();
}
同名.cpp文件:
#include "tool.h"void A::fun()
{
}void B::fun()
{
}
源文件:
#include<stdio.h>
#include"tool.h"//声明头文件using namespace A;
using namespace B;int main()
{A::fun();//当两个命名空间中都有同名函数需要标明使用的是哪一个return 0;
}
定义命名空间注意事项:
命名空间标识符必须满足标识符的命名规则和命名规范,习惯名字唯一,通常以开发团队的名字(项目名)来命名
命名空间可以在全局,也可以在局部(命名空间接受嵌套定义),但不能在函数内和类中定义
命名空间的花括号是作用域
注意命名污染,尽量规避同名的出现,如果两个命名空间名同名,那么就会合并两个命名空间
十一、cin和cout
C++中用来做输入输出的操作,功能和C语言的scanf和printf一样(scanf和printf为格式化输入输出,要比cin和cout更快)
使用:
int x, y;
cin>>x>>y;//从键盘输入
cout<<x<<"\n"<<y<<endl;
代码示例:
#include<stdio.h>
#include<iostream>using std::cin;
using std::cout;
using std::endl;int main()
{int x, y;//输入流 输入cin >> x >> y;//输出流 输出cout << x << " " << y << endl;return 0;
}
十二、string类型的使用:
C++中用来存储字符串的类型
使用string类型存储操作字符串比数组更为方便:
string具有动态大小
操作简单,比如比较两个字符串是否相等可以用==比较
有很多方便的字符串处理函数,比如获取字符串长度,查找字串等等
代码示例:
#include<cstdio>
#include<iostream>
using namespace std;int main()
{string str1 = "1234567";string str2 = "1234567";str1.insert(7,"qwer");str2.append("qwer");//访问指定下标内容cout << str2.at(2) << endl;cout << str2[2] << endl;//转换为c可以识别的字符数组cout << str2.c_str() << endl;if (str1 == str2){cout << "str1等于str2"<<endl;}else {cout << "str1不等于str2" << endl;}return 0;
}
十三、c++11标准:
用来规范C++编程语言的语法、语义和行为
1、定义变量初始化
int x ={(int)1.23}; //不允许值的类型和变量的类型不一样
2、空指针
int *p = nullptr; //nullptr是关键字
3、自动类型
auto x=10; //根据值推导x的类型,x的类型为int
4、decltype
int a=1;
decltype(a)b: //理解为使用a的类型定义了b
decltype((a))m=a; //再加一个圆括号,给a定义了一别名m
隐式转换、自动推导、给变量取别名代码示例:
#include<cstdio>
#include<iostream>
using namespace std;int main()
{int x = 1.23;//隐式转换int a = {(int)1.23};//c++11标准int* p = nullptr;//c++11标准auto y = 10;//根据返回值自动推导出数据类型decltype(a)b;//使用a的类型定义了变量bdecltype((a))m=a;//给1a定义了一个别名return 0;
}
for(auto) 代码示例:
#include<cstdio>
#include<iostream>int main() {int xy[10] = { 0,1,2,3,4,5,6,7,8,8 };for(auto i:xy ){std::cout << xy[i] << " ";}return 0;
}
###不能够遍历指针
给类型取别名代码示例:
#include<cstdio>
#include<iostream>int main()
{using utf32 = unsigned int;return 0;
}