c++初识

文章目录

  • 1 c++初识
    • 1.1 变量
  • 2 数据类型
    • 2.1 整型
    • 2.2 sizeof关键字
    • 2.3 实型(浮点型)
    • 2.4 字符型
    • 2.5 字符串型
    • 2.6 布尔类型 bool
    • 2.7 数据的输入 cin
  • 3 运算符
    • 3.1 算术运算符
    • 3.2 赋值运算符
    • 3.3 比较运算符
    • 3.4 逻辑运算符
  • 4 程序流程结构
    • 4.1选择结构
      • 4.1.1 if 语句
        • 案例: 三只小猪称体重
      • 4.1.2 三目运算符
      • 4.1.3 switch 语句
    • 4.2 循环结构
      • 4.2.1 while 循环结构
        • 案例: 猜数字游戏
      • 4.2.2 do…while 循环语句
        • 案例: 水仙花数
      • 4.2.3 for 循环语句
        • 案例: 敲桌子
      • 4.2.4 嵌套循环
        • 案例: 乘法口诀表
    • 4.3 跳转语句
      • 4.3.1 break 语句
      • 4.3.2 continue 语句
      • 4.3.3 goto 语句
  • 5 数组
    • 5.1 概述
    • 5.2 一维数组
      • 5.2.1 定义方式
      • 5.2.2 一维数组数组名
        • 案例1: 找最大值
        • 案例2: 数组元素逆序
      • 5.2.3 冒泡排序
    • 5.3 二维数组
      • 5.3.1 定义方式
      • 5.3.2 二维数组数组名
      • 案例: 考试成绩统计
  • 6 函数
    • 6.1 函数的定义
    • 6.2 函数的调用
    • 6.3 值传递
    • 6.4 函数的常见样式
    • 6.5 函数的声明
    • 6.6 函数的分文件编写
  • 7 指针
    • 7.1 指针的基本概念
    • 7.2 指针变量的定义和使用
    • 7.3 指针所占内存空间
    • 7.4 空指针和野指针
    • 7.5 const 修饰指针
    • 7.6 指针和数组
    • 7.7 指针和函数
    • 7.8 指针、数组、函数
      • 案例:数组排序
  • 8 结构体
    • 8.1 结构体的定义和使用
    • 8.2 结构体数组
    • 8.3 结构体指针
    • 8.4 结构体嵌套结构体
      • 案例:老师辅导学员
    • 8.5 结构体作函数参数
    • 8.6 结构体中 const 使用场景
    • 8.7 案例
      • 案例1
      • 案例2

1 c++初识

1.1 变量

作用: 用于记录程序中不可更改的数据

格式:

  1. #define宏常量:#define 常量名 常量值
    通常在文件上方定义,表示一个常量

  2. const修饰的变量const 数据类型 常量名 = 常量值
    通常在变量定义前加关键字const,修饰该变量为常量,不可修改

#include 
using namespace std;

#define Day 7

int main()
{
	int a = 10;
	const int month = 12;
	//month = 24;  错误,const修饰的变量也称为常量
	
   	cout << "Hello !\n";  //Hello !
	cout << "Hello World !" << endl;  //Hello World !
	cout << "a = " << a << endl;  //a = 10
	cout << "一周总共有:" << Day << "天" << endl;  //一周总共有:7天
	cout << "一年总共有:" << month << "个月" << endl;  //一年总共有:12个月
   	
	system("pause");
	return 0;
}

2 数据类型

2.1 整型

数据类型 占用内存空间 取值范围
short(短整型) 2字节 (-2^15 ~ 2^15-1)(-32768 ~ 32767)
int(整型) 4字节 (-2^31 ~ 2^31-1)
long(长整型) windows:4字节,linux:32位4字节,64位8字节 (-2^31 ~ 2^31-1)
long long(长长整型) 8字节 (-2^63 ~ 2^63-1)
char ch = 'a';
cout << ch << "\t" << (int)ch << endl;  //字符型变量对应的ASCII编码

a	97

2.2 sizeof关键字

作用: 统计数据类型所占内存大小

语法:sizeof( 数据类型 / 变量名 )

2.3 实型(浮点型)

注意: 默认情况下,输出一个小数,会显示出 6 位有效数字

数据类型 占用内存空间 有效数字范围
float 4字节 7 位有效数字
double 8字节 15 ~ 16位有效数字
long long num1 = 10;
float f1 = 3.14f;  //默认双精度double,会多进行一步单精度的转换
double d1 = 3.1415926;

