C++基础笔记(包含函数、指针、结构体)—基于《黑马程序员》

※基础模块

1、命名规范

通用规则:标识符不可用关键字直接命名;标识符是由字母、数字、下划线构成;标识符第一个字符只可用字母或下划线;标识符区分大小写。(标识符是用来标识变量、函数、类、模块,或任何其他用户自定义项目的名称。)

  • 命名空间:以小写字母命名。
  • 类与结构:大写字母“C”开头 + 一个或多个单词。
  • 宏、枚举值:全部大写,且用下划线连接。
  • 函数
    – 函数的名称:由一个或多个单词组成,首字母大写。
    (函数名应当使用"动词"或者"动词+名词"(动宾词组)的形式。)
    – 保护成员函数:开头以一个下划线开头。
    – 私有成员函数:开头以两个下划线开头。
    – 虚函数:以“Do”开头。
    – 回调和事件处理函数:以“On”开头。
  • 变量、常量: 前缀 + 类型 + 一个或多个单词(一般是"名词"或"名词+形容词")。
  • 类型:类型名称的每个单词的首字母都大写,但是不包括下划线

2、注释

  • 单行注释:通常放在一行代码上方或语句末尾,对该行代码进行说明。 代码// 内容
  • 多行注释:通常放在一行代码上方,对该段代码进行说明。 代码/* 内容 */

3、输入输出

正常情况下,C++每个输入输出语句前需要加std::(例如输入的语句是std::cin>>内容;),但由于个人习惯(懒),喜欢使用命名空间 using namespace std;,这样后面的输入输出,就无需再进行添加std::,具体语法如下:

  • 输入cin >> 内容;
  • 输出cout << 内容;
  • 输入输出例子(不考虑异常,异常处理在后面讲)
    (这里末尾的endl是让输出(cout)的时候进行换行,不加也不影响结果。)
#include <iostream>
using namespace std;

int main()
{
    int number;
    cout << "请输入数字number:";
    cin >> number;
    cout << "您输入的数字为:" << number << endl;
}

4、变量

  • 作用:给一段指定的内存空间命名,
  • 语法数据类型 变量名 = 初始值;

5、常量

  • 作用:用来记录程序中不可更改的数据,
  • 语法
    1.#define宏常量:#define 常量名 常量值;,通常在文件上方定义,表示一个常量。
    2.const修饰的变量:const 数据类型 常量名 = 常量值;,修饰该变量为常量后,不可修改。

※数据类型

C++规定在创建一个变量或常量时,必须要指定出相应的数据类型,否则无法给变量分配内存。

1、整型

  • 作用:整型变量表示的是整数类型的数据。
    整型
    这里需要注意,取值范围指的是数值的范围,例如short取值范围就是:-32768~32767。
  • 可以发现整型大小比较:short < int <= long <= long long (long类型在不同操作系统占用空间不同)

2、sizeof关键字

  • 作用:利用sizeof关键字可以统计数据类型所占内存大小。
  • 语法sizeof(数据类型 / 变量);
  • 例子
#include <iostream>
using namespace std;

int main()
{
    int number = 20230112;
    cout << number << "所占内存为:" << sizeof(number) << endl;
}

sizeof

3、实型(浮点型)

  • 作用:用于表示小数。
    浮点型变量分为两种:1.单精度float。2.双精度double。
    在这里插入图片描述
    这里需要注意,有效数值范围指的是数值中出现数字的个数,而不是小数点后数字的个数,例如3.14的有效数字范围是3,而不是2。
  • 例子:由结果可以知道,输出的小数默认是6位有效数字。
#include <iostream>
using namespace std;
int main()
{

    float f1 = 3.1415926f;//末尾带f,是为了区分float,不带f,会被默认为double类型
    cout << "f1值为:" << f1 << endl;
    double d1 = 3.1415926;
    cout << "d1值为:" << d1 << endl;
}

浮点

  • 补充科学计数法
#include <iostream>
using namespace std;

int main()
{
    /*
      e后为正数a,则乘10的a次方
      e后为负数a,则乘0.1的a次方
    */

    double f1 = 2023e2;//2023*10^2 
    cout << "f1值为:" << f1 << endl;
    double f2 = 2023e-2;//2023*0.1^2
    cout << "f2值为:" << f2 << endl;
} 

科学计数法

4、字符型

  • 作用:字符型变量用于显示单个字符。
  • 语法char ch = 'x';
  • 注意
    –1.字符用单引号括起来,不是双引号。
    –2.单引号内只能有一个字符,不可以是字符串。
    –3.C和C++中字符型变量只占1个字节。
    –4.字符型变量不是将字符本身放到内存中存储,而是将对应的ASCII编码放入到存储单元。

以字符A举例,查看对应的ASCII码。

#include <iostream>
using namespace std;

int main()
{
    char ch = 'A';
    cout << "字符'A'对应的ASCII码为:" << (int)ch << endl;
}

查看A对应的ASCII码

  • 补充:ASCII码对照表。

    ASCII编码对照表

5、转义字符

  • 作用:用于表示一些不能显示出来的ASCII字符。
  • 补充:转义字符对应表如下图,其中加粗的为最常用的转义字符。
    转义字符表
    – 其中水平制表符 \t ,水平制的表占8个字节。如果有3个字符,则会生成5个空格,如果有4个字符,则会生成4个空格,例:
#include <iostream>
using namespace std;

int main() 
{
	cout << "aaa\t20230113\naaaa\t20230113";
}

水平制表符

6、字符串类型

  • 作用:用于表示一串字符。
  • 特点:string占32字节,不同库中占用大小可能不同,也有4、12、28、32字节,并且字符串所占空间是从堆中动态分配,与sizeof()无关。
  • 语法
    – 1.C语言风格:char 变量名[] = "字符串值";
    – 2.C++语言风格:string 变量名 = "字符串值";
