
本文共 23895 字,大约阅读时间需要 79 分钟。
从今天起开始C++的学习,为以后学习QT、OpenCV铺路。
本篇是C++教程中C部分的总集,为本专栏里所有 1.x部分的集合,嫌一篇篇看麻烦的直接看本篇好了。
开发环境搭建:
推荐教程视频:
已投币三连,非常好的视频教程,感谢up主的奉献。
一、代码的注释
代码注释常用于标注代码功能、记录作者和版本修改信息,方便阅读查看。
// 单行注释/* ... ... 多行注释 ... ... */#includeusing namespace std;/* 多行注释 main 主函数 */int main() { cout << "Hello World!!" << endl; // 单行注释,打印输出Hello world!! system("pause"); return 0;}
cout:c out,打印输出,相当于 printf。
cin:c in,检测输入,相当于 scanf。
endl:end line,换行结束,相当于键盘敲回车。
system("pause");:让程序暂停,按任意键继续。
二、变量
变量,字面意思,可以被改变的数据。而实际是给计算机的一段内存空间起名,方便操作这段内存的数据。
变量如果需要被使用,需要先声明变量。声明变量的格式:
数据类型 变量名 = 初始值;
#includeusing namespace std;int main() { int i = 100; cout << "Hello World!!" << endl; cout << "i = " << i << endl; system("pause"); return 0;}
三、常量
可以被修改的数据叫做变量,不可被修改的数据叫常量。
C++定义常量有两种方法:
(1)#define宏常量:#define 常量名 常量值
通常在代码文件的上方声明。
#define 常量名 常量值#define Year 2020#define Name "XiaoMing"
(2)const修饰变量:const 数据类型 常量名 = 常量值
const 数据类型 常量名 = 常量值const int year = 2020;
常量被修改,编译器会报错。
四、关键字
是C++中预先保留的单词(标识符)。
注意:给变量或者常量起名称时,不要和关键字重复,会有语法歧义。
五、标识符(变量、常量)命名规则
(1)标识符不能是关键字
(2)标识符只能由 数字、字母、下划线 组成。
(3)标识符的第一个字符必须是 字母或者下划线。
(4)标识符中字母区分大小写
可以是 inta,但不能是 int。
year2020、Status、_a、Student_66 这些都符合命名规则,但 2class、618_Day 这样以 数字开头的不行。
Age 和 age 代表的变量并不是同一个,是两个独立且互不相关的变量。
标识符命名尽量简介直观,方便自己和他人阅读。
六、数据类型
(1)整形
整型数据类型的区别,主要是占用空间的不同,从而导致取值范围不同,有大有小。
int最为常用。
数据类型 | 占用空间 | 取值范围 |
short(短整型) | 2个字节(Byte) | (-2^15 ~ 2^15-1) |
int(整形) | 四个字节 | (-2^31 ~ 2^31-1) |
long(长整型) | windows为4个字节、32位linux为4个字节、64位linux为8个字节 | (-2^31 ~ 2^31-1) |
long long(长长整型) | 8个字节 | (-2^63 ~ 2^63-1) |
表示小数。区别在于表示的有效数字范围不同。
数据类型 | 占用空间 | 有效数字范围 |
float(单精度浮点) | 4字节 | 7位有效数字 |
double(双精度浮点) | 8字节 | 15~16位有效数字 |
注意:有效数字范围,并不是指小数点后的数,而是整个浮点的数的数量。例如 3.14,有效数字为3。
默认的 cout << 输出浮点类型,会显示6位有效数字。
(3)字符型
显示单个字符。c/c++中,字符型变量只占用一个字节。
字符型变量不是将字符放入内存中,而是将对应的ASCII编码放入内存。
char ch = 'a';
ASCII 编码对照表:
(4)转义字符
表示一些不能显示出来的ASCII字符。
对照表:
(5)字符串类型
表示一串字符。
C风格字符串:
char str1[] = "123abc";
C++风格字符串:
string str1 = "123abc"; // 需要包含头文件 #include
(6)布尔类型
代表真或假的值。
bool的值只有两个:
true - 真,1
false - 假,0
(7)数据的输入
用于从键盘获取数据。
语法:cin >> 变量
(8)sizeof 统计内存大小
sizeof关键字,可以统计数据类型所占内存大小。
sizeof(数据类型/变量)
#includeusing namespace std;int main() { cout << "short\t\t占用空间:" << sizeof(short) << endl; cout << "int\t\t占用空间:" << sizeof(int) << endl; cout << "long\t\t占用空间:" << sizeof(long) << endl; cout << "long long\t占用空间:" << sizeof(long long) << endl; cout << "float\t\t占用空间:" << sizeof(float) << endl; cout << "double\t\t占用空间:" << sizeof(double) << endl; cout << "char\t\t占用空间:" << sizeof(char) << endl; cout << "bool\t\t占用空间:" << sizeof(bool) << endl; system("pause"); return 0;}---------------------------------------------------------------------------short 占用空间:2int 占用空间:4long 占用空间:4long long 占用空间:8float 占用空间:4double 占用空间:8char 占用空间:1bool 占用空间:1请按任意键继续. . .
sizeof 和 strlen 区别:
七、运算符
运算符用于执行代码的运算。
运算符分类:
运算符类型 | 作用 |
算术运算符 | 处理四则运算 |
赋值运算符 | 将表达式的值赋给变量 |
比较运算符 | 表达式的比较,并返回一个真值或假值 |
逻辑运算符 | 根据表达式的值返回真值或假值 |
(1)算术运算符
处理四则运算。
运算符 | 术语 | 示例 | 结果 |
+ | 正号 | +5 | 5 |
- | 负号 | -5 | 5 |
+ | 加 | 2 + 3 | 5 |
- | 减 | 5 - 3 | 2 |
* | 乘 | 2 * 3 | 6 |
/ | 除 | 6 / 3 | 2 |
% | 取模(取余) | 10 % 3 | 1 |
++ | 前置递增 | a=2; b=++a; | a = 3; b = 3; |
-- | 前置递减 | a=2; b=--a; | a = 1; b = 1; |
++ | 后置递增 | a=2; b=a++; | a = 3; b = 2; |
-- | 后置递减 | a=2; b=a--; | a = 1; b = 2; |
(2)赋值运算符
将表达式的值赋给变量。
运算符 | 术语 | 示例 | 结果 |
= | 赋值(等于) | a=2; | a=2; |
+= | 加等于 | a=2; a+=2; | a=4; |
-= | 减等于 | a=2; a-=2; | a=0; |
*= | 乘等于 | a=2; a*=3; | a=6; |
/= | 除等于 | a=6; a/=3; | a=2; |
%= | 模等于 | a=10; a%=3; | a=1; |
(3)比较运算符
表达式的比较,并返回一个真值或假值。
运算符 | 术语 | 示例 | 结果 |
== | 相等于 | 5 == 2 | 0 |
!= | 不等于 | 5 != 2 | 1 |
< | 小于 | 5 < 2 | 0 |
> | 大于 | 5 > 2 | 1 |
<= | 小于等于 | 5 <= 2 | 0 |
>= | 大于等于 | 5 >= 2 | 1 |
注意:= 和 == 的使用区别。
(4)逻辑运算符
根据表达式的值返回真值或假值
运算符 | 术语 | 示例 | 结果 |
! | 非 | !a | 如果 a为假,则 !a为真。反之则反 |
&& | 逻辑与 | a && b | a,b全为1时, a && b = 1。a,b任意一个为0, a && b = 0。 |
|| | 逻辑或 | a || b | a,b全为0时, a || b = 0。a,b任意一个为1, a || b = 1。 |
注意:& 和 &&、| 和 || 的使用区别。与 与逻辑与,或 与 逻辑或。
八、程序流程结构
c/c++支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构。
顺序结构:程序按顺序执行,不发生跳转。
选择结构:依据条件是否满足,有选择的执行相应功能。
循环结构:依据条件是否满足,循环多次执行某段代码。
(1)选择结构
1. 使用 if语句,语法为:
if (条件) { /* 满足条件后,可执行括号中内容 */ // ...}
if (条件1) { /* 满足条件1后,执行本括号中程序 */ // ... /* 执行完程序后,结束整个if结构 */}else if (条件2) { /* 如果条件1不满足,而条件2满足,执行本括号中程序 */ // ... /* 执行完程序后,结束整个if结构 */}else if (条件3) { /* 如果条件1、条件2均不满足,而条件3满足,执行本括号中程序 */ // ... /* 执行完程序后,结束整个if结构 */}.........
if (条件1) { /* 满足条件1后,执行本括号中程序 */ // ... /* 执行完程序后,结束整个if结构 */}else if (条件2) { /* 如果条件1不满足,而条件2满足,执行本括号中程序 */ // ... /* 执行完程序后,结束整个if结构 */}else if (条件3) { /* 如果条件1、条件2均不满足,而条件3满足,执行本括号中程序 */ // ... /* 执行完程序后,结束整个if结构 */}.........else { /* 如果条件1、条件2、条件3...均不满足,则执行本括号中程序 */ // ... /* 执行完程序后,结束整个if结构 */}
int main() { int a = 0; if (a < 0) { cout << "a小于0" << endl; } else if (a > 0) { cout << "a大于0" << endl; } else { cout << "a等于0" << endl; } system("pause"); return 0;}---------------------------------------------------a等于0请按任意键继续. . .
if支持多重嵌套。
2. 三目运算符
三目运算符可实现简单的判断。语法:
表达式1 ? 表达式2 : 表达式3// 如果表达式1为真,则执行表达式2,并返回表达式2的结果。// 如果表达式1为假,则执行表达式3,并返回表达式3的结果。
int main() { int a = 10; a > 0 ? cout << "a大于0" << endl : cout << "a小于0" << endl; system("pause"); return 0;}------------------------------------------------------------------a大于0请按任意键继续. . .
3. switch语句。执行多条件分支语句。语法:
switch (表达式) { case 结果1: 执行代码段; break; case 结果2: 执行代码段; break; case 结果3: 执行代码段; break; ... ... ... defaule: 执行代码段; break;}
int usr=0; cout << "请输入1、2、3其中一个数字" << endl; cin >> usr; switch (usr) { case 1: cout << "输入了1" << endl; break; case 2: cout << "输入了2" << endl; break; case 3: cout << "输入了3" << endl; break; default: cout << "不在规定范围内输入" << endl; break; }--------------------------------------------------------------请输入1、2、3其中一个数字3输入了3请按任意键继续. . .
注意:别少写break,少写break代码会继续向下执行。直到再次遇到break,才会结束整个switch。
(2)循环结构
1. while循环语句。语法:
while (条件) { /* 满足条件后,执行本括号中程序 */ // ... /* 执行完程序后,接着判断条件。如满足,继续循环执行本括号程序;如不满足,结束while循环 */}
2. do while循环语句。语法:
do { // 先执行一次本括号程序 // ... /* 执行完程序后,判断条件。如满足,继续循环执行本括号程序;如不满足,结束while循环 */}while (条件)
3. for循环语句。满足循环条件,执行循环语句。语法:
for (表达式1; 表达式2; 表达式3){ 循环语句}for (初始化语句; 循环条件; 自增或自减){ 循环语句}
int i, j; for (i = 0; i < 5; i++) { for (j = 0; j < 10; j++) { cout << "j "; } cout << "i" << endl; }-------------------------------------------j j j j j j j j j j ij j j j j j j j j j ij j j j j j j j j j ij j j j j j j j j j ij j j j j j j j j j i请按任意键继续. . .
(3)跳转语句
break语句:用于跳出选择结构或循环结构。
(注意:break只会跳出距离它最近的for、while这些循环语句,跟if没有关系)
作用:
出现在switch语句中,作用是终止case并跳出switch。
出现在循环语句中,作用是跳出当前的循环语句。
出现在嵌套循环语句中,跳出最近的内层循环语句。
int usr=0; cout << "请输入1、2、3其中一个数字" << endl; cin >> usr; switch (usr) { case 1: cout << "输入了1" << endl; //break; case 2: cout << "输入了2" << endl; //break; case 3: cout << "输入了3" << endl; //break; default: cout << "不在规定范围内输入" << endl; //break; }---------------------------------------------------------------请输入1、2、3其中一个数字2输入了2输入了3不在规定范围内输入请按任意键继续. . .
int i, j; for (i = 0; i < 5; i++) { for (j = 0; j < 10; j++) { if (j >= 5) break; cout << "j "; } cout << "i" << endl; }---------------------------------------------------------j j j j j ij j j j j ij j j j j ij j j j j ij j j j j i请按任意键继续. . .
int i, j; for (i = 0; i < 5; i++) { for (j = 0; j < 10; j++) { cout << "j "; } cout << "i" << endl; break; }------------------------------------------------------j j j j j j j j j j i请按任意键继续. . .
continue语句:循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环。
int i, j; for (i = 0; i < 5; i++) { for (j = 0; j < 10; j++) { if (j == 5 || j == 8) { continue; } cout << j; } cout << "i" << endl; }--------------------------------------------------------01234679i01234679i01234679i01234679i01234679i请按任意键继续. . .
goto语句:可以无条件跳转语句。
(注意:少用,goto不利于梳理代码逻辑)
cout << "执行代码段1" << endl; goto CODE_1; cout << "执行代码段2" << endl; cout << "执行代码段3" << endl; CODE_1: cout << "执行代码段4" << endl;---------------------------------------------------------执行代码段1执行代码段4请按任意键继续. . .
九、数组
数组:一个里面存放了相同类型数据元素的集合。
特点:每个数组中的元素都是相同的数据类型;数组是由连续的内存位置组成的。
注意:数组的下标是从0开始索引。
(1.1)一维数组
一维数组的三种定义方式:
数据类型 数组名[ 数组长度 ];数据类型 数组名[ 数组长度 ] = { 值1, 值2 ...};数据类型 数组名[ ] = { 值1, 值2 ...};int str1[5];int str1[5] = { -2, -1, 0, 1, 2};int str1[] = { -2, -1, 0, 1, 2};
int i=0; int str1[5]; str1[0] = -2; str1[1] = -1; str1[2] = 0; str1[3] = 1; str1[4] = 2; for (i = 0; i <5; i++) { cout << str1[i] << " "; } cout << endl;-----------------------------------------------------------2 -1 0 1 2请按任意键继续. . .
int i=0; int str1[5] = { -2, -1, 0, 1, 2 }; for (i = 0; i <5; i++) { cout << str1[i] << " "; } cout << endl;------------------------------------------------------------2 -1 0 1 2请按任意键继续. . .
int i=0; int str1[] = { -2, -1, 0, 1, 2 }; for (i = 0; i <5; i++) { cout << str1[i] << " "; } cout << endl;--------------------------------------------------------2 -1 0 1 2请按任意键继续. . .
(1.2)一维数组数组名
一维数组名称的用途:
1.可以统计整个数组在内存中的长度。
2.可以获取数组在内存中的首地址。
int i=0; int str1[5] = { -2, -1, 0, 1, 2 }; for (i = 0; i <5; i++) { cout << str1[i] << " "; } cout << endl; cout << "str1[]整个数组占用的空间:" << sizeof(str1) << endl; cout << "str1[0]元素占用的空间:" << sizeof(str1[0]) << endl; cout << "str1[]数组中元素个数:" << sizeof(str1) / sizeof(str1[0]) << endl; cout << "str1[]数组的内存首地址:" << str1 << endl; cout << "str1[0]元素的内存首地址:" << &str1[0] << endl; cout << "str1[1]元素的内存首地址:" << &str1[1] << endl;-----------------------------------------------------------------------------------------2 -1 0 1 2str1[]整个数组占用的空间:20str1[0]元素占用的空间:4str1[]数组中元素个数:5str1[]数组的内存首地址:00D8FA64str1[0]元素的内存首地址:00D8FA64str1[1]元素的内存首地址:00D8FA68请按任意键继续. . .
(1.3)一维数组常用算法
寻找最大值:
int i=0; int str1[5] = { -2, -1, 0, 1, 2 }; int start = 0; int end = sizeof(str1) / sizeof(str1[0]); int xtemp = 0; for (i = 0; i < end; i++) { if (str1[i] > str1[xtemp]) { xtemp = i; } } for (i = 0; i < 5; i++) { cout << str1[i] << " "; } cout << endl; cout << "str1[]数组中元素个数:" << end << endl; cout << "str1[]数组中第几个元素为最大值:" << xtemp + 1 << endl; cout << "最大值为:" << str1[xtemp] << endl;---------------------------------------------------------------------------2 -1 0 1 2str1[]数组中元素个数:5str1[]数组中第几个元素为最大值:5最大值为:2请按任意键继续. . .
逆置(整个数组首位互换):
int str1[5] = { -2, -1, 0, 1, 2 }; int start = 0; int end = sizeof(str1) / sizeof(str1[0]) - 1; int xtemp = 0; for (i = 0; i < 5; i++) { cout << str1[i] << " "; } cout << endl; while (start < end) { xtemp = str1[start]; str1[start] = str1[end]; str1[end] = xtemp; start++; end--; } for (i = 0; i < 5; i++) { cout << str1[i] << " "; } cout << endl;---------------------------------------------------------------2 -1 0 1 22 1 0 -1 -2请按任意键继续. . .
冒泡排序:
int i=0,j=0; int str1[5] = { 8, 2, 5, 4, 6 }; int start = 0; int end = sizeof(str1) / sizeof(str1[0]) - 1; int xtemp = 0; cout << "数组原始值:"; for (i = 0; i < 5; i++) { cout << str1[i] << " "; } cout << endl; for (i = end; i > 0; i--) { for (j = 0; j < i; j++) { if (str1[j] > str1[j + 1]) { xtemp = str1[j]; str1[j] = str1[j + 1]; str1[j + 1] = xtemp; } } } cout << "冒泡排序后:"; for (i = 0; i < 5; i++) { cout << str1[i] << " "; } cout << endl;----------------------------------------------------------------------数组原始值:8 2 5 4 6冒泡排序后:2 4 5 6 8请按任意键继续. . .
(2.1)二维数组
二维数组的四种定义方式:
数据类型 数组名[ 行数 ][ 列数 ];数据类型 数组名[ 行数 ][ 列数 ] = { { 值1, 值2 ...}, { 值11, 值12 ...}, ... };数据类型 数组名[ 行数 ][ 列数 ] = { 值1, 值2, 值3, 值4 ...};数据类型 数组名[ ][ 列数 ] = { 值1, 值2, 值3, 值4 ...};int str1[2][3];int str1[2][3] = { { -2, -1, 0}, { 1, 2, 3} };int str1[2][3] = { -2, -1, 0, 1, 2, 3};int str1[][3] = { -2, -1, 0, 1, 2, 3};
int i=0,j=0; int str1[2][3] = { { -2, -1, 0}, { 1, 2, 3} }; //int str1[2][3] = { -2, -1, 0, 1, 2, 3 }; //int str1[][3] = { -2, -1, 0, 1, 2, 3 }; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { cout << str1[i][j] << " "; } cout << endl; }-----------------------------------------------------------------2 -1 01 2 3请按任意键继续. . .
(2.2)二维数组数组名
二维数组名称的用途:
1.统计二维数组所占内存空间。
2.获取二维数组在内存中的首地址。
int i = 0,j = 0; int str1[2][3] = { { -2, -1, 0}, { 1, 2, 3} }; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { cout << str1[i][j] << " "; } cout << endl; } cout << "str1[][]二维数组占用的空间:" << sizeof(str1) << endl; cout << "str1[][]第一行占用的空间:" << sizeof(str1[0]) << endl; cout << "str1[0][0]元素占用的空间:" << sizeof(str1[0][0]) << endl; cout << endl; cout << "str1[][]二维数组的行数:" << sizeof(str1) / sizeof(str1[0]) << endl; cout << "str1[][]二维数组的列数:" << sizeof(str1[0]) / sizeof(str1[0][0]) << endl; cout << "str1[][]二维数组中所有元素个数:" << sizeof(str1) / sizeof(str1[0][0]) << endl; cout << endl; cout << "str1[][]二维数组的内存首地址:" << str1 << endl; cout << "str1[0][0]第一行行首的内存首地址:" << &str1[0][0] << endl; cout << "str1[0][1]元素的内存首地址:" << &str1[0][1] << endl; cout << "str1[1][0]第二行行首的内存首地址:" << &str1[1][0] << endl;------------------------------------------------------------------------------------------2 -1 01 2 3str1[][]二维数组占用的空间:24str1[][]第一行占用的空间:12str1[0][0]元素占用的空间:4str1[][]二维数组的行数:2str1[][]二维数组的列数:3str1[][]二维数组中所有元素个数:6str1[][]二维数组的内存首地址:00CFF844str1[0][0]第一行行首的内存首地址:00CFF844str1[0][1]元素的内存首地址:00CFF848str1[1][0]第二行行首的内存首地址:00CFF850请按任意键继续. . .
(2.3)二维数组应用案例
十、函数
(1)函数的定义
作用:将一段经常使用的代码封装起来,减少重复代码。
组成:
1.返回值类型:一个函数可以返回一个值。
2.函数名:函数的名称。
3.参数列:使用函数时,传入的数据。
4.函数体语句:花括号内的代码,函数内需要执行的语句,用户代码。
5.return表达式:和返回值类型匹配。函数执行完后,返回相应数据。
语法:
返回值类型 函数名 (参数列表){ 函数体语句 return表达式}int add (int num1, int num2){ int sum = num1 + num2; return sum;}int main(){ /* 用户代码段 */ // ... // ... system("pause"); return 0;}
(2)函数的调用,形参,实参
#includeusing namespace std;// 函数定义int add(int num1, int num2) // int num1, int num2为形式参数,简称形参{ int sum = num1 + num2; return sum;}int main() { // a,b称为 实际参数,简称实参 int a = 11, b = 23; // 调用add函数 int sum = add(a, b); cout << "a + b = " << sum << endl; system("pause"); return 0;}------------------------------------------------------------------------a + b = 34请按任意键继续. . .
(3)值传递
要点:实参传递给形参后,形参的改变不会影响到实测。
#includeusing namespace std;// 函数定义int test1(int num1, int num2){ cout << "输入的 num1 = " << num1 << endl; cout << "输入的 num2 = " << num2 << endl; cout << endl; num1 += 10; num2 += 20; cout << "输出的 num1 = " << num1 << endl; cout << "输出的 num2 = " << num2 << endl; cout << endl; return 0;}int main() { // a,b称为 实际参数,简称实参 int a = 11, b = 23; cout << "a = " << a << endl; cout << "b = " << b << endl; cout << endl; // 调用add函数 test1(a, b); cout << "a = " << a << endl; cout << "b = " << b << endl; cout << endl; system("pause"); return 0;}----------------------------------------------------------------------a = 11b = 23输入的 num1 = 11输入的 num2 = 23输出的 num1 = 21输出的 num2 = 43a = 11b = 23请按任意键继续. . .
(4)函数的常见样式
常见的函数样式有4种:
1.无参无返
2.有参无返
3.无参有返
4.有参有返
(5)函数的声明
作用:告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
注意:函数的声明可以多次,但是函数的定义只能有一次。
#includeusing namespace std;// 函数的声明int test1(int num1, int num2);int main() { // a,b称为 实际参数,简称实参 int a = 11, b = 23; cout << "a = " << a << endl; cout << "b = " << b << endl; cout << endl; // 调用add函数 int max = test1(a, b); cout << "较大值 = " << max << endl; system("pause"); return 0;}// 函数定义int test1(int num1, int num2){ return num1 > num2 ? num1 : num2;}------------------------------------------------------------------a = 11b = 23较大值 = 23请按任意键继续. . .
(6)函数的分文件编写
函数太多,不能写同一个文件中。而且功能混淆,不便于梳理、阅读、移植。
作用:让代码结构更加清晰。
函数的分文件编写一般有4个步骤:
1.创建后缀名为.h的头文件
2.创建后缀名为.cpp的源文件
3.在头文件中写函数的声明
4.在源文件中写函数的定义
将(5)的代码分文件编写:
demo.cpp
#includeusing namespace std;#include "swap.h"int main() { // a,b称为 实际参数,简称实参 int a = 11, b = 23; cout << "a = " << a << endl; cout << "b = " << b << endl; cout << endl; // 调用add函数 int max = swap(a, b); cout << "较大值 = " << max << endl; system("pause"); return 0;}
swap.cpp
#include "swap.h"// 函数定义int swap(int num1, int num2){ return num1 > num2 ? num1 : num2;}
swap.h
#includeusing namespace std; // 函数的声明int swap(int num1, int num2);
十一、指针
(1)指针的定义和使用
指针的作用:可以通过指针间接访问内存。
(1)指针变量的定义和使用:
指针变量定义语法:
数据类型 * 变量名;
#includeusing namespace std;int main() { int a = 13; int* p; // 指针指向数据a的地址 p = &a; cout << "a的内存地址为:" << &a << endl; cout << "指针p为:" << p << endl; cout << endl; // 解引用 *p = 100; cout << "a = " << a << endl; cout << "*p = " << *p << endl; system("pause"); return 0;}------------------------------------------------------------a的内存地址为:007FF988指针p为:007FF988a = 100*p = 100请按任意键继续. . .
(2)指针所占用的空间
指针也是一种数据类型,这种数据类型占用多少内存字节呢?
#includeusing namespace std;int main() { int a = 13; int* p; // 指针指向数据a的地址 p = &a; cout << "sizeof(int * ) = " << sizeof(int*) << endl; cout << "sizeof(float * ) = " << sizeof(float*) << endl; cout << "sizeof(double * ) = " << sizeof(double*) << endl; cout << "sizeof(char * ) = " << sizeof(char*) << endl; system("pause"); return 0;}Debug x86:------------------------------------------------------------------------sizeof(int * ) = 4sizeof(float * ) = 4sizeof(double * ) = 4sizeof(char * ) = 4请按任意键继续. . .Debug x64:------------------------------------------------------------------------sizeof(int * ) = 8sizeof(float * ) = 8sizeof(double * ) = 8sizeof(char * ) = 8请按任意键继续. . .
指针所占用的内存空间大小,只跟操作系统有关。32位系统为4字节,64位系统为8字节。
指针前面的数据类型,只是表示这段指针对应的值的数据类型,并不是指针的类型。
修改程序运行在32位、64位操作系统环境,在这里勾选 x86、x64。
(3)空指针
空指针:指针变量指向内存中编号为0的空间。
用途:初始化指针变量。
注意:空指针指向的内存是不可以访问的。
#includeusing namespace std;int main() { //空指针 int* p = NULL; //*p = 100; cout << "指针p指向的内存地址: " << p << endl; cout << "指针p指向的值为: " << *p << endl; system("pause"); return 0;}-------------------------------------------------------指针p指向的内存地址: 00000000D:\VS_C++_PRJ\demo01\Debug\demo01.exe (进程 11668)已退出,代码为 -1073741819。按任意键关闭此窗口. . .
(4)野指针
野指针:指针变量指向非法的内存空间。
注意:在程序中,尽量避免出现野指针。
#includeusing namespace std;int main() { //野指针 int * p = (int *)0x21003000; //*p = 100; cout << "指针p指向的内存地址: " << p << endl; cout << "指针p指向的值为: " << *p << endl; system("pause"); return 0;}---------------------------------------------------------------------------指针p指向的内存地址: 21003000D:\VS_C++_PRJ\demo01\Debug\demo01.exe (进程 7944)已退出,代码为 -1073741819。按任意键关闭此窗口. . .
(5)const修饰指针
const修饰指针有三种情况:
1.const修饰指针 ---- 常量指针2.const修饰指针 ---- 指针常量
3.const既修饰指针,也修饰常量
const修饰指针 ---- 常量指针:
int a = 10, b = 10;// 常量指针// 特点:指针的指向可以修改,但是指针指向的值不可修改const int * p = &a;*p = 20; // 错误,指针指向的值不可以修改p = &b; // 正确,指针的指向可以修改
const修饰指针 ---- 指针常量:
int a = 10, b = 10;// 指针常量// 特点:指针的指向不可以修改,指针指向的值可以修改int * const p = &a;*p = 20; // 正确,指针指向的值可以修改p = &b; // 错误,指针的指向不可以修改
const既修饰指针,也修饰常量:
int a = 10, b = 10;// 指针常量// 特点:指针的指向、指针指向的值,都不可以修改const int * const p = &a;*p = 20; // 错误,指针指向的值不可以修改p = &b; // 错误,指针的指向不可以修改
(6)指针和数组
作用:利用指针访问数组中的元素
int main() { int str1[10] = {11, 56, 82, 42, 85, 45, 89, 23, 41, 57}; int* p = str1; cout << *p << endl; cout << *p + 1 << endl; cout << *(p + 1) << endl; p++; cout << *p << endl; system("pause"); return 0;}-------------------------------------------------------------------11125656请按任意键继续. . .
(7)指针和函数(地址传递)
作用:利用指针做函数参数,可以修改实参的值。
与10.3值传递,对比着看。
要点:如果不想修改实参,就用值传递。如果想修改实参,就用地址传递。
int swap(int * num1, int * num2){ int xtemp = *num1; *num1 = *num2; *num2 = xtemp; return 0;}int main() { int a = 22; int b = 55; cout << "a = " << a << endl; cout << "b = " << b << endl; cout << endl; swap(&a, &b); cout << "a = " << a << endl; cout << "b = " << b << endl; cout << endl; system("pause"); return 0;}---------------------------------------------------------a = 22b = 55a = 55b = 22请按任意键继续. . .
(8)指针、数组、函数,配合使用案例
十二、结构体
(1)结构体定义和使用
基本概念:结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。
结构体定义和使用:
语法:
struct 结构体名 { 结构体成员列表 };
通过结构体创建变量的方式有三种:
struct 结构体名 变量名;struct 结构体名 变量名 = { 成员1值, 成员2值... };定义结构体时顺便创建变量;
代码:
/* ------------------ 1.struct 结构体名 变量名; 之后进行赋值操作 ------------------ */struct Student{ // 成员列表 string name; // 姓名 int age; // 年龄 int score; // 分数};int main() { //struct Student xiaoMing; Student xiaoMing; // struct关键字可以省略 xiaoMing.name = "小明"; xiaoMing.age = 18; xiaoMing.score = 96; xiaoMing = { "小明", 18, 96 }; cout << "姓名:" << xiaoMing.name << " 年龄:" << xiaoMing.age << " 分数:" << xiaoMing.score << endl; system("pause"); return 0;}/* -------------- 2.struct 结构体名 变量名 = { 成员1值, 成员2值... }; -------------- */struct Student{ // 成员列表 string name; // 姓名 int age; // 年龄 int score; // 分数};int main() { Student xiaoMing = {"小明", 18, 96}; cout << "姓名:" << xiaoMing.name << " 年龄:" << xiaoMing.age << " 分数:" << xiaoMing.score << endl; system("pause"); return 0;}/* -------------------- 3.定义结构体时顺便创建变量; -------------------- */struct Student{ // 成员列表 string name; // 姓名 int age; // 年龄 int score; // 分数};int main() { xiaoMing.name = "小明"; xiaoMing.age = 18; xiaoMing.score = 96; xiaoMing = { "小明", 18, 96 }; cout << "姓名:" << xiaoMing.name << " 年龄:" << xiaoMing.age << " 分数:" << xiaoMing.score << endl; system("pause"); return 0;}-----------------------------------------------------------------------------------姓名:小明 年龄:18 分数:96请按任意键继续. . .
使用 typedef 定义 struct 结构体方法:
(2)结构体数组
作用:将自定义的结构体放入到数组中,方便维护。
语法:
struct 结构体名 数组名[ 元素个数 ] = { {}, {}, ... {} };
struct Student{ // 成员列表 string name; // 姓名 int age; // 年龄 int score; // 分数};int main() { struct Student stuArray[3] = { { "小明", 18, 96 }, { "小红", 20, 100 }, { "小亮", 21, 98 } }; for (int i = 0; i < 3; i++) { cout << "姓名:" << stuArray[i].name << " 年龄:" << stuArray[i].age << " 分数:" << stuArray[i].score << endl; } system("pause"); return 0;}----------------------------------------------------------------------------姓名:小明 年龄:18 分数:96姓名:小红 年龄:20 分数:100姓名:小亮 年龄:21 分数:98请按任意键继续. . .
(3)结构体指针
作用:通过指针访问结构体中的成员。
利用操作符 -> 可以通过结构体指针访问结构体属性。
示例:
struct Student{ // 成员列表 string name; // 姓名 int age; // 年龄 int score; // 分数};int main() { struct Student xiaoMing = { "小明", 18, 96 }; Student* p = &xiaoMing; cout << "姓名:" << p->name << " 年龄:" << p->age << " 分数:" << p->score << endl; system("pause"); return 0;}-----------------------------------------------------------------姓名:小明 年龄:18 分数:96请按任意键继续. . .
(4)结构体嵌套
结构体嵌套结构体:
作用:结构体中的成员可以是另一个结构体。
例如:每个老师辅导一个学员,老师的结构体中,记录学生的结构体。
示例:
struct student{ // 成员列表 string name; // 姓名 int age; // 年龄 int score; // 分数};struct teacher{ int id; // 职工编号 string name; // 教师姓名 int age; // 教师年龄 struct student stu; // 子结构体 学生};int main() { teacher wang; wang.id = 112374; wang.name = "王芳"; wang.age = 26; wang.stu.name = "小明"; wang.stu.age = 18; wang.stu.score = 96; cout << "教师姓名:" << wang.name << " 教师年龄:" << wang.age << " 教师ID号:" << wang.id << endl; cout << "学生姓名:" << wang.stu.name << " 学生年龄:" << wang.stu.age << " 学生分数:" << wang.stu.score << endl; system("pause"); return 0;}-------------------------------------------------------------------------教师姓名:王芳 教师年龄:26 教师ID号:112374学生姓名:小明 学生年龄:18 学生分数:96请按任意键继续. . .
(5)结构体做函数参数
作用:将结构体作为参数向函数中传递
传递方式分两种:值传递,地址传递。
值传递示例:
struct student{ // 成员列表 string name; // 姓名 int age; // 年龄 int score; // 分数};void printStudent(student stu){ cout << "姓名:" << stu.name << " 年龄:" << stu.age << " 分数:" << stu.score << endl; stu.name = "无"; stu.age = 0; stu.score = 0;}int main() { student xiaoMing = { "小明", 18, 96 }; printStudent(xiaoMing); cout << "姓名:" << xiaoMing.name << " 年龄:" << xiaoMing.age << " 分数:" << xiaoMing.score << endl; system("pause"); return 0;}---------------------------------------------------------------------------姓名:小明 年龄:18 分数:96姓名:小明 年龄:18 分数:96请按任意键继续. . .
地址传递示例:
struct student{ // 成员列表 string name; // 姓名 int age; // 年龄 int score; // 分数};void printStudent(student * stu){ cout << "姓名:" << stu->name << " 年龄:" << stu->age << " 分数:" << stu->score << endl; stu->name = "无"; stu->age = 0; stu->score = 0;}int main() { student xiaoMing = { "小明", 18, 96 }; printStudent(&xiaoMing); cout << "姓名:" << xiaoMing.name << " 年龄:" << xiaoMing.age << " 分数:" << xiaoMing.score << endl; system("pause"); return 0;}--------------------------------------------------------------------------姓名:小明 年龄:18 分数:96姓名:无 年龄:0 分数:0请按任意键继续. . .
如果不想实参结构体内容,用值传递,反之用地址传递。
地址传递还可以使用数组,可实现同样功能,书写与阅读比指针更加直观。
(6)结构体中const使用场景
作用:用const来防止误操作
值传递会copy,会占内存空间,复制也会多花时间。所以如果可以用地址传递,可以提高执行效率。
而地址传递可能会对原始对象进行误修改,这时候就可以加 const。如果出现修改,编译器会报错
示例:
void printStudent(const student * stu){ cout << "姓名:" << stu->name << " 年龄:" << stu->age << " 分数:" << stu->score << endl; stu->name = "无"; // 编译器会报错 stu->age = 0; stu->score = 0;}
发表评论
最新留言
关于作者