cout << "long long 类型所占内存空间为:" << sizeof(long long) << endl;
cout << "float sizeof = " << sizeof(f1) << endl;
cout << "f1 = " << f1 << endl;
cout << "d1 = " << d1 << endl;  //默认情况下,输出一个小数,会显示出6位有效数字

long long 类型所占内存空间为:8
float sizeof = 4
f1 = 3.14
d1 = 3.14159

2.4 字符型

注意: 字符型变量不是把字符本身放到内存中存储,而是将对应的ASCII编码放入到存储单元 A ~ Z( 65 ~ 90 ) a ~ z( 97 ~ 122 )

2.5 字符串型

  1. C :char 变量名[] = "字符串值"
  2. C++ :string 变量名 = "字符串值"
// C 风格
char str1[] = "Hello World !";
cout << "C 风格:" << str1 << endl;
// C++ 风格  #include 
string str2 = "Hello World !";
cout << "C++ 风格:" << str2 << endl;

2.6 布尔类型 bool

作用: 布尔数据类型代表真或假的值( true 真 : 非零的值都代表真 / false 假 : 0 )

bool 类型占 1 个字节大小

bool flag = true;
cout << flag << endl;  //1

flag = false;
cout << flag << endl;  //0
cout << "bool类型所占内存空间为:" << sizeof(bool) << endl;  //bool类型所占内存空间为:1

2.7 数据的输入 cin

作用: 从键盘获取数据

语法:cin >> 变量

int a;
float b;
char ch;
string str;
bool flag;

cout << "请输入所赋的值(int float char string bool):";
cin >> a >> b >> ch >> str >> flag;
cout << "a\tb\tch\tstr\tflag" <

3 运算符

3.1 算术运算符

注意:两个小数不可以做取余运算

+(正号) -(负号) %(取模/取余)
+(加) -(减) *(乘) /(除)
a++ a - - ++a - -b
cout << 10 % 20 << endl;  //10

//1. 前置递增
int a = 10;
++a;
cout << "a = " << a << endl;  //a = 11

//2. 后置递增
int b = 10;
b++;
cout << "b = " << b << endl;  //b = 11

//3. 区别:
//前置递增:先+1,再运算
int a1 = 10;
int b1 = ++a1 * 10;
cout << "a1 = " << a1 << endl;  //a1 = 11
cout << "b1 = " << b1 << endl;  //b1 = 110

//后置递增:先运算,再+1
int a2 = 10;
int b2 = a2++ * 10;
cout << "a2 = " << a2 << endl;  //a2 = 11
cout << "b2 = " << b2 << endl;  //b2 = 100

3.2 赋值运算符

= %=
+= -= *= /=

3.3 比较运算符

== !=
> < >= <=
int a = 10, b = 20;
cout << (a == b) << endl;  //0
cout << (a <= b) << endl;  //1

3.4 逻辑运算符

! 取反
&& 有 0 出 0 , 全 1 为 1
|| 有 1 出 1 , 全 0 出 0

4 程序流程结构

顺序结构 , 选择结构 , 循环结构

4.1选择结构

4.1.1 if 语句

形式:

  • 单行 if 语句

  • 多行 if 语句

  • 多条件 if 语句

  • 嵌套 if 语句

案例: 三只小猪称体重

//1. 创建三只小猪的体重
int num1 = 0;
int num2 = 0;
int num3 = 0;

//2. 用户输入三只小猪的体重
cout << "请输入小猪A的体重:";
cin >> num1;
cout << "请输入小猪B的体重:";
cin >> num2;
cout << "请输入小猪C的体重:";
cin >> num3;

//3. 判断哪只小猪最重
if(num1 > num2)  //A比B重
{
    if(num1 > num3)
        cout << "小猪A 最重!" << endl;  //A比C重
    else
        cout << "小猪C 最重!" << endl;  //C比A重
}
else  //B比A重
{
    if(num2 > num3)
        cout << "小猪B 最重!" << endl;  //B比C重
    else
        cout << "小猪C 最重!" << endl;  //C比B重
}

4.1.2 三目运算符

注意: 三目运算符返回的是变量,可以继续赋值!

int a = 10, b = 20, c;
c = a > b ? a : b;
cout << "c = " << c << endl;  //20

(a < b ? a : b) = 100;
cout << "a = " << a << endl;  //100
cout << "b = " << b << endl;  //20

4.1.3 switch 语句

int score;
cout << "请给电影进行打分:";
cin >> score;
switch(score)
{
case 10:
    cout << "您认为是经典电影!" << endl;
    break;  //退出当前分支
case 9:
    cout << "您认为电影非常好!" << endl;
    break;
case 8:
    cout << "您认为电影一般!" << endl;
    break;
default:
    cout << "您认为这是烂片!" << endl;
    break;
}

