目录
一、初识C++
1、固定格式
#include <iostream>
using namespace std;
int main()
{
// 这里写代码...
system ("pause");
return 0;
}
2、第一个程序:hello world
#include <iostream>
using namespace std;
int main()
{
cout << "hello world" << endl;
return 0;
}
3、注释
单行注释://
多行注释:/* */
4、变量与常量
变量:数据类型 变量名=变量值;
int a = 5;
常量:宏常量、const修饰变量
宏常量:#define 常量名 常量值
#include <iostream>
using namespace std;
int main()
{
#define day 7
cout << "一周总共有" << day << "天" << endl;
return 0;
}
const修饰变量:const 数据类型 常量名=常量值
#include <iostream>
using namespace std;
int main()
{
const int month = 12;
cout << "一年有" << month << "个月" << endl;
return 0;
}
5、关键字/标识符
在定义变量或者常量的时候不要用下面这些关键字。
标识符命名规则:
1、不能是关键字;2、只能由字母、数字、下划线组成;
3、第一个字符必须为字母或下划线;4、字母严格区分大小写。
二、数据类型
1、整型
int 变量名 = 变量值;
数据类型存在的意义:给变量分配合适的内存空间。
sizeof关键字:sizeof(数据类型/变量)
利用sizeof关键字可以统计数据类型所占内存大小。
2、实型(浮点型)
单精度:float
双精度:double
float 变量名 = 变量值;
两者唯一的区别在于表示的有效数字范围不同。
float:占用4字节,7位有效数字。
double:占用8字节,15-16位有效数字。
还有一种小数表示法:科学计数法(少用),float a = 3e2,3e2表示:3*10^2
float a = 3.14f;一般我们会在数字后面加上一个f,否则编译器会默认是双精度类型的。
float默认情况下会在小数点后显示5位。
3、字符型和字符串类型
字符型:char 变量名 = ’一个字符’;
注:只能用单引号,不能用双引号,而且只能有一个字符,不能是字符串。
C和C++中都只占用1个字节。
字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放入到存储单元。
查看字符的ASCII码:cout << (int)a << endl;
(int)a:把字符型强制转化成整型,a是97,A是65。
字符串类型:
C语言:char 变量名[] = “字符串值”;
C++:string 变量名 = “字符串值”;
这两种风格在C++中都可以用,记得要用双引号。
4、转义字符
现阶段常用的有:\n、\\、\t
\t一共占8个位置,如果是aaaa\t,那么输出结果为:aaaa+4个空格,如果是aaa\t,输出结果为:aaa+5个空格。
5、布尔类型
bool 变量名 = true/false;
bool型只有两种:true、false,本质上1代表真值,0代表假值,布尔类型只占1个字节大小。
6、数据的输入
cin >> 变量1 >> 变量2 >> 变量3
输入之前记得先声明变量类型。
三、运算符
1、算数运算符
两个整数相除,结果依然是整数,去抹去小数部分。
前置递增++a表示:先让变量+1,然后再进行表达式的运算;
后置递增a++表示:先进行表达式的运算,后让变量+1。
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = ++a *10;
int c = 10;
int d = c++ *10;
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "c=" << c << endl;
cout << "d=" << d << endl;
// 输出的结果:a=11,b=110,c=11,d=100
return 0;
}
2、赋值运算符
=、+=、-=、*=、/=、%=
3、比较运算符
==相等于,!=不等于
>、<、>=、<=
4、逻辑运算符
四、程序运行结构
程序运行结构:顺序结构、选择结构、循环结构
1、选择结构:if语句
单行:if(条件){条件满足执行的语句}
多行:if(条件){条件满足执行的语句}
else{条件未满足执行的语句}
多条件:if(条件1){条件1满足执行的代码}
else if(条件2){条件2满足执行的代码}
......
else{以上条件都不满足执行的代码}
#include <iostream>
using namespace std;
int main()
{
// 用户输入分数,如果在500-600区间内,恭喜考上本科,如果大于600,恭喜考上重点,否则,复读。
int score = 0;
cout << "请输入一个分数:" << endl;
cin >> score;
if(score>600)
{
cout << "考上重点大学!" << endl;
}
else if(500<=score && score<=600)
{
cout << "考上本科!" << endl;
}
else
{
cout << "去复读!" << endl;
}
return 0;
}
嵌套if语句:if语句中再嵌套if语句
接上面的例子,在大于600分的重点档里,600-630:211,630-680:985,680+:清北。
#include <iostream>
using namespace std;
int main()
{
int score = 0;
cout << "请输入一个分数:" << endl;
cin >> score;
if(score>600)
{
if (score > 600 && score <= 630)
{
cout << "考上211大学!" << endl;
}
else if(score > 630 && score <= 680)
{
cout << "考上985大学!" << endl;
}
else
{
cout << "考上清北!" << endl;
}
}
else if(500<=score && score<=600)
{
cout << "考上本科!" << endl;
}
else
{
cout << "去复读!" << endl;
}
return 0;
}
小练习:三只小猪称体重:分别输入三只小猪的体重,判断哪只最重。
#include <iostream>
using namespace std;
int main()
{
int a=0,b=0,c=0;
cin >> a >> b >> c;
if(a>b)
{
if(a>c)
{
cout << a << endl;
}
else
{
cout << c << endl;
}
}
else
{
if(b>c)
{
cout << b << endl;
}
else
{
cout << c << endl;
}
}
return 0;
}
三目运算符和switch语句
三目运算符:条件?条件满足执行的语句:条件不满足执行的语句;
switch语句:
switch(需要判断的变量)
{
case 常量1 :当变量=常量1时需要执行的语句;break;
case 常量2 :当变量=常量2时需要执行的语句;break;
......
default:其他情况下执行的语句;break;
}
注意在判断时只能是一个整型或者字符型,不能是一个区间。
优点是结构清晰,执行效率高于if。
练习:给电影打分。
#include <iostream>
using namespace std;
int main()
{
int score = 0;
cin >> score;
switch(score)
{
case 9:
cout << "经典佳作!" << endl;
break;
case 8:
cout << "不错的电影!" << endl;
break;
// ...
default:
cout << "都一般!" << endl;
break;
}
return 0;
}
2、循环结构:while语句、for语句
while语句:while(条件){条件满足时执行的语句}
练习:系统随机生成1-100之间的数字,玩家进行猜测,如果猜错,提示玩家数字过大或者过小,如果猜对,恭喜玩家获得胜利,并退出游戏。
生成随机数:rand()%要生成的随机数的区间最大值,如rand()%100,表示生成0-99的随机数。
#include <iostream>
using namespace std;
#include <ctime>
int main()
{
// 添加随机数种子,利用当前系统时间生成随机数,防止每次随机数都一样。
srand((unsigned int)time(NULL));
int num = rand()%100+1;
int guess = 0;
while(1)
{
cin >> guess;
if(guess>num)
{
cout << "猜大了" << endl;
}
else if(guess<num)
{
cout << "猜小了" << endl;
}
else
{
cout << "猜对了" << endl;
break;
}
}
return 0;
}
do...while语句:do(循环语句)while(循环条件)
与while不同的是,它会先执行一次循环语句,再判断循环条件。
练习:水仙花数是指一个3位数,它的每个位上的数字的3次幂之和等于它本身,例如:1^3+5^3+3^3=153,请利用do...while语句,求出所有3位数中的水仙花数。
#include <iostream>
using namespace std;
int main()
{
// 1、先获取所有的三位数100-999,;2、在所有的三位数中找到水仙花数。
int num = 100;
do
{
int a,b,c;
// a:个位,b:十位,c:百位。
// 如果想拿到一个数字的个位数,只需要对它模以10即可。
a = num % 10;
b = num / 10 % 10;
c = num / 100;
if(a*a*a + b*b*b + c*c*c == num)
{
cout << num << endl;
}
num++;
} while (num<1000);
return 0;
}
for语句:for(起始表达式;条件表达式;末尾循环体){满足条件执行的循环语句}
eg:for(inti=1;i<10;i++){cout << i << endl;}
练习:敲桌子游戏:从1开始到数字100,如果数字个位或者十位含有7,或者该数字是7的倍数,敲桌子,其余数字输出。
#include <iostream>
using namespace std;
int main()
{
for(int i=1;i<=100;i++)
{
if(i%7==0 || i%10==7 || i/10==7)
{
cout << "敲桌子" << endl;
}
else
{
cout << i << endl;
}
}
return 0;
}
嵌套循环:在循环体中再嵌套一层循环。
练习:利用嵌套循环打印下面的乘法口诀表。
#include <iostream>
using namespace std;
int main()
{
// 1、列数*行数=结果;2、列数<=当前行数
for(int i=1;i<=9;i++)
{
for(int j=1;j<=i;j++)
{
cout << i << "x" << j << "=" << j*i << " ";
}
cout << endl;
}
return 0;
}
跳转语句:break、continue、goto
break:用于跳出选择结构或者循环结构。
continue:跳过本次循环中余下未执行的语句,继续执行下一次循环。
goto:可以无条件跳转语句。goto 标记,如果标记的名称存在,则会直接跳转到标记的语句执行。
#include <iostream>
using namespace std;
int main()
{
cout << "11111" << endl;
cout << "22222" << endl;
goto FLAG;
cout << "33333" << endl;
cout << "44444" << endl;
FLAG:
cout << "55555" << endl;
return 0;
}
// 输出结果为:11111 22222 55555
五、数组
所谓数组,就是一个集合,里面存放了相同类型的数据元素。
特点:1、数组中的每个数据元素都是相同的数据类型;2、数组是由连续的内存位置组成的。
从0开始进行索引。
1、一维数组
一维数组的三种定义方式:
1、数据类型 数组名[数组长度];
2、数据类型 数组名[数组长度] = {值1,值2,...};
3、数据类型 数组名[] = {值1,值2,...};
如果规定了数组长度为5,但是只写入3个数,剩下的数会自动用0填充。
定义的时候必须初始化它的长度。
#include <iostream>
using namespace std;
int main()
{
// 1、数据类型 数组名[数组长度];
int a[3];
// 给数组中的元素进行赋值:
a[0] = 10;
a[1] = 20;
a[2] = 30;
// 2、数据类型 数组名[数组长度] = {值1,值2,...};
int b[3] = {10,20,30};
// 3、数据类型 数组名[] = {值1,值2,...};
int c[] = {10,20,30};
// 访问数组元素:利用循环输出数组元素。
for(int i=0;i<3;i++)
{
cout << a[i] << endl;
}
for(int j=0;j<3;j++)
{
cout << b[j] << endl;
}
for(int s=0;s<3;s++)
{
cout << c[s] << endl;
}
return 0;
}
直接cout<< a << endl;出来的是它的十六进制地址:0x61fe14
一维数组名的用途:
1、可以统计整个数组在内存中的长度;
2、可以获取数组在内存中的首地址。
注:数组名是一个常量,不可以进行赋值操作。
#include <iostream>
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
// 统计整个数组所占用的内存长度,这个输出为20
cout << sizeof(a) << endl;
// 统计单个元素所占的内存空间,这个输出为4,可以通过sizeif(a)/ sizeof(a[0])来获取数组长度。
cout << sizeof(a[0]) << endl;
// 获得整个数组首地址,为了方便查看,可以利用long long把它转成十进制,这个输出为:6422016
cout << (long long)a << endl;
// 获得某个元素的首地址,因为第一个元素的首地址和整个数组的首地址是一样的,这里演示第二个元素,输出为:6422020
cout << (long long)&a[1] << endl;
return 0;
}
练习:数组元素逆置。
#include <iostream>
using namespace std;
int main()
{
int set[5] = {1,2,3,4,5};
cout << "原数组元素为:" << endl;
for(int i=0;i<5;i++)
{
cout << set[i] << endl;
}
// 获取起始元素下标位置和末尾元素的下表位置
int start = 0;
int end = (sizeof(set)/sizeof(set[0]))-1;
while (start<end)
{
// 首尾元素互换
int temp = set[start];
set[start] = set[end];
set[end] = temp;
// 下标更新
start++;
end--;
}
//打印输出逆置后的数组
cout << "数组元素逆置后为:" << endl;
for(int j=0;j<5;j++)
{
cout << set[j] << endl;
}
return 0;
}
冒泡排序:最常用的排序算法,对数组内元素进行排序。
升序排序、降序排序。
练习:对42805719进行升序排列
1、比较相邻的元素,如果第一个比第二个大,就交换他们两个。
第一轮对比完成后结果为:240571389
2、找到第一个最大值:9
这个9就像一个气泡一样冒出来,所以叫它冒泡排序。
3、重复上面的步骤,每次比较次数-1,直到不需要比较。
第一轮对比8次(元素数-1),第二轮对比7次...
#include <iostream>
using namespace std;
int main()
{
int set[9] = {4,2,8,0,5,7,1,3,9};
cout << "未排序之前的数组为:" << endl;
for(int i=0;i<9;i++)
{
cout << set[i] << endl;
}
// 开始冒泡排序:总共排序的轮数=元素个数-1
for(int i=0;i<9-1;i++)
{
// 内层循环对比=元素个数-当前轮数-1
for(int j=0;j<9-i-1;j++)
{
// 如果第一个数字比第二个数字大,交换两个数字
if(set[j] > set[j+1])
{
// 实现两个元素的交换。
int temp = set[j];
set[j] = set[j+1];
set[j+1] = temp;
}
}
}
cout << "排序后结果为:" << endl;
for(int s=0;s<9;s++)
{
cout << set[s] << endl;
}
return 0;
}
2、二维数组
二维数组的四种定义方式:
1、数据类型 数组名[行数][列数];
2、数据类型 数组名[行数][列数] = {{数据1,数据2},{数据3,数据4}};
3、数据类型 数组名[行数][列数] = {{数据1,数据2,数据3,数据4}};
4、数据类型 数组名[][列数] = {{数据1,数据2,数据3,数据4}};
推荐第二种,更为直观。
按照以下坐标进行访问:
利用for循环打印二维数组中的每个元素:
#include <iostream>
using namespace std;
int main()
{
int set[2][3] = {{1,2,3},{4,5,6}};
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
cout << set[i][j] << endl;
}
}
return 0;
}
二维数组名:
1、查看二维数组所占用的内存空间;
2、获取二维数组首地址。
#include <iostream>
using namespace std;
int main()
{
int set[2][3] = {{1,2,3},{4,5,6}};
// 1、查看二维数组占用的内存空间大小
cout << "二维数组占用的内存空间为:" << sizeof(set) << endl;
cout << "二维数组第一行占用的内存空间为:" << sizeof(set[0]) << endl;
// 可以利用sizeof求行数:整个/每行;求列数:每行/每个。
cout << "二维数组的行数为:" << sizeof(set)/sizeof(set[0]) << endl;
cout << "二维数组的列数为:" << sizeof(set[0])/sizeof(set[0][0]) << endl;
// 2、查看二维数组的首地址
cout << "二维数组的首地址为:" << set <<endl;
// 转成十进制:
cout << "二维数组的首地址为:" << (long long)set <<endl;
cout << "二位数组第一行首地址为:" << (long long)&set[0] <<endl;
cout << "二位数组第一个元素首地址为:" << (long long)&set[0][0] << endl;
// 二维数组的首地址=二维数组第一行的首地址=位数组第一个元素的首地址
return 0;
}
练习:考试成绩统计:
#include <iostream>
using namespace std;
int main()
{
int grade[3][3] = {{100,100,100},{90,50,100},{60,70,80}};
for(int i=0;i<3;i++)
{
int sum = 0;
for(int j=0;j<3;j++)
{
sum += grade[i][j];
// cout << grade[i][j];
}
cout << sum << endl;
}
return 0;
}
六、函数
1、函数的定义
函数的定义要有以下五个步骤:
返回值类型、函数名、形参列表、函数体语句、return表达式
返回值类型 函数名 (形参列表)
{
函数体语句;
return表达式;
}
如:计算两个数相加的函数。
int add(int a,int b)
{
int sum = a + b;
return sum;
}
2、函数的调用
函数名(实参)
练习:调用上面的加法函数。
int main()
{
int num1 = 10;
int num2 = 20;
int s = add(num1,num2);
cout << s << endl;
return 0;
}
在函数定义的时候,a和b并没有真实的数据,只是一个形式上的参数,简称形参;后面调用的时候,实参的值会传递给形参。
函数调用时实参将数值传递给形参,这就叫值传递。
3、函数的常见样式
常见四种:无参无返、有参无返、无参有返、有参有返。
无返回值都用void声明返回值类型。
#include <iostream>
using namespace std;
// 1、无参无返:void
void test01()
{
cout << "test01函数" << endl;
}
// 2、有参无返:void
void test02(int a)
{
cout << "test02函数,传入的参数:" << a << endl;
}
// 3、无参有返
int test03()
{
cout << "test03函数" << endl;
return 3;
}
// 4、有参有返
int test04(int b)
{
cout << "test04函数,传入的参数:" << b << endl;
return b;
}
int main()
{
// 调用无参无返函数
test01();
// 调用有参无返函数
test02(2);
// 调用无参有返函数,如果有返回值了就需要有变量来接收。
int s = test03();
cout << "test03返回值为:" << s << endl;
// 调用有参有返函数
int t = test04(4);
cout << "test04返回值为:" << t << endl;
return 0;
}
4、函数的声明
告诉编译器函数名称及如何调用函数,函数的实际主体可以单独定义。
为什么要写函数的声明?——之前只能在main函数体前写函数,这样程序才会执行,但是如果想把函数写在main函数体后面,需要先告诉编译器函数的存在,这就需要利用函数的声明。
声明可以写多次,但是定义函数只有一次。
练习:比较函数,两个整形数字进行比较,返回较大的值。
#include <iostream>
using namespace std;
// 声明比较函数max的存在
int max(int a,int b);
int main()
{
int a = 10;
int b = 20;
cout << max(a,b) << endl;
return 0;
}
// 定义比较函数max
int max(int a,int b)
{
return a>b?a:b;
}
七、指针
1、指针的定义和使用
指针的作用:可以通过指针间接访问内存。
内存编号是从0开始记录的,一般用十六进制数字表示,可以用指针变量保存地址。
指针的定义:
数据类型 变量名 = 变量值;
数据类型 * 指针变量名;
指针变量名 = &变量名;
或者直接:数据类型 * 指针变量名 = &变量名
指针的使用:
通过解引用的方式来找到指针指向的内存。
* 指针变量名
&取地址,*取值。
#include <iostream>
using namespace std;
int main()
{
int a = 10;
// 定义指针
int* p;
p = &a;
// 或者直接:int* p = &a;其中,p就是指针(地址)。
// 获取指针中存放的地址:
cout << "指针中存放的地址编号为:" << p << endl;
// 输出结果为:指针中存放的地址编号为:0x61fe14
// 获取指针中存放的地址中存放的数据:解引用,在指针前加一个*就是解引用,可以找到指针指向的内存中的数据。
cout << "指针中地址编号中存放的数据为:" << *p << endl;
// 输出结果为:指针中地址编号中存放的数据为:10
return 0;
}
2、指针所占的内存空间
指针也是一种数据类型,一般来说,在32位操作系统下占4个字节,64位下占8个字节。
3、空指针和野指针
空指针:指针变量指向内存为0的空间,用于初始化指针变量。
空指针指向的内存是不可以访问的。
如果一开始不知道指针指向哪里合适,可以用空指针。
#include <iostream>
using namespace std;
int main()
{
// 1、空指针用于初始化指针变量
int* p = NULL;
// 2、空指针不可访问
*p = 100;
// 这个运行会报错!
return 0;
}
野指针:指针变量指向非法的内存空间。
在程序中要尽量避免出现。
#include <iostream>
using namespace std;
int main()
{
// 野指针:我们随便编了一个内存地址
int* p = (int*)0x1100;
// 这个运行会报错!
return 0;
}
4、const修饰指针
①const修饰指针:常量指针——指针指向可以修改,指针指向的值不能修改。
const int * p = & a;
②const修饰常量:指针常量——指针指向的值能修改,指针指向不能修改。
int * const p = & a;
③const既修饰指针,又修饰常量——指针指向和指针指向的值都不能修改。
小技巧:可以把const译成常量,*译成指针,const *就是常量指针,*const就是指针常量。
5、指针和数组、指针和函数
1、指针和数组:利用指针访问数组中的元素。
#include <iostream>
using namespace std;
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = arr;
// 数组名就是地址,数组名是第一个元素的地址,和数组地址虽然值一样,但指向大小不一样。
cout << "利用指针来访问第一个元素:" << *p << endl;
// 让指针往后移4个字节即可(一个整型 元素占4个字节)
p++;
cout << "利用指针来访问第二个元素:" << *p << endl;
return 0;
}
还可以直接p[i],下标从0开始
2、指针和函数:利用指针作函数参数,可以修改实参的值。
#include <iostream>
using namespace std;
// 函数:两个数字进行交换
// 1、值传递
void swap01(int a,int b)
{
int temp = a;
a = b;
b = temp;
cout << "swap01中的a=" << a << endl;
cout << "swap01中的b=" << b << endl;
}
// 2、地址传递:如果我们想在函数体中真的修改外部的a、b的数据,就用这个
void swap02(int *p1,int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
cout << "swap02中的a=" << *p1 << endl;
cout << "swap02中的b=" << *p2 << endl;
}
int main()
{
int a = 10;
int b = 20;
// 1、值传递
swap01(a,b);
cout << "运行swap01后外部的a=" << a << endl;
cout << "运行swap01后外部的b=" << b << endl;
// 2、地址传递
swap02(&a,&b);
cout << "运行swap02后外部的a=" << a << endl;
cout << "运行swap02后外部的b=" << b << endl;
return 0;
}
原因:地址传递是直接改了地址,地址交换了,里面存储的数据自然也就交换了。
3、指针配合函数、数组的案例:
案例:封装一个函数,利用冒泡排序,实现对整型数组的升序排序。
例如一个数组:int arr[10] = {4,3,6,9,1,2,10,8,7,5};
#include <iostream>
using namespace std;
// 冒泡排序函数:参数1:数组地址,参数2:数组长度
void bubble(int *arr,int len)
{
for(int i=0;i<len-1;i++)
{
for(int j=0;j<len-i-1;j++)
{
if(arr[j]>arr[j+1])
{
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
// 打印数组的函数:
void printarr(int *arr,int len)
{
for(int i=0;i<len;i++)
{
cout << arr[i] << endl;
}
}
int main()
{
int arr[10] = {4,3,6,9,1,2,10,8,7,5};
int len = sizeof(arr)/sizeof(arr[0]);
// 一般来说,需要传入数组、数组的长度。
bubble(arr,len);
printarr(arr,len);
return 0;
}
核心:
如何把一个数组传入一个函数中?——用指针接收首地址;
熟练运用冒泡排序;
在函数中使用数组,最好还要传入它的长度。
八、结构体
结构体属于用户自定义的数据类型,允许用户储存不同的数据类型。
整型、字符型等,这些数据类型都属于内置的数据类型。
如果要写一个动物的数据类型?——结构体可以实现。
1、结构体的定义和使用
定义结构体:struct 结构体名 {结构体成员列表};
使用结构体的三种方式:
1、struct 结构体名 变量名
2、struct 结构体名 变量名 = {成员1值,成员2值...}
3、定义结构体时顺便创建变量
#include <iostream>
using namespace std;
#include <string>
// 创建学生数据类型,学生包括:姓名、年龄、分数
// 自定义数据类型就是一些内置数据类型的集合。
struct Student
{
// 成员列表:姓名、年龄、分数
string name;
int age;
int score;
}s3; // 方法三:定义结构体的时候顺便创建变量
int main()
{
// 方法一:struct 结构体名 变量名
struct Student s1;
// 给s1属性赋值,通过.访问结构体变量中的属性
s1.name = "张三";
s1.age = 18;
s1.score = 100;
cout << "姓名:" << s1.name << endl << "年龄:" << s1.age << endl << "分数:" << s1.score << endl;
// 方法二:struct 结构体名 变量名 = {值1,值2...};注意按顺序
struct Student s2 = {"李四",19,80};
cout << "姓名:" << s2.name << endl << "年龄:" << s2.age << endl << "分数:" << s2.score << endl;
// 方法三:定义结构体的时候顺便创建变量
s3.name = "王五";
s3.age = 20;
s3.score = 90;
cout << "姓名:" << s3.name << endl << "年龄:" << s3.age << endl << "分数:" << s3.score << endl;
return 0;
}
一般来说用第一种、第二种比较多,第三种少一点。
定义的时候struct关键字不可以省略,创建的时候可以省略。
利用.访问它的成员。
2、结构体数组
struct 结构体名 数组名[元素个数] = {{},{},...{}}
#include <iostream>
using namespace std;
#include <string>
// 1、定义学生结构体,包括:姓名、年龄、分数
struct Student
{
string name;
int age;
int score;
};
int main()
{
// 2、创建结构体数组,给结构体数组中的元素赋值
struct Student stu_arr[3] = {{"张三",18,100},{"李四",19,80},{"王五",20,90}};
// 3、修改结构体数组中的元素值
stu_arr[2].name = "尼古拉斯·赵四";
// 4、遍历结构体数组并输出
for(int i=0;i<3;i++)
{
cout << "姓名:" << stu_arr[i].name << endl;
cout << "年龄:" << stu_arr[i].age << endl;
cout << "分数:" << stu_arr[i].score << endl;
}
return 0;
}
3、结构体指针
#include <iostream>
using namespace std;
#include <string>
// 1、定义学生结构体,包括:姓名、年龄、分数。
struct Student
{
string name;
int age;
int score;
};
int main()
{
// 2、创建学生结构体变量。
struct Student s = {"张三",18,100};
// 3、通过指针指向结构体变量。
struct Student* p = &s;
// 4、通过指针访问结构体变量数据,需要利用符号->,也可以用(*p).访问。
cout << "姓名:" << p->name << endl << "年龄:" << p->age << endl << "分数:" << p->score << endl;
return 0;
}
4、结构体嵌套结构体
结构体中的成员可以是另一个结构体,如老师辅导学员,一个老师的结构体中记录一个学生的结构体。
#include <iostream>
using namespace std;
#include <string>
// 定义学生结构体(要先于老师),包括:姓名、年龄、分数
struct Student
{
string name;
int age;
int score;
};
// 定义老师结构体:工号、姓名、年龄、学生结构体
struct Teacher
{
int id;
string name;
int age;
struct Student stu;
};
int main()
{
struct Teacher tea;
tea.id = 1010;
tea.name = "孙老师";
tea.age = 32;
tea.stu.name = "张三";
tea.stu.age = 18;
tea.stu.score = 100;
cout << "老师工号:" << tea.id << endl << "老师姓名:" << tea.name << endl << "老师年龄" << tea.age << endl << "老师带的学生:" << tea.stu.name << endl << "学生年龄:" << tea.stu.age << endl << "学生分数:" << tea.stu.score << endl;
return 0;
}
5、结构体做函数参数
将结构体作为参数向函数中传递,传递方式有两种:值传递和地址传递。
#include <iostream>
using namespace std;
#include <string>
// 定义学生结构体,包括:姓名、年龄、分数
struct Student
{
string name;
int age;
int score;
};
// 1、值传递
void print01(struct Student s1)
{
s1.age = 20;
cout << "值传递中打印的s1信息为:" << endl << "姓名:" << s1.name << endl << "年龄:" << s1.age << endl << "分数:" << s1.score << endl;
}
// 2、地址传递
void print02(struct Student * p)
{
p->age = 20;
cout << "地址传递中打印的s2信息为:" << endl << "姓名:" << p->name << endl << "年龄:" << p->age << endl << "分数:" << p->score << endl;
}
int main()
{
struct Student s1;
s1.name = "张三";
s1.age = 18;
s1.score = 100;
print01(s1);
cout << "值传递后打印的s1信息为:" << endl << "姓名:" << s1.name << endl << "年龄:" << s1.age << endl << "分数:" << s1.score << endl;
struct Student s2;
s2.name = "李四";
s2.age = 19;
s2.score = 80;
print02(&s2);
cout << "地址传递后打印的s2信息为:" << endl << "姓名:" << s2.name << endl << "年龄:" << s2.age << endl << "分数:" << s2.score << endl;
return 0;
}
地址传递会真正改变实参,值传递不会。
6、结构体中的const使用场景
用const来防止误操作。
#include <iostream>
using namespace std;
#include <string>
struct Student
{
string name;
int age;
int score;
};
// 打印函数。
// 如果用值传递,当数据量过大时,值传递要拷贝的数据就很多了,为了节省空间,通常会用地址传递(指针),指针只占4个字节,而且还不会多余复制一份数据副本。
void print(const struct Student *p)
{
// 在这种地址传递的函数中,有可能会误更改数据比如:p->age=20;这样就会修改全局变量,为了防止这种情况发生,就会在前面加上const。
cout << "姓名:" << p->name << endl << "年龄:" << p->age << endl << "分数:" << p->score << endl;
}
int main()
{
struct Student s = {"张三",18,100};
print(&s);
return 0;
}
7、结构体案例
案例1:每名老师带5个学生,共有3名老师。设计学生和老师结构体,其中在老师结构体中,有姓名和一个存放5名学生的数组。学生结构体有姓名、考试分数。
创建数组存放3名老师,通过函数给每个老师及学生赋值,最终打印出所有数据。
#include <iostream>
using namespace std;
#include <string>
#include <Ctime>
struct Student
{
string name;
int score;
};
struct Teacher
{
string name;
struct Student stu_arr[5];
};
// 给老师和学生赋值的函数,函数接收数组有两种方法:一种是指针,一种是下面这种
void assignment(struct Teacher tea_arr[],int len)
{
// 给老师赋值
string name_tealist = "ABC";
for(int i=0;i<len;i++)
{
// 做一个拼接字符串的操作:
tea_arr[i].name = "teacher_";
tea_arr[i].name += name_tealist[i];
// 给每名老师带的学生赋值
for(int j=0;j<5;j++)
{
// 学生姓名
string name_stulist = "ABCDE";
tea_arr[i].stu_arr[j].name = "student_";
tea_arr[i].stu_arr[j].name += name_stulist[j];
// 学生成绩,随机数,后面的51表示0-50之间的一个数。
int random = rand()%51 +50;
tea_arr[i].stu_arr[j].score = random;
}
}
}
void print(struct Teacher tea_arr[],int len)
{
for(int i=0;i<len;i++)
{
cout << "老师姓名:" << tea_arr[i].name << endl;
for(int j=0;j<5;j++)
{
cout << "所带学生姓名:" << tea_arr[i].stu_arr[j].name << ",分数:" << tea_arr[i].stu_arr[j].score << endl;
}
}
}
int main()
{
// 随机数种子
srand((unsigned int) time(NULL));
// 1、创建3名老师的数组
struct Teacher tea_arr[3];
///2、通过函数给3名老师赋值,并给老师带的学生赋值
int len = sizeof(tea_arr)/sizeof(tea_arr[0]);
assignment(tea_arr,len);
// 3、打印输出所有的老师及学生信息
print(tea_arr,len);
return 0;
}
案例2:设计一个英雄的结构体,包括:姓名、年龄、性别。
创建结构体数组,数组中存放5名英雄(自己定义)。
通过冒泡排序算法,将数组中的英雄按照年龄进行升序排序,并打印结果。
#include <iostream>
using namespace std;
#include <string>
struct Hero
{
string name;
int age;
string gender;
};
void bubble(struct Hero hero[],int len)
{
for(int i=0;i<len-1;i++)
{
for(int j=0;j<len-i-1;j++)
{
if(hero[j].age > hero[j+1].age)
{
struct Hero temp = hero[j];
hero[j] = hero[j+1];
hero[j+1] = temp;
}
}
}
}
void print(struct Hero hero[],int len)
{
for(int s=0;s<len;s++)
{
cout << "姓名:" << hero[s].name << ",年龄:" << hero[s].age << ",性别:" << hero[s].gender << endl;
}
}
int main()
{
struct Hero hero[5] = {{"刘备",23,"男"},{"关羽",22,"男"},{"张飞",20,"男"},{"赵云",21,"男"},{"貂蝉",19,"女"}};
int len = sizeof(hero)/sizeof(hero[0]);
bubble(hero,len);
print(hero,len);
return 0;
}