#include <iostream>
using namespace std;

int main()
{
	//C风格字符串
	char str1[] = "20230113";
	cout << str1 << endl;
	//C++风格字符串
	string str2 = "20230113";//有时候这句会报错 需要加入头文件 #include<string>
	cout << str2 << endl;
}

字符串类型

7、布尔类型

  • 作用:用于表示真或假的值。
  • 补充:bool类型占1个字节,值分为:true–真(本质是1),false–假(本质是0)。
  • 例子
#include <iostream>
using namespace std;

int main()
{
	bool flag1 = true;
	bool flag2 = false;
	cout << "true值为:" << flag1 << "\nfalse值为:" << flag2 << endl;
}

布尔值

※运算符

  • 作用:用于执行代码的运算。
  • 介绍运算符

1、算术运算符

  • 作用:用于处理四则运算。
    算术运算符
  • 例子加减乘除取余
#include <iostream>
using namespace std;

int main()
{
	int number1 = 9;
	int number2 = 2;
	cout << number1 + number2 << endl;
	cout << number1 - number2 << endl;
	cout << number1 * number2 << endl;
	cout << number1 / number2 << endl;
	cout << number1 % number2 << endl;
}

算术运算符
需要注意“a / b”符号
– ①:若b为0,则分母为0,即报错;
– ②:若a,b都为整型,则结果也是整型,即整除运算(舍去小数部分),例 3 / 2 = 1 ,2 / 2 = 1 ;
– ③:若a为double类型,则结果为小数;
– ④:进阶小技巧

	使用setprecision(位数),可以四舍五入保留指定位数有效数字。
	cout << setprecision(4)<< 3.22474 <<endl;
	结果3.225
	
	cout.setf(ios::fixed); 
	cout << setprecision(4)<< 3.2 <<endl; //末尾保留或补足小数位数0 
	结果3.200
	
	cout.unsetf(ios::fixed);
	cout << setprecision(4)<< 3.200 <<endl;//不保留末尾0 
	结果3.2

需要注意“a % b”符号
– ①:若b为0,则分母为0,即报错;
– ②:若a,b都为整型,a > b,则结果为 a / b 的余数,a < b,则结果为 a
– ③:若a为double类型,则不可做取模运算;

  • 例子前置后置递增(递减同理)
#include <iostream>
using namespace std;

int main()
{
	
	int number1 = 1;
	number1++;//等价于 number = number + 1;
	cout << number1 << endl;//结果为2

	int number2 = 1;
	++number2;
	cout << number2 << endl;//结果为2

	//前置递增 先让变量+1 然后进行表达式运算
	int number3 = 1;
	int newNumber3 = ++number3 * 10;//相当于 2*10
	cout << newNumber3 << endl;//结果为20

	//后置递增 先进行表达式运算 后让变量+1
	int number4 = 1;
	int newNumber4 = number4++ * 10;//还是 1*10 运算后 number4才变成2
	cout << newNumber4 << endl;//结果为10
}

前置后置递增

2、赋值运算符

  • 作用:用于将表达式的值赋给变量。
    赋值运算符
  • 例子
#include <iostream>
using namespace std;

int main()
{
	int number1 = 0;
	number1 = 10;//将10赋值给number1
	number1 += 5;//等价于 number1 = number1 + 5;
	cout << number1 << endl;
	number1 -= 5;//等价于 number1 = number1 - 5;
	cout << number1 << endl;
	number1 *= 5;//等价于 number1 = number1 * 5;
	cout << number1 << endl;
	number1 /= 5;//等价于 number1 = number1 / 5;
	cout << number1 << endl;
	number1 %= 3;//等价于 number1 = number1 % 3;
	cout << number1 << endl;
}

赋值运算符例子

3、比较运算符

  • 作用:用于表达式的比较,并返回一个真值和假值。
    比较运算符
  • 例子
#include <iostream>
using namespace std;

int main()
{
	int number1 = 20;
	int number2 = 23;
	//中间加( )确定比较运算符的优先级
	cout << (number1 == number2) << endl; //a不等于b 所以为0
	cout << (number1 != number2) << endl;//a确实不等于b 所以为1
	cout << (number1 > number2) << endl;//a不小于b 所以为0 
	cout << (number1 < number2) << endl;//a的确小于b 所以为1
	cout << (number1 >= number2) << endl;//a不小于等于b 所以为0 
	cout << (number1 <= number2) << endl;//a的确小于等于b 所以为1
}

比较运算符例子

4、逻辑运算符

  • 作用:用于根据表达式的值返回真值或假值。
    逻辑运算符
  • 例子
#include <iostream>
using namespace std;

int main()
{
	int number1 = 2023;//在C++中 除了0都为真

	//逻辑运算符 非 ! 真变假 假变真
	cout << !number1 << endl;// 非1 即0
	cout << !!number1 << endl;// 非非1 即 非0 即1

	//逻辑运算符 与 && 真真为真 一假则假
	cout << (number1 && 0) << endl; // 一假为假 即0
	cout << (number1 && 1) << endl; // 真真为真 即1

	//逻辑运算符 或 || 假假为假 否则为真(一个为真就为真)
	cout << (0 || 0) << endl; // 假假为假 即0
	cout << (number1 || 0) << endl; // 一真为真 即1
}

逻辑运算符例子

※程序流程结构

1、选择结构

  • 作用:执行满足条件的语句。
  • 类型
    –1.单行格式if语句:if (条件) {条件满足执行的语句;}
    –2.多行格式if语句:if (条件) {条件满足执行的语句;} else {条件不满足执行的语句;}
    –3.多条件的if语句:if (条件1) {条件1满足执行的语句;} else if (条件2) {条件2满足执行的语句;} .... else {条件不满足执行的语句;}
    –4.三目运算符:条件 ? 条件满足执行的语句 : 条件不满足执行的语句
    –5.switch语句:switch (表达式) { case 结果1 : 执行语句 ; break; case 结果2 : 执行语句; break; ...default: 执行语句; break; }
  • 例子
    1.选出A、B、C中的最大值(以类型1-4,进行解答)。
