【C++】学习记录

一、第一个C++程序

cpp 复制代码
#include<iostream>
using namespace std;

int main() {
	cout << "Hello World!";
	return 0;
}

二、数据类型、变量与常量、运算符

2.1 数据类型

2.2 变量与常量

2.3 运算符


三 、判断语句(if-else、switch-case)

3.1 if语句

if语句:用来实现两个分支的选择结构。

3.1.1 if语句的一般形式

cpp 复制代码
//1.没有else子句部分
if(表达式)   语句1

//2.有else子句部分
if(表达式){
  语句1
}else{
  语句2
}

if 语句基本形式是:if (表达式)语句,"表达式"值可以是任意合法的数值。

3.1.2 级联的if-else语句

示例:交电费,分阶段收费

cpp 复制代码
#include<iostream>
using namespace std;

int main() {
	float x = 0.0;
	float y = 0.0;
	cin >> x;

	if (x <= 100)                   y = x * 0.5;
	else if (x > 100 && x <= 300)   y = 100 * 0.5 + (x - 100) * 0.8;
	else if (x > 300 && x <= 1000)  y = 100 * 0.5 + 200 * 0.8 + (x - 300) * 1.2;
	else                            y = 100 * 0.5 + 200 * 0.8 + 700 * 1.2 + (x - 1000) * 2;
	
	cout << y;
	return 0;
}

3.1.3 嵌套的if-else语句

示例:找出三位数中的最大值?

cpp 复制代码
#include<iostream>
using namespace std;

int main() {
	int a, b, c;
	int max = 0;
	cin >> a >> b >> c;
	if (a > b) {
		if (a > c) {
			max = a;
		}
		else {
			max = c;
		}
	}
	else {
		if (b > c) {
			max = b;
		}
		else {
			max = c;
		}
	}
	cout << max;
	return 0;
}

3.2 switch语句

switch语句:实现多分支选择结构。

其基本语句为:

cpp 复制代码
switch(控制表达式)
{
  case 常量: 
      语句;
      break;
  default:
      语句;
      break;
}

示例:根据月份数输出对应月份的英文

cpp 复制代码
#include<iostream>
using namespace std;

int main() {
	int month;
	cin >> month;
	switch (month) {
	case 1:cout << "January" << endl; break;
	case 2:cout << "February" << endl; break;
	case 3:cout << "March" << endl; break;
	case 4:cout << "April" << endl; break;
	case 5:cout << "May" << endl; break;
	case 6:cout << "June" << endl; break;
	case 7:cout << "July" << endl; break;
	case 8:cout << "August" << endl; break;
	case 9:cout << "September" << endl; break;
	case 10:cout << "October" << endl; break;
	case 11:cout << "November" << endl; break;
	case 12:cout << "December" << endl; break;
	}
	return 0;
}

3.3 关系、逻辑与条件运算符与表达式

3.3.1 关系运算符与表达式

例如:a>3是一个关系表达式,>是一个关系运算符。

关系运算符:

运算符 含义 举例 说明
> 大于 a>b a>b 则true,否则false
>= 大于等于 a>=b a>=b则true,否则false
< 小于 a<b a<b 则true,否则false
<= 小于等于 a<=b a<=b则true,否则false
== 等于 a==b a=b 则true,否则false
!= 不等于 a!=b a!=b 则true,否则false

括号、关系运算符与算术运算符的优先级:

|------|--------|-----|---------------|-------|
| 括号() | *、/、% | +、- | <、<=、>、>= | ==、!= |
| 优先级高 ---------------------------------------------------------> 优先级低 |||||

3.3.2 逻辑运算符与表达式

运算符 含义 举例 说明
&& 逻辑与(and) a&&b 全真则真,一假全假
|| 逻辑或(or) a||b 一真全真,全假才假
^ 异或运算符 //严格来说,这是位运算符, 但它常常用于逻辑判断,故 放在这里。 a^b 一真一假则为真, 全真全假则为假
! 逻辑非(not) !a 假则为真,真则为假

运算符优先级:

|------|---------------|--------|------------|------------------|---------------|-------|------|------|
| 括号() | !、-(负号)、++、-- | *、/、% | +、- (加减运算) | <<、>> (左右位移) | <、<=、>、>= | ==、!= | && | || |
| 优先级高 ---------------------------------------------------------> 优先级低 |||||||||