注意:

  1. switch 语句中表达式类型只能是整型或字符型 ;
  2. case 里如果没有 break , 程序会一直向下执行 .

总结: 与 if 语句相比, switch 语句的结构清晰,执行效率高 ; 缺点是 switch 语句不可以判断区间

4.2 循环结构

4.2.1 while 循环结构

语法 : while( 循环条件 ){ 循环语句 }
只要循环条件结果为真,则执行循环语句

注意: 在执行循环语句时, 程序必须提供跳出循环的出口, 否则出现死循环

案例: 猜数字游戏

#include 
#include  //time系统时间头文件包含
using namespace std;

int main()
{
	//添加随机数种子,利用当前系统时间生成随机数,防止每次随机数都一样
	srand((unsigned int)time(NULL));

	// 1. 系统生成随机数
	int num = rand() % 100 + 1;  // 生成 0+1 ~ 99+1 随机数

	// 2. 玩家进行猜测
	int val;
	while(1)
	{
		cout << "请输入猜测的数字:";
		cin >> val;

		// 3. 判断
		// 猜错,返回第二步
		if(val > num)
			cout << "猜测过大!" << endl;
		else if(val < num)
			cout << "猜测过小!" << endl;
		else
		{
			cout << "恭喜您猜对了!" << endl;
			cout << "系统生成的随机数是:" << num << endl;
			//猜对
			break;  //break ,可以利用该关键字退出当前循环
		}
	}

	system("pause");
	return 0;
}

4.2.2 do…while 循环语句

语法 :do{ 循环语句 } while( 循环条件 );

注意: 与 while 的区别在于, do…while 会先执行一次循环语句, 再判断循环条件

案例: 水仙花数

描述: 水仙花数是指一个3位数,它的每个位上的数字的3次幂之和等于它本身

例: 1^3 + 5^3 + 3^3 = 153

//1. 打印所有的三位数
int num = 100;
do
{
    //2. 从所有的三位数字中找到水仙花数
    int a = 0;
    int b = 0;
    int c = 0;

    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);

4.2.3 for 循环语句

语法 :for( 起始表达式; 条件表达式; 末尾循环体 ){ 循环语句 }

注意: for 循环中的表达式,要用分号进行分隔

总结: while , do…while , for 循环语句中 , for 循环结构比较清晰 , 比较常用

案例: 敲桌子

描述: 从1开始数到100 , 如果数字个位含有7 , 或数字十位含有7 , 或该数字是7的倍数 , 则打印敲桌子 , 其余数字直接打印输出.

//1. 输出1~100
for(int i = 1; i <= 100; i++)
{
    //2.找到特殊数字
    //是7的倍数,个位有7, 十位有7
    if(i % 7 == 0 || i % 10 == 7 || i / 10 == 7)
        cout << "敲桌子" << endl;
    else
        cout << i << endl;
}

4.2.4 嵌套循环

案例: 乘法口诀表

for(int i = 1; i <= 9; i++)  //行数
{
    for(int j = 1; j <= i ; j++)  //列数
        cout << j << "*" << i << "=" << j * i << "\t";
    cout << endl;
}

4.3 跳转语句

4.3.1 break 语句

作用: 用于跳出选择结构循环结构

break 使用的时机:

  • switch 条件语句中,作用是终止 case 并跳出 switch;
  • 循环语句中,作用是跳出当前的循环语句;
  • 嵌套语句中,作用是跳出最近的内层循环语句。

4.3.2 continue 语句

作用 :循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环

注意: continue 并没有使整个循环终止,而 break 会跳出循环

4.3.3 goto 语句

作用: 可以无条件跳转语句

语法:goto 标记

解释: 如果标记的名称存在,执行到 goto 语句时,会跳转到标记位置

注意: 在程序中不建议使用 goto 语句,以免造成程序流程混乱

5 数组

5.1 概述

数组:就是一个集合,里面存放了相同类型的数据元素

特点:

  1. 数组中的每个数据元素都是相同的数据类型

  2. 数组是由连续的内存位置组成的

5.2 一维数组

5.2.1 定义方式

一维数组定义的三种方式:

  1. 数据类型 数组名[ 数组长度 ];
  2. 数据类型 数组名[ 数组长度 ] = { 值1, 值2 ...};
  3. 数据类型 数组名[ ] = { 值1, 值2 ...};

注意: 定义数组时,必须有初始长度

总结:

  1. 数组名的命名规范与变量名命名规范一致,不要和变量重名

  2. 数组中下标是从 0 开始索引