#include <iostream>
using namespace std;

int main()
{
	int A, B, C;
	cout << "请输入A的数值:";
	cin >> A;
	cout << "请输入B的数值:";
	cin >> B;
	cout << "请输入C的数值:";
	cin >> C;

	// 使用if嵌套 (类型前3条的嵌套使用)
	if (A == B && B == C) // A=B=C 三者相等
	{
		cout << "A、B、C值相等,都为最大值!" << endl;
	}
	else // A、B、C不同时相等
	{
		if (A > B) // A>B
		{
			if (A > C) // A>C A最大值
			{
				cout << "A为最大值!" << endl;
			}
			else if (A < C) // A<C C是最大值
			{
				cout << "C为最大值!" << endl;
			}
			else // A=C 并列最大值
			{
				cout << "A和C都是最大值!" << endl;
			}
		}
		else   // A≤B
		{
			if (A == B) // A=B和C比较
			{
				// 使用三目运算符 (类型第4条的嵌套使用)
				cout << (B > C ? "A和B都是最大值!" : "C是最大值!") << endl;
			}
			else // A≠B 取最大值B与C进行比较
			{
				if (B == C) // B=C 并列最大值
				{
					cout << "B和C都是最大值!" << endl;
				}
				else // B≠C 
				{
					cout << (B > C ? "B为最大值!" : "C是最大值!") << endl;
				}
			}
		}
	}
}

选择例题2

  • 补充:三目运算符也可以赋值 例:在整型abcd中,若 (a<b ? c:d)=100,当a的确小于b时,将执行c,此时变量c将被赋值成为100。
    2.给学习态度打分(以类型5,进行解答)。
#include <iostream>
using namespace std;

int main()
{
	int score;
	cout << "请给您的学习状态打分(请输入1-3之间的整数):";
	cin >> score;
	switch (score)// 这个括号里只能输入整型或字符型,不可以是区间
	{
	case 1: // 输入的数据为1时执行下面语句
		cout << "一般般。" << endl;
		break;// 退出当前分支,若没有break,则会执行下一条语句
	case 2:
		cout << "适中吧。" << endl;
		break;
	case 3:
		cout << "很完美。" << endl;
		break;
	default:// 输入其他数据执行下面语句
		cout << "布吉岛。" << endl;
		break;
	}
}

选择例题2

2、循环结构

  • 作用:满足循环套件,执行循环语句。
  • 类型
    –1.while循环语句:while (循环条件) { 循环语句; }
    –2.dowhile循环语句:do { 循环语句; } while (循环条件); ,dowhile先执行一次在进行循环判定。
    –3.for循环语句:for (变量表达式;条件表达式;末尾循环体) { 循环语句; }
  • 例子
    1.猜1-100随机数游戏(while循环)。
#include <iostream>
using namespace std;

int main()
{
	srand((unsigned int)time(NULL));//添加随机数种子 利用当前时间产生随机数,防止每次随机数一样
	int number = rand() % 100 + 1;// rand()%100是产生0-99的随机数,所以+1变成1-100
	int key = 0;// 玩家输入的数值
	while (true)// 满足while()括号中的语句才会循环,这里利用true无限循环
	{
		cout << "请输入1-100的整数:";
		cin >> key;
		if (key > number)
		{
			cout << "您输入的数字太大啦!\n" << endl;
		}
		else if (key < number)
		{
			cout << "您输入的数字太小啦!\n" << endl;
		}
		else
		{
			cout << "恭喜您猜对啦!!!" << endl;
			break;// 跳出当前循环
		}
	}
}

猜数字例子

  • 补充:若添加随机数种子时,time报错 可以在头文件中添加 #include <ctime>
    2.水仙花数(do…while循环)。
#include <iostream>
using namespace std;

int main()
{
	// 水仙花数是指一个3位数,它的每个位上的数字的3次方之和等于他本身
	int a, b, c; // 用来代替三位数的百位、十位、个位
	int number = 100; // 三位数即 100 - 999
	cout << "水仙花数为:" << endl;
	do
	{
		a = number / 100; // 百位
		b = number / 10 % 10; // 十位
		c = number % 10; // 个位
		if (number == a * a * a + b * b * b + c * c * c) // 判定条件
		{
			cout << number << endl;
		}
		number++;
	} while (number < 1000);
}

水仙花数例子
3.敲桌子游戏(for循环)。

#include <iostream>
using namespace std;

int main()
{
	//从编号1-100内,选出十位、个位为7和7的倍数的编号,进行敲桌子。
	cout << "敲桌子的编号为:" << endl;
	for (int i = 1; i <= 100; i++)
	{
		if (i / 10 == 7 || i % 10 == 7 || i % 7 == 0)
		{
			cout << i << endl;
		}
	}
}

敲桌子例子

3、跳转语句

  • 类型

–1.break语句:用于跳出选择结构或者循环结构。

使用时机:
1.出现在switch语句中,作用是终止case并跳出switch。
2.出现在循环语句中,作用是跳出当前的循环语句。
3.出现在嵌套循环中,作用是跳出最近的内层循环语句。
(↑上文中出现过例子,不再进行举例。)

–2.continue语句:在循环语句中,跳过本次循环,执行下次循环。

#include <iostream>
using namespace std;

int main()
{
	for (int i = 0; i < 10; i++)
	{
		if (i == 5)//当i为5时,跳过本次循环,即不输出5
		{
			continue;
		}
		cout << i << " ";
	}
	cout << endl;
}

continue例子
–3.goto语句:可以无条件跳转语句。语法:goto 标记;
如果标记的名称存在,则在执行到goto语句时,会跳转到标记的位置。