3.3.3 条件运算符与表达式

|----------------|------------|---------------------------|
| 运算符 | 举例 | 说明 |
| 表达式1?表达式2:表达式3 | (a>b)?a:b | 如果表达式1为真,取值表达式2;为假,取值表达式3 |

3.4 分支结构的测试:程序测试方法

什么是测试?(找逻辑上的bug)

  • 指对一个完成了全部或部分功能、模块的计算机程序在正式使用前的检测,以确保该程序能按预定的方式正确地运行。

  • 是程序员开发人员或程序测试人员的任务。

  • 通过运行测试用例,找出程序中尽可能多的Bug。
    程序测试方法的分类:

  • 白盒测试(结构测试):程序员自己看代码,主要用于测试的早期和重要的路径。

  • 黑盒测试(功能测试):代码交给系统测试,主要用于测试的后期和重要的功能。


四、循环语句(for、while、do-while)

选择循环语句的一般原则:循环次数已知------for语句

循环次数未知------while语句

循环体至少执行一次------do-while语句

4.1 for循环

for语句能用于两种情况:1.循环次数已经确定。2.循环次数不确定而只给出循环结束条件。

其基本语法如下:

cpp 复制代码
for(循环变量赋初值;循环条件;循环变量增值){
            //循环语句
}

示例:求1~100的和(注意到,sum前面不加"&")

cpp 复制代码
#include<iostream>
using namespace std;
int main(){
  int sum=0;
  int i;
  for(i=1;i<=100;i++){
  sum=sum+i;
}
  cout<<"1~100的和为"<<sum;
  return 0;
}
/*为什么printf里面的变量sum不加"&"?
加&传递的是指针,是一个内存地址;不加&传递的是值,是一个变量的拷贝。
printf 在输出时,只需要值就够了。
而scanf 之所以加&,是因为他需要知道你想把输入的参数,保存在内存的什么地方,也就是你给的变量的地址*/

4.2 while循环

while语句:只要当循环条件表达式为真(即给定的条件成立),就执行循环体语句。

(while循环的特点:先判断循环条件,后执行循环体语句)

其基本语法如下:

cpp 复制代码
while(循环条件){
     //循环体
}

示例:求1~100的和

cpp 复制代码
#include<iostream>
using namespace std;

int main(){
  int i=1,sum=0;
  while(i<=100){
    sum=sum+i;
    i++;
}
cout<<"1~100的和为"<<sum;
return 0;
}

4.3 do-while循环

do-while语句:先执行循环体,然后再检查循环条件是否成立,若成立再执行循环体。

(do-while循环的特点:先无条件执行循环体,然后判断循环条件是否成立。)

其基本语法如下:

cpp 复制代码
do{
    //循环体
}while(循环条件)

示例:求1~100的和

cpp 复制代码
#include<iostream>
using namespace std;