5.2.2 一维数组数组名

  1. 可以统计整个数组在内存中的长度;
  2. 可以获取数组在内存中的首地址,即数组名即首地址

注意: 数组名是常量,不可以赋值

int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//可以通过数组名统计整个数组占用内存大小
cout << "每个元素占用内存空间为:" << sizeof(arr[0]) << endl;  //4
cout << "整个数组占用内存空间为:" << sizeof(arr) << endl;  //40
cout << "数组中元素个数为:" << sizeof(arr) / sizeof(arr[0]) << endl;  //10

//可以通过数组名查看数组首地址
cout << "数组首地址为:" << (int)arr << endl;  //7337696
cout << "数组中第一个元素地址为:" << (int)&arr[0] << endl;  //7337696
cout << "数组第二个元素地址为:" << (int)&arr[1] << endl;  //7337700

案例1: 找最大值

int arr[5] = { 300,350,200,400,390 };
int max = arr[0];
for(int i = 1; i < 5; i++)
{
    if(max < arr[i])
        max = arr[i];
}
cout << "最大值为:" << max << endl;

案例2: 数组元素逆序

int arr[5] = { 1,3,2,5,4 };
int j = sizeof(arr) / sizeof(arr[0]) - 1;  //j :末尾元素下标

cout << "数组元素逆序前:" << endl;
for(int i = 0; i < 5; i++)  //i :起始元素下标
    cout << arr[i] << " ";
cout << endl;