#include <iostream>
using namespace std;

int main()
{
	cout << "1" << endl;
	cout << "2" << endl;
	goto FLAG; // 标记名一般命名为全大写。
	cout << "3" << endl;
FLAG: // 执行到上方goto语句时,将跳到这里的指定标记处 即跳过"3"的输出。
	cout << "4" << endl;
}

goto语句例子

※数组

  • 概述:一个存放相同类型的数据元素集合。
  • 特点:1.数组每个数据元素的数据类型相同。2.数组是由连续的内存位置组成。

1、一维数组定义

  • 定义
    –1.数据类型 数据名[ 数组长度 ];
    –2.数据类型 数据名[ 数组长度 ] = { 值1,值2.... };
    –3.数据类型 数据名[ ] = { 值1,值2.... };
  • 例子
 #include <iostream>
using namespace std;

int main()
{
	// 1、数据类型 数据名[ 数组长度 ];
	int arr1[3];
	arr1[0] = 0;
	arr1[1] = 1;
	arr1[2] = 2;
	cout << arr1[1] << endl;

	// 2、数据类型 数据名[数组长度] = { 值1,值2.... }; 
	int arr2[3] = { 0,1 }; 
	for (int i = 0; i < 3; i++)
	{
		cout << arr2[i] << endl; // 若数组中元素个数小于数组长度,则剩下的位置会被0填补。
	}

	// 3、数据类型 数据名[] = { 值1,值2.... }; 
	int arr3[] = { 1,0 }; // 数组个数未填写时,数组会自己检测数组个数,即2个。
	for (int i = 0; i < sizeof(arr3) / sizeof(arr3[0]); i++) //end(arr3)-begin(arr3)也可以计算数组arr3的长度
	{
		cout << arr3[i] << endl;
	}
}

一维数组例子

2、一维数组数组名

  • 用途
    – 1.统计整个数组在内存的长度。sizeof( arr );
    – 2.统计第一个元素在内存的长度。sizeof( arr[0] );
    – 3.获取数组的元素个数。sizeof( arr ) / sizeof( arr[0] );
    – 4.获取数组在内存中的首地址。cout << arr << endl;
    – 5.获取数组在内存中首地址的十进制。cout << (int) arr << endl;
    – 6.获取元素在内存中的首地址。cout << &arr[0] << endl;
  • 补充
    – 1.取元素在内存中的地址,需要使用取址符&,获取地址。
    – 2.数组名是常数,无法直接赋值。
  • 例子:将数组元素倒置,例1,2,3,4,5倒置变成5,4,3,2,1。
#include <iostream>
using namespace std;

int main()
{
	/*
		思路:1、2、3、4倒置,只需要将1,4对换,2,3对换即可,
			 即第一位与倒数第一位,第二位与倒数第二位交换...第n位与倒数第n位交换。
			 当第n位的下标,大于等于倒数第n位的下标时,交换完毕,停止交换。
	*/
	int arr[] = { 1,5,3,2,4 };
	int temp = 0; // 用来做临时储存数组元素的容器
	int length = sizeof(arr) / sizeof(arr[0]); // 数组元素的个数
	int start = 0; // 倒置时做临时初始下标(倒置操作前者)
	int end = length - 1; // 倒置时做临时末尾下标(倒置操作后者)
	cout << "原数组为:";
	for (int i = 0; i < length; i++) // 打印原数组 
	{
		cout << arr[i] << " ";
	}
	cout << "\n倒置后的数组为:";

	while (start < end) // 将数组倒置
	{
		temp = arr[end]; // 临时容器记录正在进行倒置操作的后者
		arr[end] = arr[start]; // 将数组准备倒置的前者赋值给后者
		arr[start] = temp; // 将临时容器记录的值 给数组准备倒置的前者
		start++; // 将数组准备倒置的前者向后移动一位
		end--; // 将数组准备倒置的后者向前移动一位
	}

	for (int i = 0; i < length; i++) // 和上面打印数组一样 (其实数组打印的语法重复,写成方法调用更好)
	{
		cout << arr[i] << " ";
	}
}

数组倒置元素例子

  • 难·例子:利用冒泡排序给已知数组元素升序。
#include<iostream>
using namespace std;

int main()
{
    /*
        思路:冒泡排序原理,是比较相邻的元素。如果第一个比第二个大,就交换它们两个。
			  对每一对相邻的元素进行同样的工作,执行完毕后,找到第一个最大值。
			  随后对剩下的元素,重复以上的步骤,每次比较次数-1﹐直至排列完成,不需要比较。
    */
    int arr[] = { 4,2,8,7,9,1,6,3,5 };
    int temp = 0; // 用来做临时储存数组元素的容器
    int length = sizeof(arr) / sizeof(arr[0]); // 数组元素的个数
    int start = 0; // 倒置时做临时初始下标(倒置操作前者)
    int end = 1; // 倒置时做临时末尾下标(倒置操作后者)
    cout << "冒泡排序前的数据为:";
    for (int i = 0; i < length; i++) {
        cout << arr[i] << " ";
    }

    for (int i = 1; i < length; i++) // 元素共需进行n-1次冒泡排序 得出结果
    {
        for (int j = 0; j < 9 - i; j++) // 第n次排序进行9-n次交换
        {
            if (arr[start] >= arr[end]) // 若前面元素的大于等于后面元素,则发生交换
            {
                temp = arr[start];
                arr[start] = arr[end];
                arr[end] = temp;
            }
            start++;
            end++; // 将需要交换的元素下标下移
        }
        start = 0;
        end = 1; // 将记录元素临时下标初始化
    }

    cout << "\n冒泡排序后的数据为:";
    for (int i = 0; i < 9; i++) {
        cout << arr[i] << " ";
    }
}

冒泡排序例子