int main(){
 int i=1,sum=0;
 do{
    sum=sum+i;
    i++;
}while(i<=100);//注意在这里,有一个分号!!

cout<<("1~100的和为"<<sum;
return 0;
}

4.4 改变循环执行的状态

4.4.1 break语句提前终止循环

break语句的作用:使流程跳出循环体之外,接着执行循环体下面的语句。

(break语句只能用于循环语句和switch语句之中,而不能单独使用。)

示例:1~100从小到大依次相加,当和大于3000时,立刻输出和。

cpp 复制代码
#include<iostream>
using namespace std;

int main(){
  int sum=0;
  for(i=1;i<=100;i++){
    sum=sum+i;
    if(sum>3000) break;//break语句前常用if语句作为执行条件
}
cout<<"此时和为"<<sum;
return 0;
}

思考:如果是双重循环,在内循环体内有一个break语句,下一步进行什么循环?

解答:提前终止内循环,继续进行外循环。

4.4.2 continue语句提前结束本次循环

continue语句的作用:结束本次循环,进入下一次循环。

示例:要求输出100~200不能被3整除的数。

cpp 复制代码
#include<iostream>
using namespace std;

int main() {
	int i;
	for (i = 100; i < 200; i++) {
		if (i % 3 == 0)   //i%3==0,是指i除以3的余数等于0,即i能够被3整除
			continue;     //continue语句也常搭配if语句进行使用
		cout<<i<<endl;
	}
	return 0;
}

4.5 递推法

4.5.1 通过Fibonacci数列看递推法

斐波那契数列是什么?

斐波那契数列是一个数列,以0和1开始,后面的每一项都是前两项的和。数列的前几项如下:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

cpp 复制代码
#include<iostream>
using namespace std;

int F(int num);

int main() {
	int i;
	cin >> i;
	F(i);
	cout << F(i);
	return 0;
}

int F(int num) {
	if ((num == 0) || (num == 1)) {
		return num;
	}
	else {
		return F(num - 1) + F(num - 1);
	}
	return 0;
}

4.5.2 递推法的基本思想

  • 递推法:指从问题的已知条件出发,依据某种递推关系,依次推出所要求的各中间结果及最后结果。
  • 递推初始条件确定:问题本身已经给定or通过对问题的分析与化简后确定。
  • 递推的方向(两种):顺推法、逆推法

顺推法:从已知初始条件出发,通过递推关系逐步推算出要解决的问题的结果的方法。如求斐波那契数列。

倒推法:在不知初始值的情况下,经某种递推关系而获知于问题的解或目标,从这个解或目标出发,采用倒推手段,一步步地倒退到这个问题的初始情况。如猴子吃桃。
实现递推的步骤:

  1. 确定递推变量:要根据问题的具体实际,设置递推变量。
  2. 建立递推关系:递推关系是指,如何从变量的前一些值推出其下一个值,或从变量的后一些值推出其上一个值的公式(或关系)。
  3. 确定初始(边界)条件:对确定的递推变量,要根据问题最简单情形的数据确定递推变量的初始(边界)值,这是递推的基础。
  4. 对递推过程进行控制:递推过程不能无休止地重复执行下去。递推过程在什么时候结束,满足什么条件结束,这是编写递推算法必须考虑的问题。

4.6 穷举法

4.6.1 什么情况下用穷举算法

  1. 穷举法:根据问题中的"约束条件",将所有可能的解一一列举出来,并逐个验证是否符合"约束条件",找出符合要求的解。
  2. 穷举法适合求解的问题:可能的答案是有限个and答案是已知的,但又难以用解析法描述。这种算法通常用循环结构来完成。

4.6.2 百鸡问题

"百鸡问题":鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一。百钱买百鸡,问鸡翁、母、雏各几何?

cpp 复制代码
#include<iostream>
using namespace std;

int main() {
	int i, j, k;
	for (i = 1; i <= 20; i++) {
		for (j = 1; j <= 33; j++) {
			for (k = 1; k <= 300;k++) {
				if ((i + j + k == 100) && (5 * i + 3 * j + k / 3 == 10)) {
					break;
				}
			}
		}
	}
	cout << i << " " << j << " " << k << endl;
	return 0;
}

优化,两重循环(k=100-i-j)

cpp 复制代码
#include<iostream>
using namespace std;

int main() {
	int i, j,k;
	
	for (i = 1; i <= 20; i++) {
		for (j = 1; j <= 33; j++) {
			k = 100 - i - j;
				if ((5*i + 3*j + k/3 == 100) && ( k % 3 == 0)) {
					break;
				}
		}
	}
	cout << i << " " << j << " " << k << endl;
	return 0;
}

4.7 循环程序调试方法:单步调试法

程序调试的步骤:猜测出错位置,设置断点------>单步运行------>观察变量------>发现问题------>修正代码,重新运行------>解决问题

循环程序常用断电:初始值,改变程序条件变量的位置,判断条件。


五、数组

5.1 一维数组

定义一维数组:数据类型 数组名常量表达式;

如int a10,char c10

  • 数组是用来存储相同数据类型的数据结构。
  • 数组在内存里有一块连续的存储空间(区别于链表)。
  • 常量表达式是来表示数组大小的,定义之后就不能改变。

5.2 二维数组

定义二维数组:数据类型 数组名常量表达式1常量表达式2;

如int a\[\]10,char c\[\]10

  • 二维数组可以表示二维表格上的数据。
  • 二维数组存储形式先行后列。
  • 二维数组的处理一般采用双重循环语句。

5.3 字符串与字符数组

解决两个问题:

  • 字符串输入cin和cin.getline区别
  • 字符串输出如何不出现乱码?
    字符串与字符数组的不同

字符串char name\[\]="hust";//数组长度为5

|---|---|---|---|-----|
| h | u | s | t | \0 |

字符数组char name\[\]={'h','u','s','t'};//数组长度为4

|---|---|---|---|
| h | u | s | t |

字符数组的输入输出

在实际应用cin输入字符数组时,会自动在输入的字符尾端加上'\0',故在定义数组大小时应考虑到这一点。

  • 字符数组的输入(cin、cin.getline)

用"cin>>数组名"的形式输入

遇到空格,Tab,回车键表示数据之间间隔;回车键还可以表示输入结束

用"cin>>数组名"输入单个字符串时,其中不能有空格

用"cin>>数组名"输入多个字符串时,可以用空格分隔

用cin.getline函数(输入字符串中包含空格字符)

cin.getline(字符数组名,字符个数n)

输入回车表示输入结束

输入字符的数量(不包含回车)最大为n-1

输入的字符后会自动添加串结束符'\0',作为字符串的一部分放入数组

如果输入字符的数量(不包含回车)大于n-1个,将前n-1个字符放入数组

cin和cin.getline混合使用

运行下面这个代码会发现cin,getline语句被直接跳过,并没有输入的过程。这是因为cin>>和cin.getline从缓冲区读数据时的方式不同,cin>>不读"\n"换行符,但是cin.getline读"\n"换行符,那么在实际的运行过程中代码读完cin>>之后会立马遇到一个换行符,cin.getline 也就没运行就结束了。

那么如何解决上述问题?(清空缓冲区)

混合使用cin和cin.get.line时,用cin.clear()和cin.sync()解决问题

cpp 复制代码
//混用之后,有问题的代码
#include<iostream>
using namespace std;

int main() {
	char ch[5];
	int number;
	cin >> number;
	cin.getline(ch, 5);
	return 0;
}

//清空缓冲区,没问题的代码
#include<iostream>
using namespace std;

int main() {
	char ch[5];
	int number;
	cin >> number;
	cin.getline(ch, 5);
	return 0;
}
  • 字符数组的输出

cout遇到'\0'才能结束

cpp 复制代码
//没有结束符,有问题的代码
#include<iostream>
using namespace std;

int main() {
	char a[4] = "C++";
	char b[3] = { 'c','+','+' };
	cout << a << endl;
	cout << b << endl;
	return 0;
}
//加结束符,没问题的代码
#include<iostream>
using namespace std;

int main() {
	char a[4] = "C++";
	char b[3] = { 'c','+','+' ,'\0'};
	cout << a << endl;
	cout << b << endl;
	return 0;
}

5.4 字符串的应用

字符数组与数值数组之间的异同

  • 相同点:定义格式一样,可以使用循环访问每个元素。
  • 不同点1:循环控制条件不同
cpp 复制代码
int a[6] = { 1,2,3,4,5,6 };
for (int i = 0; i < 6; i++) {
	cout << a[i];
}

char b[60] = "hello";
for (int j = 0; b[i] != '\0'; j++) {
	cout << b[j];
}
  • 不同点2:字符数组可以使用数组名整体访问整个字符串
cpp 复制代码
	//输出的是数组a的首地址
    int a[6] = { 1,2,3,4,5,6 };
	cout<<a<<endl;
    //输出b为首地址的字符串,直至遇到'\0'结束
	char b[60] = "hello";
	cout << b<<endl;

六、指针------C++的灵魂

6.1 指针的概述及基本应用

6.1.1 指针的基本概念

  • 内存地址:计算机的内存被划分为一个个的存储单元,简称内存单元。内存单元按一定的规则编号,这个编号就是存储单元的地址。
  • 变量与地址:程序中定义的变量要占用一定的内存空间,不同的数据类型的变量占用的内存空间大小不一样。如整型变量占用4个存储单元,浮点型变量占用8个存储单元。
  • 访问内存中的数据(两种方式:直接访问,间接访问)

直接访问:通过变量名,直接对变量的存储空间进行存取访问。

间接访问:根据变量的地址进行存取访问。
指针变量与指针变量的定义

  • 指针变量是一种特殊的变量,用于存放内存单元的地址,即能存放地址的变量就是指针变量。
  • 指针变量定义的一般形式:数据类型 *指针变量名;

定义语句中的 *表示该变量为指针变量。

指针变量前的数据类型规定了指针变量指向的变量的数据类型。

如double *p,p为指针变量,且指针变量p里存放着double类型变量的地址。

  • 指针变量的三要素

变量名:与一般变量取名相同,数字、字母、下划线组成,字母、下划线开头。

指针变量的类型:指针所指向的变量的类型,而不是自身的类型。指针变量本身均为long int类型。

指针变量的值:是某个变量的内存地址。

6.1.2 与指针相关的运算符&、*

取地址运算符:&

  • &是一个一元运算符,用来得到一个变量的地址。&后面必须是个变量。
  • 例如int a;

&a表示变量在内存中的起始地址,
指针运算符:*

  • *是一个一元运算符,表示指针变量所指向的变量的值(取值)。*后面必须是个地址。

注意:*在不同地方出现含义不同。

  • 如:int a=5,b,*p;

p=&a;//*p也就是取地址&a内存放的变量a的值

b=*p;//(即p所指向的内存单元的内容),等价于b=a

6.1.3 指针变量的初始化与赋值

  • 指针变量初始化,在定义时赋值:数据类型 *指针名=地址
  • 指针赋值: 指针变量=地址

其中的"地址"可以是变量的地址、数组名等。

如:int x=8;

int *p=&x;//指针变量初始化

int *q;

q=p;//指针赋值

  • 不能把常量或表达式赋给指针变量。

p=&67; p=&(i+4)是非法的

  • 不能将一个整数赋给指针变量,但可以赋整数值0,0是可以直接赋给指针变量的唯一整数值,表示空地址(NULL)。

int *p; p=0;//p为空指针,不指向任何地址

6.2 指针与一维数组

6.2.1 指针表示一维数组的元素

数组:int a\[\]={1,2,3,4,5,6,7,8,9};

|--------|-------|---------|-------|
| a0 | 下标表示法 | *(a+0) | 地址表示法 |
| a1 | 下标表示法 | *(a+1) | 地址表示法 |
| a2 | 下标表示法 | *(a+2) | 地址表示法 |
| a3 | 下标表示法 | *(a+3) | 地址表示法 |

数组:int a\[\]={1,2,3,4,5,6,7,8,9};

int *p=a;

|-----------------|-------|----------------|-------|
| cout<<*(p+0) | 下标表示法 | cout<<p0 | 地址表示法 |
| cout<<*(p+1) | 下标表示法 | cout<<p1 | 地址表示法 |
| cout<<*(p+2) | 下标表示法 | cout<<p2 | 地址表示法 |
| cout<<*(p+3) | 下标表示法 | cout<<p3 | 地址表示法 |

6.2.2 指针的算术运算与比较运算

cpp 复制代码
    int a[] = { 1,2,3,4,5,6,7,8,9 };
    int* p = a;

此时p是指针变量里面存放着&a,p指向a0

  1. p++后,p指针指向的地址是什么?

6.2.3 用指针操作一维数组的实例

6.3 指针与二维数组

6.4 指针数组

6.5 多级指针、动态内存分配


七、指针


八、

相关推荐
for_ever_love__5 小时前
UI学习:UISearchController基础了解和应用
学习·ui·ios·objective-c
心中有国也有家5 小时前
GE图引擎深度解析——CANN的计算图优化与执行引擎
人工智能·pytorch·python·学习·numpy
isyangli_blog6 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008116 小时前
FastAPI APIRouter
开发语言·python
Benszen6 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆6 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木6 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
GHL2842710906 小时前
换脸工作流学习
学习·ai
MC皮蛋侠客6 小时前
C++17 多线程系列(五):C++17 并行算法——从串行到并行的零成本迁移
c++·多线程
_李小白7 小时前
【android opencv学习笔记】Day 28: 滤波算法之中值滤波器
android·opencv·学习