for(int temp, i = 0; i < j; i++, j--)
{
    temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

cout << "数组元素逆序后:" << endl;
for(int i = 0; i < 5; i++)
    cout << arr[i] << " ";
cout << endl;

5.2.3 冒泡排序

思路:

  1. 比较相邻的元素,如果第一个比第二个大,则交换;
  2. 对每一对相邻元素做同样的工作,执行完毕后,找到一个最大值;
  3. 重复以上步骤,每次比较次数 -1 ,直到不需要比较。

外层循环:排序总轮数 i = 元素个数 - 1

内层循环:每轮对比次数 j = 元素个数 - 当前排序轮数 - 1

int arr[] = { 4,2,8,0,5,7,1,3,6,9 };
int len = sizeof(arr) / sizeof(arr[0]);
cout << "排序前:" << endl;
for(int i = 0; i < len; i++)
    cout << arr[i] << " ";
cout << endl;
for(int i = 0; i < len - 1; i++)  //排序轮数:元素个数 - 1
{
    //内层循环对比
    for(int j = 0; j < len - i - 1; j++)  //对比次数:元素个数 - 当前轮数 i  - 1
    {
        //升序
        if(arr[j] > arr[j + 1])
        {
            int temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }
    }
}
cout << "排序后:" << endl;
for(int i = 0; i < len; i++)
    cout << arr[i] << " ";
cout << endl;

5.3 二维数组

5.3.1 定义方式

二维数组定义的四种方式:

  1. 数据类型 数组名 [ 行数 ][ 列数 ];
  2. 数据类型 数组名 [ 行数 ][ 列数 ] = { { 数据1, 数据2 },{ 数据3, 数据4 } };
  3. 数据类型 数组名 [ 行数 ][ 列数 ] = { 数据1, 数据2, 数据3, 数据4 };
  4. 数据类型 数组名 [ ][ 列数 ] = { 数据1, 数据2, 数据3, 数据4 };

建议:利用第二种更加直观,提高代码的可读性

5.3.2 二维数组数组名

  1. 可以查看二维数组所占内存空间;
  2. 获取二维数组首地址。
int arr[2][3] = { 1,2,3,4,5,6 };
//可以查看所占内存空间
cout << "二维数组所占内存空间:" << sizeof(arr) << endl;  //24
cout << "二维数组第一行所占内存空间:" << sizeof(arr[0]) << endl;  //12
cout << "二维数组第一个元素所占内存空间:" << sizeof(arr[0][0]) << endl;  //4
cout << "二维数组的行数:" << sizeof(arr) / sizeof(arr[0]) << "行" << endl;  //2行
cout << "二维数组的列数:" << sizeof(arr[0]) / sizeof(arr[0][0]) << "列" << endl;  //3列

//可以查看二维数组的首地址
cout << "二维数组的首地址:" << (int)arr << endl;  //11925672
cout << "二维数组第一行首地址:" << (int)arr[0] << endl;  //11925672
cout << "二维数组第二行首地址:" << (int)arr[1] << endl;  //11925684(+12)

cout << "二维数组第一个元素地址:" << (int)&arr[0][0] << endl;  //11925672
cout << "二维数组第二个元素地址:" << (int)&arr[0][1] << endl;  //11925676(+4)

案例: 考试成绩统计

string name[3] = { "张三","李四","王五" };
int score[3][3] = { {100,100,100},{90,50,100},{60,70,80} };

for(int i = 0; i < 3; i++)
{
    int sum = 0;
    cout << name[i] << "的分数:\t";
    for(int j = 0; j < 3; j++)
    {
        sum += score[i][j];
        cout << score[i][j] << "\t";
    }
    cout << "总分:" << sum << endl;
}

6 函数

6.1 函数的定义

语法:

返回值类型 函数名(参数列表)
{
	函数体语句
	
	return 表达式
} 

6.2 函数的调用

语法:函数名(参数)

//函数定义,两个数相加
int add(int num1, int num2)  //函数定义时,num1 和 num2 并没有真实数据,只是一个形式上的参数——形参
{
	int sum = num1 + num2;
	return sum;
}

int main()
{
	int a = 10, b = 20;
    //函数调用时,实参的值传给形参
	cout << add(a, b) << endl;  //实际参数——实参

	system("pause");
	return 0;
}

6.3 值传递

  • 所谓值传递,就是函数调用时,实参将数指传入给形参
  • 值传递时,如果形参发生改变,并不会影响实参

注意: 复制的一份数据!会造成空间浪费

void swap(int num1, int num2)
{
	cout << "交换前的数据:" << endl;
	cout << "num1 = " << num1 << " num2 = " << num2 << endl;  //num1 = 10 num2 = 20

	int temp = num1;
	num1 = num2;
	num2 = temp;

	cout << "交换后的数据:" << endl;
	cout << "num1 = " << num1 << " num2 = " << num2 << endl;  //num1 = 20 num2 = 10
}

int main()
{
	int a = 10, b = 20;
	cout << "交换前的数据:" << endl;
	cout << "a = " << a << " b = " << b << endl;  //a = 10 b = 20

	swap(a, b);
	cout << "交换后的数据:" << endl;
	cout << "a = " << a << " b = " << b << endl;  //a = 10 b = 20

	system("pause");
	return 0;
}

6.4 函数的常见样式

常见的函数样式有四种:

  1. 无参无返
  2. 有参无返
  3. 无参有返
  4. 有参有返
//1. 无参无返
void test01()
{
	cout << "无参无返 : This is test01 : Hello World !" << endl;
}

//2. 有参无返
void test02(int a)
{
	cout << "有参无返 : This is test02 : a = " << a << endl;
}

//3. 无参有返
int test03()
{
	cout << "无参有返 : This is test03 : ";
	return 100;
}

//4. 有参有返
int test04(int a)
{
	cout << "有参有返 : This is test04 : a = " << a << endl;
	return a;
}

int main()
{
    //无返
	test01();
	test02(100);
    //有返
	int num1 = test03();
	cout << "num1 = " << num1 << endl;
	int num2 = test04(1000);

	system("pause");
	return 0;
}

无参无返 : This is test01 : Hello World !
有参无返 : This is test02 : a = 100
无参有返 : This is test03 : num1 = 100
有参有返 : This is test04 : a = 1000

6.5 函数的声明

注意:函数的声明可以多次,但是函数的定义只能有一次

//函数的声明——可以写多次
int max(int a, int b);
int max(int a, int b);

int main()
{
	int a = 10, b = 20;
	cout << max(a, b) << endl;

	system("pause");
	return 0;
}

//定义:比较函数——只能有一次!
int max(int a, int b)
{
	return a > b ? a : b;
}

6.6 函数的分文件编写

函数分文件编写一般有四个步骤:

  1. 创建 .h 头文件;
  2. 创建 .cpp 源文件;
  3. 在头文件中写函数的声明;
  4. 再源文件中写函数的定义。
//swap.h文件
#include 
using namespace std;

//函数的声明
void swap(int a, int b);
//swap.cpp文件
#include"swap.h"

//函数的定义
void swap(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}

7 指针

7.1 指针的基本概念

作用: 可以通过指针间接访问内存

  • 内存编号是从 0 开始记录的,一般用十六进制数字表示
  • 可以利用指针变量保存地址

7.2 指针变量的定义和使用

语法:数据类型 * 变量名;

int a = 10;
int *p;  //定义
p = &a;  //赋值
cout << p << endl;  //p 的值,即 a 的地址 : 0056FC48
cout << *p << endl;  //操作指针变量指向的内存 *p,即 a 的值 : 10

7.3 指针所占内存空间

注意:
在32位( x86 )操作系统下,指针占4个字节空间大小,不管是什么数据类型

在64位( x64 )操作系统下,指针占8个字节空间大小

cout << "sizeof(char *) = " << sizeof(char *) << endl;  //4
cout << "sizeof(int *) = " << sizeof(int *) << endl;  //4
cout << "sizeof(float *) = " << sizeof(float *) << endl;  //4
cout << "sizeod(double *) = " << sizeof(double *) << endl;  //4

7.4 空指针和野指针

  • 空指针: 指针变量指向内存中编号为 0 的空间

用途: 初始化指针变量

注意: 空指针指向的内存是不可以访问的,0~255之间的内存编号是系统占用的

  • 野指针: 指针变量指向非法的内存空间
int *p1 = NULL;
//访问空指针报错 !
cout << *p1 << endl;

int *p2 = (int *)0x1100;
//访问野指针报错 !
cout << *p2 << endl;

总结: 空指针和野指针都不是我们申请的空间,因此不要访问

7.5 const 修饰指针

const 修饰指针有三种情况:

  1. const 修饰指针 —— 常量指针

    特点: 指针指向(指针的值)可以修改,但是指针指向的值不可修改。

  2. const 修饰常量 —— 指针常量

    特点: 指针指向(指针的值)不可以修改,但指针指向的值可以修改。

  3. const 既修饰指针,又修饰常量

    特点: 指针的指向和指针指向的值都不可以修改。

技巧:看 const 后面紧跟的是指针还是常量,是指针就是常量指针,是常量就是指针常量

int a = 10, b = 20;

//1. 修饰指针——指针指向(指针的值)可以修改,但是指针指向的值不可修改
const int *p1 = &a;
p1 = &b;  //正确
//*p1 = 20;  //错误

//2. 修饰常量——指针指向(指针的值)不可以修改,但指针指向的值可以修改
int * const p2 = &a;
*p2 = 100;  //正确
//p2 = &b;  //错误

//3. 既修饰指针,又修饰变量——指针的指向和指针指向的值都不可以修改
const int *const p3 = &a;
//*p3 = 100;  //错误
//p3 = &b;  //错误

7.6 指针和数组

作用: 利用指针访问数组中元素

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int *p1 = arr;  //arr 就是数组首地址
cout << "利用指针访问第一个元素:" << *p1 << endl;

p1++;  //让指针向后偏移 4 个字节
cout << "利用指针访问第二个元素:" << *p1 << endl;

cout << "利用指针遍历数组:" << endl;
int *p2 = arr;
for(int i = 0; i < 10; i++)
    cout << *(p2 + i) << " ";
cout << endl;

利用指针访问第一个元素:1
利用指针访问第二个元素:2
利用指针遍历数组:
1 2 3 4 5 6 7 8 9 10

7.7 指针和函数

作用: 利用指针作为函数参数,可以修改实参的值

注意: 指针只占 4 个字节,可以减少所占内存空间,而且不会复制出新的副本出来

void swap01(int num1, int num2)
{
	int temp = num1;
	num1 = num2;
	num2 = temp;
}

void swap02(int *p1,int *p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

int main()
{
	int a = 10, b = 20;
	//1. 值传递,不会改变实参的值,copy 了一份数据
	swap01(a, b);
	cout << "a = " << a << " , b = " << b << endl;  //a = 10 , b = 20

	//2. 地址传递,会改变实参
	swap02(&a, &b);
	cout << "a = " << a << " , b = " << b << endl;  //a = 20 , b = 10

	system("pause");
	return 0;
}

总结: 如果不需要修改实参,就用值传递,如果需要修改实参,就用地址传递

7.8 指针、数组、函数

案例:数组排序

描述: 封装一个函数,利用冒泡排序,实现对整型数组的升序排序

void sortArr(int *arr, int len);
void printArr(int *arr, int len);

int main()
{
	int arr[] = { 4,3,6,9,1,2,10,8,7,5 };
	int len = sizeof(arr) / sizeof(arr[0]);
	cout << "原数组:" << endl;
	printArr(arr, len);
	sortArr(arr, len);
	cout << "升序排序:" << endl;
	printArr(arr, len);

	system("pause");
	return 0;
}

//升序排序
void sortArr(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)
{
	int *p = arr;
	for(int i = 0; i < len; i++)
		cout << *(p + i) << " ";  // cout << arr[i] << " ";
	cout << endl;
}

8 结构体

8.1 结构体的定义和使用

基本概念: 结构体属于用户自定义的数据类型,允许用户存储不同的数据类型

语法:struct 结构体名 { 结构体成员列表 };

通过结构体创建变量的方式有三种:

  • struct 结构体名 变量名;
  • struct 结构体名 变量名 = { 成员1 , 成员2 ...};
  • 定义结构体时顺便创建变量。

总结:

  1. 定义结构体时的关键字是 struct ,不可以省略;

  2. 创建结构体变量时,关键字 struct 可以省略;

  3. 结构体变量利用操作符 “ . ” 访问成员。

//自定义数据类型,一些类型集合组成的一个类型
struct Student
{
	//成员列表
	string name;
	int age;
	int score;
}s3;

int main()
{
	Student s1;  //struct 关键字可以省略
	s1.name = "张三";
	s1.age = 18;
	s1.score = 90;
	cout << "姓名:" << s1.name << "\t年龄:" << s1.age << "\t分数:" << s1.score << endl;

	struct Student s2 = { "李四",20,95 };
	cout << "姓名:" << s2.name << "\t年龄:" << s2.age << "\t分数:" << s2.score << endl;

	s3.name = "王五";
	s3.age = 25;
	s3.score = 100;
	cout << "姓名:" << s3.name << "\t年龄:" << s3.age << "\t分数:" << s3.score << endl;

	system("pause");
	return 0;
}

姓名:张三      年龄:18        分数:90
姓名:李四      年龄:20        分数:95
姓名:王五      年龄:25        分数:100

8.2 结构体数组

作用: 将自定义的结构体放入到数组中方便维护

语法:struct 结构体名 数组名[元素个数] = { { },{ } ... { } };

struct student
{
	//成员列表
	string name;
	int age;
	int score;
};

int main()
{
	struct student stuArr[2] =
	{
		{"张三",18,80},
		{"李四",20,90},
	};
	stuArr[1].age = 25;
	stuArr[1].score = 95;
	cout << "通过数组访问结构体成员" << endl;
	cout << "姓名\t年龄\t分数" << endl;
	for(int i = 0; i < 2; i++)
		cout << stuArr[i].name << "\t" << stuArr[i].age << "\t" << stuArr[i].score << endl;

	system("pause");
	return 0;
}

通过数组访问结构体成员
姓名    年龄    分数
张三    18      80
李四    25      95

8.3 结构体指针

作用: 通过指针访问结构体中的成员

利用操作符 -> 可以通过结构体指针访问结构体属性

struct student
{
	//成员列表
	string name;
	int age;
	int score;
};

int main()
{
	cout << "通过指针访问结构体成员" << endl;
	struct student s1 = { "王五",30,100 };
	struct student *p = &s1;  //不能用 int ,s1 是 student 类型,所以应是 student 类型的指针
	cout << "姓名:" << p->name << "\t" << "年龄:" << p->age << "\t" << "分数:" << p->score << endl;

	system("pause");
	return 0;
}

通过指针访问结构体成员
姓名:王五      年龄:30        分数:100

8.4 结构体嵌套结构体

案例:老师辅导学员

描述: 每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体

struct student
{
	string name;
	int age;
	int score;
};

struct teacher
{
	int id;
	string name;
	int age;
	struct student stu;  //辅导的学生变量
};

int main()
{
	teacher t;
	t.id = 1001;
	t.name = "何老师";
	t.age = 22;
	t.stu.name = "静静";
	t.stu.age = 18;
	t.stu.score = 100;

	cout << ">>教师编号:" << t.id << "\t" << "姓名:" << t.name << "\t" << "年龄:" << t.age << endl
		 << "辅导的学生姓名:" << t.stu.name << "\t" << "年龄:" << t.stu.age << "\t" << "分数:" << t.stu.score << endl;

	system("pause");
	return 0;
}

8.5 结构体作函数参数

传递的方式有两种:

  • 值传递
  • 地址传递
struct student
{
	string name;
	int age;
	int score;
};

//值传递,形参的改变,不会影响实参
void printStudent01(struct student s)
{
	s.age = 100;
	cout << "子函数中:姓名:" << s.name << "\t" << "年龄:" << s.age << "\t" << "分数:" << s.score << endl;
}

//地址传递
void printStudent02(struct student *p)
{
	p->age = 200;
	cout << "子函数中:姓名:" << p->name << "\t" << "年龄:" << p->age << "\t" << "分数:" << p->score << endl;
}

int main()
{
	struct student s;
	s.name = "张三";
	s.age = 20;
	s.score = 90;
	cout << "值传递:" << endl;
	printStudent01(s);
	cout << "main函数中:姓名:" << s.name << "\t" << "年龄:" << s.age << "\t" << "分数:" << s.score << endl << endl;

	cout << "地址传递:" << endl;
	printStudent02(&s);
	cout << "main函数中:姓名:" << s.name << "\t" << "年龄:" << s.age << "\t" << "分数:" << s.score << endl;

	system("pause");
	return 0;
}

值传递:
子函数中:姓名:张三    年龄:100       分数:90
main函数中:姓名:张三  年龄:20        分数:90

地址传递:
子函数中:姓名:张三    年龄:200       分数:90
main函数中:姓名:张三  年龄:200       分数:90

8.6 结构体中 const 使用场景

作用:const 来防止误操作

struct student
{
	string name;
	int age;
	int score;
};

//改为指针可以节省空间,指针只占 4 个字节
void printStudent(const student *s)  //加入 const 防止函数体中的误操作
{
	//s->age = 100;  //报错,操作失败,因为加了const 修饰
	cout << "姓名:" << s->name << "\t" << "年龄:" << s->age << "\t" << "分数:" << s->score << endl;
}

int main()
{
	struct student s = { "张三",20,100 };
	printStudent(&s);

	system("pause");
	return 0;
}

8.7 案例

案例1

描述: 有三名老师,每名老师带五个学生,打印出老师数据和学生数据

注意:

  1. 老师姓名;
  2. 随机数种子。
#include 
#include 
using namespace std;

struct Student
{
	string s_name;
	int score;
};

struct Teacher
{
	string t_name;
	struct Student s_array[5];
};

void data(struct Teacher t_array[], int len)
{
	string nameSeed = "ABCDE";
	for(int i = 0; i < len; i++)
	{
       //老师姓名
		t_array[i].t_name = "teacher_";
		t_array[i].t_name += nameSeed[i];

		for(int j = 0; j < 5; j++)
		{
			//学生姓名
			t_array[i].s_array[j].s_name = "student_";
			t_array[i].s_array[j].s_name += nameSeed[j];

			//学生分数
			int random = rand() % 61 + 40;  //40~100
			t_array[i].s_array[j].score = random;
		}
	}
}

void printInfo(struct Teacher t_array[], int len)
{
	for(int i = 0; i < len; i++)
	{
		cout << ">>老师姓名:" << t_array[i].t_name << endl;
		for(int j = 0; j < 5; j++)
			cout << "\t学生姓名:" << t_array[i].s_array[j].s_name << " 考试分数:" << t_array[i].s_array[j].score << endl;
		cout << endl;
	}
}

int main()
{
	//随机数种子
	srand((unsigned int)time(NULL));  //头文件 #include 

	struct Teacher t_array[3];
	int len = sizeof(t_array) / sizeof(t_array[0]);
	data(t_array, len);
	printInfo(t_array, len);

	system("pause");
	return 0;
}

案例2

描述: 通过冒泡排序,将数组中的数据按照年龄进行升序排序,打印最终结果。

五组数据信息如下:

{"刘备", 23 ,"男"}
{"关羽", 22 ,"男"}
{"张飞", 20 ,"男"}
{"赵云", 21 ,"男"}
{"貂蝉", 19 ,"女"}
//1. 设计英雄结构体
struct Hero
{
	string name;
	int age;
	string sex;
};

void hero_Sort(struct Hero hero_array[], int len)
{
	for(int i = 0; i < len - 1; i++)
	{
		for(int j = 0; j < len - 1 - i; j++)
		{
			//如果 j 下标的元素年龄 大于 j+1 下标的元素的年龄,交换两个元素
			if(hero_array[j].age > hero_array[j + 1].age)
			{
				struct Hero temp = hero_array[j];
				hero_array[j] = hero_array[j + 1];
				hero_array[j + 1] = temp;
			}
		}
	}
}

void printHero(struct Hero hero_array[], int len)
{
	cout << "姓名\t年龄\t性别" << endl;
	for(int i = 0; i < len; i++)
		cout << hero_array[i].name << "\t" << hero_array[i].age << "\t" << hero_array[i].sex << endl;
}

int main()
{
	//2. 创建数组存放5名英雄
	struct Hero hero_array[5] =
	{
		{"刘备", 23 ,"男"},
		{"关羽", 22 ,"男"},
		{"张飞", 20 ,"男"},
		{"赵云", 21 ,"男"},
		{"貂蝉", 19 ,"女"},
	};
	int len = sizeof(hero_array) / sizeof(hero_array[0]);

	cout << ">>排序前:" << endl;
	printHero(hero_array, len);

	//3. 对数组进行排序,按照年龄进行升序排序
	hero_Sort(hero_array, len);

	//4. 将结果打印输出
	cout << ">>排序后:" << endl;
	printHero(hero_array, len);

	system("pause");
	return 0;
}

你可能感兴趣的:(笔记,c++)