3、二维数组定义

  • 类型
    – 1.数据类型 数据名 [ 行数 ] [ 列数 ];
    – 2.数据类型 数据名 [ 行数 ] [ 列数 ] = { {数据1 , 数据2} , {数据3 , 数据4} };
    – 3.数据类型 数据名 [ 行数 ] [ 列数 ] = { 数据1 , 数据2 , 数据3 , 数据4 };
    – 4.数据类型 数据名 [ ] [ 列数 ] = { 数据1 , 数据2 , 数据3 , 数据4 };
  • 例子
#include<iostream>
using namespace std;

//每次打印太麻烦,写个方法调用,后面会写章《C++高级篇文章》讲解 
void print(int arr[2][3]) 
{
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << arr[i][j] << " ";
		}
		cout << endl;
	}
}

int main()
{
	//数据类型 数据名 [ 行数 ] [ 列数 ];
	int arr1[2][3];
	arr1[0][0] = 1;
	arr1[0][1] = 2;
	arr1[0][2] = 3;
	arr1[1][0] = 4;
	arr1[1][1] = 5;
	arr1[1][2] = 6;
	print(arr1);

	//数据类型 数据名 [ 行数 ] [ 列数 ] = { {数据1 , 数据2} , {数据3 , 数据4} };
	int arr2[2][3] = { {1,2,3},{4,5,6} };
	print(arr2);

	//数据类型 数据名 [ 行数 ] [ 列数 ] = { 数据1 , 数据2 , 数据3 , 数据4 };
	int arr3[2][3] = { 1,2,3,4,5,6 };
	print(arr3);

	//数据类型 数据名[][列数] = { 数据1 , 数据2 , 数据3 , 数据4 };
	int arr4[][3] = { 1,2,3,4,5,6 };
	print(arr4);
}

二维数组定义

4、二维数组数组名

  • 用途
    – 1.查看二维数组所占内存空间。sizeof( arr );
    – 2.查看二维数组第一行所占内存空间。sizeof( arr[0] );
    – 3.查看二维数组第一个元素所占内存空间。sizeof( arr[0][0] );
    – 4.查看二维数组行数。sizeof( arr ) / sizeof( arr[0] );
    – 5.查看二维数组列数。sizeof( arr[0] ) / sizeof( arr[0][0] );
    – 5.查看二维数组元素个数。sizeof( arr ) / sizeof( arr[0][0] );
    – 6.获取二维数组首地址。cout << arr << endl;
    – 7.获取二维数组首地址的十进制。cout << (int) arr << endl;
    – 8.获取二维数组第一行的首地址。cout << arr[0] << endl;
    – 9.获取二维数组第一个元素的首地址。cout << &arr[0][0] << endl;
  • 例子
    二维数组例子题
#include<iostream>
using namespace std;

int main()
{
	int score[][3] = { {100,100,100} ,{90,50,100} ,{60,70,80} };//创建学生成绩数组
	int sum = 0;
	int tempScore[3];
	for (int i = 0; i < (sizeof(score) / sizeof(score[0])); i++)
	{
		for (int j = 0; j < (sizeof(score[0]) / sizeof(score[0][0])); j++)
		{
			sum += score[i][j];//得到每一行之和
		}
		tempScore[i] = sum;
		sum = 0;//初始化sum
	}
	cout << "张三总成绩为:" << tempScore[0] << endl;
	cout << "李四总成绩为:" << tempScore[1] << endl;
	cout << "王五总成绩为:" << tempScore[2] << endl;
}

二维数组例子

※函数

  • 概述:将一段经常使用的代码封装起来,减少重复代码。
  • 补充:一个较大的程序,一般分为若干个程序块,每个模块实现特定的你功能。

1、函数定义

  • 函数的定义一般主要有5个步骤:
    – 1、返回值类型
    – 2、函数名
    – 3、参数表列
    – 4、函数体语句
    – 5、return 表达式
  • 语法
返回值类型 函数名 (参数列表)
{
		函数体语句
		return 表达式
}

2、函数调用

使用定义好的函数。

  • 语法函数名 (参数)
  • 例子:调用求两数之和的函数
#include<iostream>
using namespace std;

int sum(int num1, int num2)//num1,num2没有真实数据,是个形参
{
	int sum = num1 + num2;
	return sum;
}

int main()
{
	int a = 2022;//a,b是真实存在的,是实参
	int b = 1;
	cout << sum(a, b) << endl;
}

函数调用例子

3、值传递

值传递就是在函数调用时实参将数值传给形参,值传递时,如果形参发生改变,不会影响实参。

  • 例子:交换两数值,改变形参时,实参不发生改变。
#include<iostream>
using namespace std;

//函数不需要返回值,声明时可以使用void
void swap(int num1, int num2)//num1,num2没有真实数据,是个形参
{
	int temp = num1;
	num1 = num2;
	num2 = temp;
	cout << "形参交换后:a=" << num1 << ",b=" << num2 << endl;
	//返回值不需要时,可以不写return
}

int main()
{
	int a = 2022;//a,b是真实存在的,是实参
	int b = 2023;
	cout << "实参交换前:a=" << a << ",b=" << b << endl;
	swap(a, b);
	cout << "实参交换后:a=" << a << ",b=" << b << endl;
}

值传递例子

4、函数声明

  • 作用:告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
  • 注意:函数的声明可以多次,但是函数的定义只能有一次!
  • 例子
#include<iostream>
using namespace std;

void swap(int num1, int num2);//函数声明,不写函数体,(可以写多个声明)

int main()
{
	int a = 2022;//a,b是真实存在的,是实参
	int b = 2023;
	swap(a, b);//调用函数,若前面没有声明函数,运行时会报错
}

void swap(int num1, int num2)//在调用函数后面写函数的话,要提前声明,不然报错(只能有一个定义)
{
	int temp = num1;
	num1 = num2;
	num2 = temp;
	cout << "交换后:a=" << num1 << ",b=" << num2 << endl;
}

