C++
一、C++简介
1、C++语法特性?
C语言是一种面向过程的语言,任何一个大事件都可以拆分为多个小事件。
C++是一种面向对象的语言,任何一个事件都是某一个对象上的行为/属性。
2、C++语法。
C++是一种全新语法,除了继承了C语言的语法之外,还拓展关于数据类型、继承、多态等新语法。
3、C++函数接口。
C语言即使是相同的功能,也可以写出多个接口。
C++语法提供了标准模板库(STL),它里面提供了一些通用的接口,全世界的人都使用同一个接口。
二、书写第一个C++程序。
1、创建一个C++工程文件。
C++工程文件格式:xxx.cpp
2、编辑代码。
1)C++兼容C语言,也是从main函数开始执行,从main函数结束。
2)如果要使用C++语法,那么就必须在文件开头包含标准头文件以及对应标准的命名空间。
#include
using namespace std; -> 标准命名空间(C++中,有很多工具都是放在这个命名空间中,如果想在C++代码中直接使用这些工具,那么就必须使用标准命名空间)
(如果不使用命名空间,那么使用工具时,就必须在工具前面加上作用域符号)
3)C++中使用cout这个工具来输出数据。
4)endl相当于是\n。
#include <iostream>
using namespace std;
int main(int argc,char *argv[])
{
cout << "helloworld" << endl; //先输出helloworld,然后再换行。
return 0;
}
3、编译代码。
C语言: gcc编译器 gcc my_first.c -o my_first
C++: g++编译器 g++ my_first.cpp -o my_first
4、执行代码。
gec@ubuntu:/mnt/hgfs/GZ2119/07 C++/01/code$ ./my_first
helloworld
三、变量。
1、变量的作用?
给一段指定的内存空间起名字,方便操作这段内存。
2、如何在C++程序中输出变量的值?
#include <iostream>
using namespace std;
int main(int argc,char *argv[])
{
cout << "helloworld" << endl; //先输出helloworld,然后再换行。
int a = 10;
cout << "a = " << a << endl;
return 0;
}
四、常量。
1、常量的作用?
用于记录程序中不可修改的数据。
2、C++定义常量方法有两种:
1)宏常量。
#include <iostream>
using namespace std;
#define DAY 7
int main(int argc,char *argv[])
{
DAY = 8;
cout << "一个星期有:" << DAY << "天" << endl;
return 0;
}
2)const修饰的变量。
#include <iostream>
using namespace std;
int main()
{
const int month = 12; //变量
//month = 13;
cout << "一年有:" << month << "月" << endl;
return 0;
}
五、字符串。
1、字符串作用?
可以表示一串字符。
2、在C++中有两种风格来表示字符串。
C风格字符串:
语法: char 数组名[] = "字符串值"
C++风格字符串:
语法: string 字符串名 = "字符串值"
#include <iostream>
using namespace std;
int main()
{
//1. C风格字符串
char str[] = "helloworld";
cout << str << endl;
//2. C++风格字符串
string str1 = "appletree";
cout << str1 << endl;
return 0;
}
六、转义符号。
常用转义符号:
'\n' -> 换行
'\t' -> 水平制表,跳到下一个Tab键的位置
#include <iostream>
using namespace std;
int main()
{
//1. 换行符
cout << "helloworld\n";
//2. 水平制表
cout << "aaa\thelloworld" << endl;
cout << "a\thelloworld" << endl;
cout << "aaaaa\thelloworld" << endl;
return 0;
}
七、数据的输入。
1、作用?
从键盘获取一些数据。
2、关键词。
cin
3、语法。
cin >> 变量
#include <iostream>
using namespace std;
//语法:
//cin >> 变量
int main()
{
/*
//1. 整型
int a = 0;
cout << "请输入一个整型数据:" << endl;
cin >> a;
cout << "a = " << a << endl;
//2. 浮点型
double d = 0;
cout << "请输入一个浮点型数据" << endl;
cin >> d;
cout << "d = " << d << endl;
//3. 字符串
string s = "helloworld";
cout << "请输入一个字符串" << endl;
cin >> s;
cout << "s = " << s << endl;
*/
int a;
char b;
cin >> a;
cin >> b;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}
八、递增递减运算符。
1、作用:变量自身+1/-1。
2、符号:++/--
#include <iostream>
using namespace std;
int main()
{
//1. 前置递增。
int a = 10;
++a;
cout << "a = " << a << endl; //11
//2. 后置递增。
int b = 20;
b++;
cout << "b = " << b << endl; //21
//3. 前置递增与后置递增有什么区别?
//前置递增:先让变量+1,然后再进行表达式运算。
int a2 = 10;
int b2 = ++a2 * 10;
cout << "a2 = " << a2 << endl; //11
cout << "b2 = " << b2 << endl; //110
//后置递增:先进行表达式运算,再让变量+1。
int a3 = 10;
int b3 = a3++ * 10;
cout << "a3 = " << a3 << endl; //11
cout << "b3 = " << b3 << endl; //100
//4. 连续递增。
int a4 = 10;
++(++a4);
cout << "a4 = " << a4 << endl; //12
int a5 = 10;
(a5++)++; //在C++中,不支持连续的后置递增
cout << "a5 = " << a5 << endl;
return 0;
}
九、比较运算符。
== 相等于 != 不等于
< 小于 > 大于
<= 小于或者等于 >= 大于或者等于
#include <iostream>
using namespace std;
int main()
{
/*
int a = 10;
int b = 20;
cout << (a==b) << endl;
cout << (a!=b) << endl;
cout << (a<b) << endl;
cout << (a>b) << endl;
cout << (a<=b) << endl;
cout << (a>=b) << endl;
*/
string s1 = "helloworld";
string s2 = "helloappletree";
cout << (s1==s2) << endl;
cout << (s1!=s2) << endl;
cout << (s1>s2) << endl;
cout << (s1<s2) << endl;
cout << (s1>=s2) << endl;
cout << (s1<=s2) << endl;
return 0;
}
结论:
字符串比较大小:按照ascii码的大小来一一对比。
十、逻辑运算符。
1、作用:
根据表达式真假,返回真值或者假值。
2、符号。
! -> 非 !a 如果a为真,结果为假,如果a为假,则结果为真。
&& -> 与 a&&b 如果a与b都为真,结果就为真,否则为假。
|| -> 或 a||b 如果a与b有一个为真,则结果为真,二者都为假时,则结果为假。
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = 10;
int c = 0;
int d = 0;
cout << !a << endl; //0
cout << !!a << endl; //1
cout << (a&&b) << endl; //1
cout << (a||b) << endl; //1
cout << (a&&c) << endl; //0
cout << (a||c) << endl; //1
cout << (c&&d) << endl; //0
cout << (c||d) << endl; //0
return 0;
}
十一、内存分区模型。
1、在C++程序执行时,将内存大方向可以划分为4个区域。
1)代码区:存放函数的二进制代码,由操作系统来进行管理。
2)全局区:存放着全局变量、静态变量、以及常量。
可以理解为: rodata区、bss段、data段统一划分到全局区。
3)堆区: 由工程师手动分配与释放,若不释放,程序结束时由操作系统来回收。
4)栈区: 由编译器自动分配与释放,存放的是函数形式参数,局部变量。
2、内存四区意义?
不同区域存放不同的数据,赋予不同的生命周期,给我们更大的灵活编程。
十二、程序运行前。
在程序编译后,生成一个可执行程序,未执行这个程序之前分为两个区域:
1、代码区:
存放CPU执行的机器指令 -> 其实就是指0101这种数据。
代码区是共享的,共享的目的是对于频繁被执行的代码,只需要在内存中有一份代码即可。
无论执行了多少次这段代码,都是使用同一个代码。
代码区是只读的,使其只读的原因是防止程序意外地修改它的指令。
2、全局区:
全局变量与静态变量存放在此。
全局区还包含了常量区、字符串常量、其他常量(const修改的变量)在存放在此。
该区域的数据在程序结束之后由操作系统来释放。
#include <iostream>
using namespace std;
//2. 创建全局变量。
int g_a = 10;
int g_b = 20;
//4.2 const修饰的全局变量 -> 全局常量
const int c_g_a = 10;
const int c_g_b = 20;
int main()
{
//1. 创建局部变量。
int a = 10;
int b = 20;
cout << "&a = " << &a << endl;
cout << "&b = " << &b << endl; //局部变量: 栈区
cout << "&g_a = " << &g_a << endl;
cout << "&g_b = " << &g_b << endl; //全局变量: 全局区
//3. 创建静态变量。
static int s_a = 10;
static int s_b = 20;
cout << "&s_a = " << &s_a << endl;
cout << "&s_b = " << &s_b << endl; //静态变量: 全局区
//4. 常量区
//1>. 字符串常量。
cout << "string addr = " << &"helloworld" << endl; //字符串常量: 全局区
//2>. const修饰变量。
//const修饰的全局变量 -> 全局常量
cout << "&c_g_a = " << &c_g_a << endl;
cout << "&c_g_b = " << &c_g_b << endl; //全局常量: 全局区
//const修饰的局部变量 -> 局部常量
const int c_l_a = 10;
const int c_l_b = 20;
cout << "&c_l_a = " << &c_l_a << endl;
cout << "&c_l_b = " << &c_l_b << endl; //局部常量: 栈区
return 0;
}
运行结果:
gec@ubuntu:/mnt/hgfs/GZ2119/07 C++/01/code$ ./space
&a = 0x7ffe3f008ff8
&b = 0x7ffe3f008ffc
&g_a = 0x601070
&g_b = 0x601074
&s_a = 0x601078
&s_b = 0x60107c
string addr = 0x400c47
&c_g_a = 0x400c04
&c_g_b = 0x400c08
&c_l_a = 0x7ffe3f009000
&c_l_b = 0x7ffe3f009004
结论:
不在全局区:
局部变量
使用const修饰的局部变量(局部常量)
在全局区:
全局变量
静态变量
常量:
字符串常量
使用const修饰的全局变量(全局常量)
十三、程序运行后。
栈区: 由编译器自动分配释放,存放函数的形式参数值,局部变量等。
注意: 不要返回局部变量的地址,栈区开辟的数据由编译器自动释放。
#include <iostream>
using namespace std;
//栈区: 形参、局部变量。
//注意: 不要返回局部变量的地址。
int *fun(int b) //b就是形式参数,存放在栈区
{
int a = 10; //a是局部变量,是存放在栈区中。 --> 开始申请a的空间
return &a;
--> 开始释放a的空间
}
int main()
{
int *p = fun(1);
cout << "p = " << p << endl; //&a 0/NULL -> 到这里,a的空间已经释放完了,所以不要再访问a的空间
-> 为了防止你再次访问,编译器就不会返回&a给你,返回NULL。
cout << "*p = " << *p << endl; //10 段错误
return 0;
}
堆区:由工程师分配和释放,若不释放,程序结束时由操作系统来回收。
在C++中主要利用new在堆区开辟空间。
#include <iostream>
using namespace std;
int *func()
{
//利用new关键词,可以将数据开辟到堆区。
int *a = new int(10); //在堆区申请一个int类型数据大小的空间,并且将10赋值给这个空间。
return a;
}
int main()
{
int *p = func();
cout << "p = " << p << endl;
cout << "*p = " << *p << endl; //10
return 0;
}
运行结果:
gec@ubuntu:/mnt/hgfs/GZ2119/07 C++/01/code$ ./new
p = 0x1d35c20
*p = 10
结论:
在函数返回时,堆区空间不会释放。
十四、new操作符。
C++中利用new操作符在堆区开辟数据。
堆区中开辟的数据,由工程师手动开辟,手动释放、释放利用操作符delete。
语法:new 数据类型
利用new创建的数据,会返回该数据对应类型的指针。
1、 堆区的基本语法示例。
#include <iostream>
using namespace std;
int *func()
{
//在堆区中创建整型数据。
int *p = new int(10);
return p;
}
int main()
{
int *p = func();
cout << "*p = " << *p << endl; //10
//堆区的数据由用户主动释放。
delete p;
p = NULL;
cout << "*p = " << *p << endl; //段错误
return 0;
}
2、在堆区利用new开辟数组。
#include <iostream>
using namespace std;
int main()
{
//创建10个整型数据在堆区。
int *arr = new int[10]; //10代表数组有10个元素。
int i;
for(i=0;i<10;i++)
{
arr[i] = i + 100; //给10个元素赋值 100~109
}
for(i=0;i<10;i++)
{
cout << arr[i] << endl;
}
//释放数组时,需要加[]才可以。
delete[] arr;
return 0;
}
十五、引用的基本使用。
1、引用作用?
给变量起别名。
2、语法。
数据类型 &别名 = 原名
#include <iostream>
using namespace std;
//引用作用:给变量起别名。
//引用语法:数据类型 &别名 = 原名
int main()
{
int a = 10;
//创建引用
int &b = a;
cout << "a = " << a << endl; //10
cout << "b = " << b << endl; //10
b = 100;
cout << "a = " << a << endl; //100
cout << "b = " << b << endl; //100
return 0;
}
十六、引用注意事项。
1、引用必须初始化。
2、引用在初始化后,不可以改变。
#include <iostream>
using namespace std;
//引用注意事项。
//1、 引用必须初始化。
//2、 引用在初始化之后,不可以改变。
int main()
{
//1. 引用必须初始化。
//int &c; //编译出错,引用必须初始化,必须要引用一块合法并且存在的空间。
//2. 引用在初始化之后,不可以改变。
int a = 10;
int b = 20;
//创建引用。
int &c = a; //一旦初始化之后,就不可以更改。(c永远都是a的别名)
c = b; //这是赋值操作
//不是让c去做b的别名
cout << "a = " << a << endl; //20
cout << "b = " << b << endl; //20
cout << "c = " << c << endl; //20
return 0;
}
十七、引用做函数参数。
作用:函数传参时,可以利用引用的技术让形参修饰实参。
优点:可以简化指针修饰实参的方法。
#include <iostream>
using namespace std;
//1. 值传递
/*
void mySwap01(int a,int b)
{
int temp = a;
a = b;
b = temp;
}
*/
//2. 地址传递
/*
void mySwap02(int *a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
*/
//3. 引用传递
void mySwap03(int &a,int &b) //别名 // int &a = a int &b = b
//形式a虽然是一个形参,但是实际上代表也是实参。
{
int temp = a; //所以这样调换,操作就是实参。
a = b;
b = temp;
}
int main()
{
int a = 10;
int b = 20;
//mySwap01(a,b); 不能交换 -> 因为交换的是形式参数的,形式参数的修改并没有影响到实参,所以实参依然是10和20。
//mySwap02(&a,&b); 能交换 -> 因为通过形参来解引用访问到实参,所以修改的是实参的值,所以可以更换。
mySwap03(a,b); 能交换 -> 因为使用引用方式来传递,实参是原名,形参是别名,所以修改形参的值,其实就是修改实参的值。
cout << "a = " << a << endl; //10 20 20
cout << "b = " << b << endl; //20 10 10
return 0;
}
十八、引用做函数返回值。
作用:引用是可以作为函数返回值存在的。
注意事项:
1、 不要返回局部变量的引用。
2、 函数的调用可以作为左值存在。
#include <iostream>
using namespace std;
//引用作为函数返回值
//1、 不要返回局部变量的引用。
//2、 函数的调用可以作为左值的存在。
//int --> 返回的是10(本体的值)
//int& --> 返回的是a (本体)
int& test01()
{
//1、不要返回局部变量的引用。
//int a = 10; //局部变量
static int a = 10;
return a; //其实就是返回a的本体。
}
int main()
{
int &ret = test01();
cout << "ret = " << ret << endl; //10
//2. 函数的调用可以作为左值的存在。
test01() = 1000; //a = 1000
cout << "ret = " << ret << endl; //1000
return 0;
}
十九、引用的本质。
本质:引用本质在C++中内存实现其实就是一个指针常量。
解析:
情况一:
int a = 10;
int b = 20;
const int *ref = &a; 等价于 int const *ref = &a;
结论:
可以再赋值给别的地址给ref,但是不可以通过ref去修改ref指向的值。
ref = &b; -> 正确
*ref = 20; -> 错误
情况二:
int a = 10;
int b = 20;
int * const ref = &a; (ref一旦赋值了&a,那么ref就永远等于&a) -> 指针常量
结论:
不可以再赋别的地址的值给ref,但是可以通过ref去修改ref指向的值。
ref = &b; -> 错误
*ref = 30; -> 正确
#include <iostream>
using namespace std;
void func(int &ref) // int &ref = &a
{
ref = 100; // *ref = 100
}
int main()
{
int a = 10;
//创建引用,ref是别名,a是原名
//系统看到这句话之后,会自动转换成 int * const ref = &a;
//ref是一个指针常量,一旦把&a的这个地址赋值给ref这个指针之后,ref就不能指向别的东西了。
//这也解析了为什么引用初始化了值之后,不能修改。
int &ref = a;
//系统看到这句话之后,发现ref是引用来的,就会自动帮我们转换成: *ref = 20;
ref = 20;
cout << "a = " << a << endl;
cout << "ref = " << ref << endl;
func(a);
cout << "a = " << a << endl; //100
cout << "ref = " << ref << endl;
return 0;
}
///////
a = 20
ref = 20
a = 100
ref = 100
二十、常量引用。
作用:常量引用主要用于修饰形参,防止误操作。
在函数形参列表中,可以使用const修饰形参,防止形参改变实参。
#include <iostream>
using namespace std;
//常量引用
//一般使用场景:修饰形式参数。
void show_value(const int &val) // const int &val = height;
{
//加了const之后,val就可以打印,但是不可以修改。
//val = 160;
cout << "val = " << val << endl;
}
int main()
{
//int &ref = 10; //错误
//引用必须引用一块合法的空间,如果这样写可以的话,意味ref=20也是成立,但是这样做,意味着10=20,就相当于是给常量赋值。
/*(1)只有一个const,如果const位于*左侧,表示指针所指数据是常量,不能通过解引用修改该数据;指针本身是变量,可以指向其他的内存单元。
(2)只有一个const,如果const位于*右侧,表示指针本身是常量,不能指向其他内存地址;指针所指的数据可以通过解引用修改。*/
//const int &ref = 10; //正确 -> 只看得到别名,看不到原名
//系统看到这句话之后,会自动帮我们转换成以下的几句话:
/*
int temp = 10; -> 既看得到原名,也看得到别名。
const int &ref = temp;
*/
//ref = 20; //编译出错,ref是只读的。
int height = 170;
show_value(height);
return 0;
}