函数声明例子

5、函数分文件编写

  • 作用:让代码结构更清晰。
  • 步骤
    – 1.创建后缀名为.h的头文件,在头文件中写函数的声明。(记得引用C++必带内容)
    – 2.创建后缀名为.cpp的源文件,在源文件中写函数的定义。(记得引用步骤1中定义的头文件)
    – 3.在需要使用相关函数的源文件中,引用步骤1中的头文件,即可使用头文件声明过的函数。
  • 例子:以上节的两数交换函数为例,分文件编写。

1.在头文件中创建swap.h头文件,并在头文件中写swap函数的声明。
(函数可以写多个的,这里只是用swap命名,用其他命名和其他函数均不影响结果。)

#include<iostream> //这两行是C++必带内容
using namespace std;

void swap(int num1, int num2);//函数声明

2.在源文件中创建swap.cpp源文件,并在源文件中写swap函数的定义。

#include "swap.h";// " " 代表自定义的头文件,引用之后,对应的源文件和头文件建立联系

void swap(int num1, int num2)//这里写了声明过的函数定义
{
	int temp = num1;
	num1 = num2;
	num2 = temp;
	cout << "交换后:a=" << num1 << ",b=" << num2 << endl;
}

3.在要使用相关函数的源文件中,引用头文件后,直接调用声明过的函数。

#include<iostream>
#include "swap.h"; //引用自定义的头文件 下面可以直接调用头文件中声明过的相关函数
using namespace std;

int main()
{	
	int a = 2022;
	int b = 2023; 
	swap(a, b);//直接使用被定义过的函数
}

函数分文件编写例子

※指针

  • 作用:通过指针可以间接访问内存。
  • 补充
    – 1. 内存编号是从0开始记录的,一般用十六进制数字表示。
    – 2. 可以利用指针变量保存地址。

1、指针变量的定义和使用

  • 指针变量定义语法数据类型 * 变量名p;
  • 指针指向变量a地址变量名p = & 变量名a; (指针p,代表变量a的地址)
  • 指针修改变量a的值* 变量名p = 数值; (“ *指针”是解引用,代表指针指向地址中的值,即变量a的值)
  • 例子
#include<iostream>
using namespace std;

int main()
{	
	int a = 2022;
	int* p; //定义指针变量p
	p = &a; //让指针p记录a的地址
	//上面两行,等价于 int* p = &a;
	cout << "a的地址为:" << p << endl; // 此时指针p为a的地址
	*p = 2023;// *p表示解引用 ,即指针p指向内存中的数据(变量a的数据)
	cout << "a的值为:" << a << endl;// 此时变量a的值,已通过指针解引用修改
}

指针例子

2、指针所占的内存空间

  • 32位系统:所有数据类型都是占4个字节。
  • 64位系统:所有数据类型都是占8个字节。
  • 想查看时候的语法cout << sizeof(int *) << endl;
    或者cout << sizeof(p) << endl; (前提是指针名为p,即定义 int * p;)

3、空指针

  • 定义:指针变量指向内存中编号为0的空间。
  • 用途:初始化指针变量。
  • 注意:空指针指向的内存是不可以访问的。
    (0~255之间的内存编号是系统占用的,因此不可以访问。)
  • 语法int * p = NULL;

4、野指针

  • 定义:指针变量指向非法的内存空间。
  • 注意:程序中要避免出现这种情况。
  • 语法int * p = (int *) 0x1100;(这里0x1100只是随便输入的,未被申请的地址例子。)

5、const修饰指针

  • const修饰指针有三种情况
    1. const修饰指针。 ——常量指针
    语法:const int * p = &a;
    特点:指针指向可以修改(可以指向其他地址,例p = &b),但是不可以修改指针指向的值。
    2. const修饰常量。 ——指针常量
    语法:int * const p = &a;
    特点:指针指向不可以修改,但是可以修改指针指向的值(例 * p=2023)。
    3. const即修饰指针,又修饰常量。
    语法:const int const * p = &a;
    特点:指针指向以及指针指向的值,都不可修改。
  • 例子
#include<iostream>
using namespace std;

int main()
{
	int a = 2022;
	int b = 2023;

	const int* p1 = &a;//常量指针
	cout << "p1指针指向a地址的值为:" << *p1 << endl;
	p1 = &b;//指针指向可以修改,但不能修改指针指向的值
	cout << "p1修改指针指向b地址的值后为:" << *p1 << endl << endl;

	int* const p2 = &a;//指针常量
	cout << "p2指针指向a地址的值为:" << *p2 << endl;
	*p2 = 2024;//指针指向不可以修改,但是可以修改指针指向的值
	cout << "修改p2指针所指向的a地址值后为:" << *p2 << endl << endl;

	const int* const p3 = &a;//const修饰指针,又修饰常量
	cout << "p3指针的指向和指向的值都不可修改,均为a地址的值:" << *p3 << endl;
}

const指针例子

6、指针和数组

  • 作用:利用指针访问数组元素。
  • 例子
#include<iostream>
using namespace std;

int main()
{
	int arr[] = { 1,2,3,4 };
	int* p = arr;//令指针指向arr,arr就是数组的首地址
	for (int i = 1; i < 5; i++) {
		cout << "数组第" << i << "个元素为:" << *p << endl;
		p++;//让指针向后偏移4个字节 (int是4个字节,其他类型就偏移对应个字节)
	}
}

指针和数组例子

7、指针和函数

  • 作用:利用指针作函数参数,可以修改实参的值。
  • 例子
#include<iostream>
using namespace std;

void swap(int* p1, int* p2)//用指针作形参
{
	int temp = *p1;
	*p1 = *p2;//指针p1指向的地址里的值,已被修改成了指针p2指向地址里的值
	*p2 = temp;
}

int main()
{
	int a = 2022;
	int b = 2023;
	cout << "交换前,a的值为:" << a << " ,b的值为:" << b << endl;
	swap(&a, &b);//函数应填实参的地址
	cout << "交换后,a的值为:" << a << " ,b的值为:" << b << endl;
}

指针和函数例子

  • 难·例子:利用冒泡排序给已知数组元素升序。
#include<iostream>
using namespace std;

void bubbleSort(int* arr, int length)//用指针作形参 传过来的是arr数组的首地址 函数里可以当数组直接用
{
	int temp = 0;
	for (int i = 1; i < length; i++) //冒泡排序(长度-1)轮
	{
		for (int j = 0; j < length - i; j++) //第i轮 交换(长度-i)次元素
		{
			if (arr[j] > arr[j + 1]) //如果 前者>后者 交换位置
			{
				temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}

void printArray(int* arr, int length)//打印数组
{
	for (int i = 0; i < length; i++)
	{
		cout << arr[i] << " ";
	}
}

int main()
{
	int arr[] = { 7,2,4,9,1,5,8,0,6,3 };
	int length = sizeof(arr) / sizeof(arr[0]);
	cout << "原数组为:";
	printArray(arr, length);
	bubbleSort(arr, length);
	cout << "\n冒泡排序后,数组为:";
	printArray(arr, length);
}

指针冒泡排序例子

※结构体

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

1、结构体定义和使用

  • 创建结构体(类)语法struct 结构体名(数据类型) { 结构体成员列表 };
  • 通过结构体创建变量的方式有三种
    – 1. struct 结构体名 变量名
    – 2. struct 结构体名 变量名 = { 成员1值 , 成员2值.... }
    – 3. 定义结构体时顺便创建变量
  • 例子
#include<iostream>
using namespace std;

struct Student // 创建学生数据类型
{
	//成员列表
	string name;
	int age, score;
}s3; // 带这个s3,是第三种创建变量方式:(定义结构体时顺便创建变量),在main函数里直接引用赋值就行

int main()
{
	// 第一种创建变量方式:(struct 结构体名 变量名),在给变量赋值
	struct Student s1;
	s1.name = "摸鱼王";
	s1.age = 20;
	s1.score = 100;
	cout << "姓名:" << s1.name << " 年龄:" << s1.age << " 分数:" << s1.score << endl;

	// 第二种创建变量方式:(struct 结构体名 变量名 = { 成员1值 , 成员2值.... })
	struct Student s2 = {"无敌停",23,100};// 这个元素不填写完整可能会报错
	cout << "姓名:" << s2.name << " 年龄:" << s2.age << " 分数:" << s2.score << endl;

	// 第三种,看创建学生类的结构体末端注释。
	s3.name = "暴龙兽";
	s3.age = 99;
	s3.score = 100;
	cout << "姓名:" << s3.name << " 年龄:" << s3.age << " 分数:" << s3.score << endl;
}

结构体定义例子

  • 补充
    – 1. 输出时,若s1.name(输出string类型)报错,加头文件#include <string>即可。
    – 2. 在结构体创建变量时,struct关键字可以省略,但在创建结构体时不可省略。

2、结构体数组

  • 作用:将自定义的结构体放入到数组中方便维护。
  • 语法struct 结构体名 数组名[ 元素个数 ] = { {} , {} ...{} }
  • 例子
#include<iostream>
using namespace std;

struct Student // 创建学生数据类型
{
	string name;
	int age, score;
};

int main()
{
	// 创建结构体数组
	struct Student stuArray[] = { {"摸鱼王",20,100},{"无敌停",23,100},{"暴龙兽",99,100} };

	// 给结构体数组中的元素,某一项赋值
	stuArray[2].name = "摸鱼停";

	// 遍历
	for (int i = 0; i < sizeof(stuArray) / sizeof(stuArray[0]); i++)
	{
		cout << "姓名:" << stuArray[i].name << " 年龄:" << stuArray[i].age << " 分数:" << stuArray[i].score << endl;
	}
}

结构体数组例子

3、结构体指针

  • 作用:通过指针访问结构体中的成员。
  • 语法:利用操作符->,可以通过结构体指针访问结构体属性。
  • 例子
#include<iostream>
using namespace std;

struct Student // 创建学生数据类型
{
	string name;
	int age, score;
};

int main()
{
	// 创建结构体变量
	Student stu1 = { "摸鱼王",20,100 };

	// 通过指针指向结构体变量
	Student* p = &stu1;

	//通过指针访问结构体变量中的数据
	cout << "姓名:" << p->name << " 年龄:" << p->age << " 分数:" << p->score << endl;
}

结构体指针例子

4、结构体嵌套结构体

  • 作用:结构体中的成员可以是另一个结构体。
  • 例如:每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体。
  • 例子
#include<iostream>
using namespace std;

struct Student // 创建学生数据类型
{
	string name;
	int age, score;
};

struct Teacher // 创建教师数据类型
{
	string name;
	int age;
	Student stu;// 子结构体 学生
};

int main()
{
	Teacher teacher = {"摸鱼王",50,"停停",22,100};
	//调用子结构的变量 (结构变量名.子结构变量名.子结构成员变量名)
	cout << "教师姓名:" << teacher.name << " 教师年龄:" << teacher.age << " 辅导学生:" << teacher.stu.name 
		<< " 学生年龄:" << teacher.stu.age << " 学生分数:" << teacher.stu.score << endl;
}

结构体嵌套结构体例子

5、结构体做函数参数

  • 作用:将结构体作为参数向函数中传递。
  • 传递方式有两种
    – 1. 值传递 (函数体中修改形参,不影响实参的值)
    – 2. 地址传递(函数体中修改形参,影响实参的值)
  • 例子
#include<iostream>
using namespace std;

struct Student // 创建学生数据类型
{
	string name;
	int age, score;
};

void printStudent1(Student stu) // 值传递 
{
	stu.age = 22;
	cout << "值传递打印数据→姓名:" << stu.name << " 年龄:" << stu.age << " 分数:" << stu.score << endl;
}

void printStudent2(Student* p) // 地址传递
{
	p->age = 23;
	cout << "地址传递打印数据→姓名:" << p->name << " 年龄:" << p->age << " 分数:" << p->score << endl;
}


int main()
{
	Student student = { "摸鱼王",20,100 };
	cout << "原始数据中,stu的age值为:" << student.age << endl << endl;
	printStudent1(student);
	cout << "值传递中修改变量,不改变实参的值,即当前地址中stu的age仍为初始值:" << student.age << endl << endl;
	printStudent2(&student);
	cout << "地址传递中修改变量,会改变实参的值,即当前地址中stu的age更新为:" << student.age << endl << endl;
}

6、结构体中const使用场景

  • 作用:用const来防止误操作。
  • 例子
#include<iostream>
using namespace std;

struct Student // 创建学生数据类型
{
	string name;
	int age, score;
};

// 用地址传递(指针) 可以减少内存空间,而且不会赋值新的副本 
void printStudent1(const Student * stu) // const修饰指针,即常量指针,不可修改stu的值
{
	// s->age="23"; 此时这句话会报错,因为常量指针不可修改值,防止用户误操作进行提醒 
	cout << "姓名:" << stu->name << " 年龄:" << stu->age << " 分数:" << stu->score << endl;
}

int main()
{
	Student student = { "摸鱼王",20,100 };
	printStudent1(&student);
}

结构体const使用例子

7、结构体综合例题

  • 例子1
    结构体例题1
#include<iostream>
using namespace std;

struct Student // 创建学生数据类型
{
	string name; 
	int score;
};

struct Teacher // 创建教师数据类型
{
	string name;
	Student array[5];
};

void assignment(Teacher  teacher[], int length) // 给教师和学生信息赋值
{
	string nameTeacher = "ABCDEF";
	string nameStudent = "abcdef";
	for (int i = 0; i < length; i++) {
		teacher[i].name = "teacher_";
		teacher[i].name += nameTeacher[i];// 第i个教师名为 teacher_ 和 ABCD中第i个字母拼接
		for (int j = 0; j < (sizeof(teacher[i].array) / sizeof(teacher[i].array[0])); j++) // 给老师对应的学生赋值
		{
			teacher[i].array[j].name = "student_";
			teacher[i].array[j].name += nameTeacher[i]; // 给学生姓名赋予老师的尾号
			teacher[i].array[j].name += nameStudent[j]; // 给学生姓名赋予学生专属尾号
			int random = rand() % 40 + 60; // 产生0~40的随机数 + 60 即 60~100的随机数
			teacher[i].array[j].score = random;
		}
	}
}

void printInfo(Teacher teacher[], int length) // 打印教师和学生信息
{
	for (int i = 0; i < length; i++)
	{
		cout << "第" << (i + 1) << "个教师名为:" << teacher[i].name << endl;
		cout << "培养的学生名字和成绩分别为:";
		for (int j = 0; j < (sizeof(teacher[i].array) / sizeof(teacher[i].array[0])); j++)
		{
			cout << teacher[i].array[j].name << " " << teacher[i].array[j].score << " ";
		}
		cout << endl; // 打印完一个教师和学生信息 换行
	}
}

int main()
{
	//↓这步随机数种子如果报错 需要在头文件中添加 #include <ctime> 详细如第四章循环结构例题
	srand((unsigned int)time(NULL));//添加随机数种子 为学生每次产生不同的随机数成绩做准备
	Teacher teacher[3]; // 创建教师数组
	int length = sizeof(teacher) / sizeof(teacher[0]); // 获取教师数组长度(不要直接用3 养成好习惯)
	assignment(teacher, length); // 调用教师赋值函数
	printInfo(teacher, length); // 调用打印信息函数
}

结构体例题1代码

  • 例子2
    在这里插入图片描述
#include<iostream>
using namespace std;

struct Hero // 创建英雄数据类型
{
	string name;
	int age;
	string sex;
};

void bubbleSort(Hero heroArray[], int length) // 冒泡排序
{
	for (int i = 1; i < length; i++) // 冒泡排序轮数 
	{
		for (int j = 0; j < length - i; j++) // 每轮冒泡交换次数
		{
			if (heroArray[j].age <= heroArray[j + 1].age)
			{
				Hero temp = heroArray[j]; // 创建新对象保存当前数组中对象的信息
				heroArray[j] = heroArray[j + 1]; // 将数组交换,等同所有元素交换
				heroArray[j + 1] = temp;
			}
		}
	}
}

void printInfo(Hero heroArray[], int length) // 打印数据
{
	for (int i = 0; i < length; i++) // 冒泡排序轮数 
	{
		cout << "姓名:" << heroArray[i].name << " 年龄:" << heroArray[i].age << " 性别:" << heroArray[i].sex << endl;
	}
}

int main()
{
	Hero heroArray[5] = { {"小赵",22,"男"},{"小张",21,"男"},{"小李",22,"女"},{"小孟",23,"女"},{"小天",20,"男"} };
	int length = sizeof(heroArray) / sizeof(heroArray[0]);
	cout << "初始数据:" << endl;
	printInfo(heroArray, length); // 调用打印数据函数
	bubbleSort(heroArray, length); // 调用冒泡排序函数
	cout << "冒泡排序后数据:" << endl;
	printInfo(heroArray, length); // 调用打印数据函数
}

结构体例题2代码


终于把《黑马程序员》的C++课程基础笔记更新完啦,做两天例题休息休息。然后更新剩下的高级篇内容(内存、引用、重载、封装、继承、多态、文件操作),后续更新进阶笔记(模板、容器、算法),嘻嘻,祝大家代码写的越来越好,下线下线。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值