c++基础

C++基础

1:头文件

1.0:头文件:其中有带h和没有带h后缀的,带h后缀的是老版本的编译器,没带是新版本的编译器。

#include <limits.h>                  #最大最小要导入这个

#include <ctype.h>                  #字符处理函数功能
#define _CRT_SECURE_NO_WARNINGS 

#include <iostream>                    #用cout打印


1.1:头文件iostream:如果程序使用输入或输出工具,一定要提供下面这两行代码:

#include <iostream>
using namespace std;

iostream是C++标准库中的一个头文件

提供了输入输出流的支持,包括了cin、cout、cerr、clog等对象以及相应的操作符<<和>>等。通过引入iostream头文件,可以使用C++中的输入输出流机制,使得程序的输入输出更加方便、灵活,也更符合面向对象的编程思想。可以通过以下代码引入iostream头文件:

#include <iostream>

在程序中使用cout输出信息的示例:

#include <iostream>

using namespace std;

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

其中,cout代表标准输出流,<<代表插入操作,将数据流插入到输出流中,endl代表换行操作。以上程序会输出一行字符串"Hello World!"。

#include<iostream>:该编程指令导致预处理器将iostream文件内容添加到程序中,这个是一种典型的预处理操作,在原代码编译之前,替换或添加文本

1.2:问题解答

1.21:为什么将iostream文件的内容添加到程序中?

答:涉及到程序与外部世界之间的通信,iostream中的io指的就是输入(进入程序的信息)和输出(从程序中发出的信息
解释:c++中输入和输出方案,涉及iostream文件中的多个定义,为了使用cout来显示消息,第一个程序需要这些定义,include编译指令导致iostream文件的内容一起被发送给编译器,iostream中的内容没有被修改,而是将源代码文件和iostream组合成一个符合文件,编译的下一阶段

1.22:using namespace std有什么作用:

在 C++ 中,using namespace std; 是一个编译指令,用来告诉编译器在代码中使用 std 命名空间中的标识符时不需要加上前缀 std::,直接使用即可。

例如,如果不使用 using namespace std;,则需要使用 std::cout 来输出内容:

#include <iostream>

int main() {
    std::cout << "Hello, world!" << std::endl;
    return 0;
}

而使用 using namespace std; 后,则可以直接使用 cout:

#include <iostream>

using namespace std;

int main() {
    cout << "Hello, world!" << endl;
    return 0;
}

需要注意的是,对于大型项目或者需要避免命名冲突的情况,建议不要在头文件中使用 using namespace std;,而是在源文件中使用。同时,其他命名空间中的标识符也应该使用对应的命名空间前缀来调用。

1.3:函数解析:

using叫做编译指令,名称空间,在编译器执行编译的时候,不知道是那个版本的,名称空间的名称用来指哪个版本的产品,按照这种方式,类,函数,变量便是c++编译器的标准组件,现在都被放置在名称空间的std中。仅当头文件没有扩展名h时,情况才如此。意味着,在iostream中定义用于输出的cout变量上是:std::cout,endl是std::endl,可以省略编译指令using,以下述方式进行编码。

cin:输入符

cout:输出符:默认是以10进制格式显示整数的

cout.put():输出符:通过类对象cout来使用函数put(),是另一种显示字符的方法,可以代替<<运算符.

endl:控制符,在输出流中插入endl将屏幕光标移到下一行,

\n:换行符:通常在字符串中运用,显示字符串时,字符串包含了换行符,而不是在末尾加endl,可以减少输出量

int carrots:变量:首先用int,确定数据类型,carrots:为变量,在c++中变量都必须声明。

2:函数:函数分为两种,有返回值的和没有返回值的,

1:平方根函数:sqrt()要定义头文件,平方根的头文件为:include <cmath>,使用平方根函数,要定义一个数据类型平方根的返回值double

#include<iostream>
using namespace std;
#include <cmath>;

int main() {

	//变量的定义
	//语法:数据类型  变量名 = 初始值

	int carrots;
	cout << "hew many" << endl;
	cin >> carrots;
	carrots = carrots + 1;
	cout << "now you" << carrots << endl;


	//平方根的返回值数据类型定义
	double area;
	double side;
	//输入
	cin >> area;
	//使用sqrt函数
	side = sqrt(area);
	
	//输出
	cout << side << endl;
	//结束返回值
	return 0;
}

在这里插入图片描述
在这里插入图片描述

LNK开头的是连接错误

在这里插入图片描述

3:数值类型

int类型最大最小值
INT_MIN    :最小值
INT_MAX    :最大值


unsigned int 类型最大是:
UINT_MAX


long类型的最大最小
LONG_MIN
LONG_MAX
无符号的long类型大小
ULONG_MAX

long long 类型大小
LLONG_MIN 
LLONG_MAX
无符号类型
ULLONG_MAX 


整型:shortintlonglong long,这些整型是从小到大进行排序的。

存储值:
short:至少16位
int:int至少与short一样长
long:至少32为,且至少与int一样长
long long:至少64位,且至少与long一样长
无符号整型:就是值不能为负数,整型前面加上unsigned如:unsigned short等等.

输出符,进制的修改
cout:输出符:默认是以10进制格式显示整数的
使用控制符可以修改输出cout函数的进制,控制符为:dec:修改十进制hex:修改十六进制oct:修改八进制
cout默认是以10进制格式显示整数的,改成十六进制的,代码如下

cout << hex;
cout << 十六进制的变量 << endl;

char类型:字符和小整数,足够长,能够表示目标计算机系统中的所有基本符号,所有的字母,数字,标点符号等,c++将常量存储为char类型

常量函数:const,让数值固定死。

浮点数类型:floatdoublelong double,在默认情况下是双进度的:double类型

float:至少32位
double:至少48位
long double:为80,96,或128

定点模式:写入到函数体中,cout.setf(ios_base::fixed,ios_base::floatfield);精确显示如是float,精度到后面的6位

在这里插入图片描述

数组

创建一个数组 数组的类型 数组的变量[ 多少个数组]
创建数组及赋值 int 变量[3] = {3个自定义元素}

不可以这样赋值,如下列:
int hend[4] = {5,6,7,8};:定义完成
hand = heand :不能定义后,在进行赋值。
hend[4] = {5,6,8,9}:也不能定义以后在fu

显示类型的内存大小函数

sizeof("%对应的占位符号"&对应的变量)

计算数组里面多少个元素

列如:short things[] = {1,5,3,8};

int num_elememts = sizeof things / sizeof (short);

数组的初始化

如:
unsigned int counts[10] = {}; 全部初始化为0。
float balances[100] {}; 全部初始化为0。

数组初始化禁止缩窄转换,要类型一样的。

如:long plifs[] = {25,92,3.0};这里的3.0是浮点数,转换成整数是要缩窄转换的,即使浮点数后面小数点为0,也不能通过编译。

字符串

字符 : ’ '(单引号是一个字符,如果要赋值成数组后面要加上 /0 其中 /0 为空字符),
字符串: " "(双引号是一个字符串是默认带 /0 的):其实双引号代表着的是一个地址。

strlen:字符串的有效长度,这里是指,,如果设置为15个长度数组,但是只用到了4个有效数组这个函数就只返回4个字节

 strlen(字符串变量)

字符串复制:strcpy(变量1,变量2):对变量复制

字符串的拼接:strcat():字符串的拼接

struct inflatable:结构体

struct  inflatable 
{
	char name[20];
	float volume;
	double price;
}

创建枚举量,枚举赋值必须是整型,int或long或long long

enum spectrum{red,orange,yellow,green,blue,violet,indigo,ultraviolet};
括号内的是枚举量
spectrum :枚举类
spectrum  band;  :通过枚举类创建枚举变量

枚举的取值范围如下,首先,
要找到上限,需要知道枚举的最大值,找到小于这个最大值的,最小的2的幂,将它减去1,得到的便是取值范围的上限。
要找到下限:需要知道枚举量的最小值,如果它不小于0,则取值范围的下限为0,否则采用与寻找上限方式相同的方式,但加上负号,列如,如果最小的枚举量为-6,而比他小的,最大的2的幂是-8,因此下限为-7
上限:
在这里插入图片描述下限:
在这里插入图片描述

4:指针

C++中的指针是一种特殊的数据类型,它存储了一个变量的内存地址。通过指针,程序可以对变量的值和地址进行操作,使得程序具有更高的灵活性和效率。

在C++中,定义一个指针需要使用 * 符号。例如:

int* ptr;

上述代码定义了一个整型指针 ptr。

指针可以通过取地址符 & 来获取变量的地址,例如:

int num = 10;
int* ptr = &num;

上述代码定义了一个整型变量 num,并且通过指针变量 ptr 获取了 num 的地址。此时,ptr 存储的值就是 num 的地址。

指针可以通过解引用符 * 来获取指针所指向的变量的值,例如:

int num = 10;
int* ptr = &num;
cout << *ptr; // 输出:10

上述代码通过解引用符 * 获取了 ptr 所指向的 num 变量的值,即输出了 10。

指针还可以用于动态内存分配,例如:

int* arr = new int[10]; // 动态分配长度为 10 的整型数组

上述代码使用了 new 操作符动态分配了一个长度为 10 的整型数组,并将数组的首地址赋给了指针变量 arr。此时,arr 就可以像普通数组一样使用。

需要注意的是,指针也可以为空,表示指向的地址为 NULL。在使用指针时需要注意空指针的情况。

指针:int* p_updates:创建一个int*类型的p_updates指针,带 int*符号的就是创建int类型的指针

&updates:前面带个&符号在写上变量名:打印出来的是内存地址
p_updates = &updates:将内存地址赋值到指针变量中
*p_updates  :打印出来的是&updates地址里面的值。

5:new用法

在C++中,new是一个操作符,用于在堆上动态分配内存空间。它的基本语法为:

指针变量 = new 数据类型;

其中,指针变量是一个指向已分配内存空间的指针,数据类型是要分配的数据类型。

例如,如果想动态分配一个整型变量,可以使用以下语句:

int *p = new int;

这样就在堆上动态分配了一个int型变量,并将其地址赋给了指针变量p。

另外,new操作符还可以用于动态分配数组。例如,如果想动态分配一个大小为10的整型数组,可以使用以下语句:

int *p = new int[10];

这样就在堆上动态分配了一个大小为10的int型数组,并将其首元素的地址赋给了指针变量p。

使用完new分配的内存后,应该使用delete操作符来释放这些内存,避免内存泄漏。delete的使用方法为:

delete 指针变量;

例如,如果要释放前面所分配的整型变量内存,可以使用以下语句:

delete p;

如果要释放前面所分配的整型数组内存,可以使用以下语句:

delete [] p;

使用new来动态的分配内存的操作符:是分配的内存块,

new可以在运行时动态地申请内存来构造一个对象或一组对象,这些对象的生命周期由程序员控制。
当使用new时一定要使用下面的释放内存的delete,否则会内存泄漏。

new 数据类型;
new 数据类型[数组大小];

typeName * pointer_name = new typeName ;

释放掉new开辟的内存空间delete

delete 内存块的指针;
释放的是指针指向的内存,不是删除指针本身。

在C++中,使用new动态地分配内存空间,程序员需要手动释放这些内存空间以避免内存泄漏。可以使用delete表达式来释放由new运算符开辟的内存空间。

delete有两种形式,一种是释放单个对象的内存,另一种是释放一个对象数组的内存。具体用法如下:
例如:
1:释放单个对象的内存

int* ptr = new int;  //分配一个int类型的内存空间
*ptr = 10;  //给这个内存空间赋值
delete ptr;  //释放这个内存空间

2:释放一个对象数组的内存

// 分配内存
int* arr = new int[10];
// 使用内存
// ...
// 释放内存
delete[] arr;

当delete表达式执行时,它会先调用该空间中的析构函数,然后将空间返回给操作系统。如果指针不是通过new分配的,则不能使用delete来释放它,否则会导致未定义的行为。

6:

窗口一直执行

system("pause");

代码块,方法

定义方法
void test()

输入阻塞函数

scanf("%hd",&变量)
&变量:取变量的地址

从键盘上输入给变量赋值:cingetline()

输入头文件 :#include <iostream>
cin >> 变量   :这个面向字符读取,如果遇到空格或者换行符的话就会终止

cin.getline() :输入的字符要比指定的字符多就会getline和get将把剩余的字符留到输入的列表中,而getline()会设置失效位

cin.getline()   这个面向行读取,遇到空格也不会终止
这里getline():有两个函数,第一个是字符的变量,第二个是字符变量的上限

cin.get():get():在读取空行会后将设置失效位

cin.get() 也有两个参数 ,第一个是字符的变量,第二个是字符变量的上限 ,面向行的输入,但是还有一个换行符,在缓存区里面
再使用使用cin.get:就可以在换行符进行了捕获了

可以连续使用cin.getline().getline():getline()括号内写上,变量和字符的上限值,但是get()的是不行的,因为第一个get读取了缓存区的字符,但是回车换行符还再缓存区中当,连续再点get时读的是回车换行符,缓存区就失效

如果失效了,在进行开启捕获位的话使用cin.clear();

创建结构体:struct 变量 {}

输出函数
printf()

显示类型的内存大小函数

sizeof("%对应的占位符号"&对应的变量)
sizeof  变量名

类型

数据类型不一样,首先转换成一样的类型再进行计算

在这里插入图片描述

unsigned         :无符号类型也就是不为负数,最小值为0
无符号是u%打印
代表着10进制无符号 


字符语法
char 
占位符为%c
内存大小为1个字节
字符存储的时候存储的是一个数字这里有一个ascii码表,每个字符都对应着数字对字符代表着


字符串
char[] = "";
增加头文件
#include <string>
string 变量名 = "";  :`string` :能自动调节所需的内存大小


布尔数据类型
bool
bool 变量名= true;bool 变量名 = false;  假
所存空间为1




short               :有符号的类型,最大到了32768多左右 ,短整型
占位符号: %hd\n
unsigned short      :无符号
占位符号: %hu\n
内存占2个字节


int                 :数值类型 ,整型,
unsigned  int       :无符号的整型
占位符号:用%d
内存大小为4个字符


long             		:长整型
unsigned long         :无符号的长整型
占位符号:用%ld
内存大小为 4或者8,在gcc编译器中确定就是占用8个字符,32位的4个字节,64位的8个字节



long long     
unsigned long long   :无符号long类型      
占位符号为%lld
内存大小为8个字符



float           :浮点型
精确到6位
占用4个字节


double         小数双精度
精确到15位
内存占用8个字节



在这里插入图片描述





字符常量:  ''   ,单引号
字符串常量:  ""  ,双引号

宏常量:                         #define 变量名   定义上方
修饰变量(也称为常量):           const          


在这里插入图片描述

\t :中间形成个空格,形成对其方式
在这里插入图片描述

字符转换

toupper()    :将字符转换成大写
tolower()    :将字符转换成小写
toascii()    :将字符转换成ascii 码

在这里插入图片描述

进制转换

十进制:逢十进一,0-9 ,正常以数字1-9开头 ,%d :源码占位
二进制:逢二进一,0-1 ,c语言不能直接行书写2进制进
八进制:逢八近一,0-7 ,以数值0开头 ,%o :补码占位
十六进制:逢十六进一,0-F ,以0x开头,如0x123 ,%n :补码占位
十进制转二进制
十进制转八进制
十进制转十六进制
小数转二进制

在有符号开头中的第一个位经常表示正负

1表示为负
0表示为正

反码

源码:正数的源码 等于反码等于补码
在计算过程中正码计算是有错误的
反码:在正数的反码是不变的,负数的反码(符号位不变,其他位取反),如果计算机用反码进行存储,负数运算结果是正确的,但是0的状态还是有两种
补码:正数的补码不变,负数的补码等于反码加1,如果计算机用补码去存储,负数运算结果是正确的,0的状态只有一种

补码求源码

补码求反码:符号位不变,其他位取反
反码求源码:反码加1

变量赋值时

在变量赋值时,赋值是十进制,给的是源码,如果赋值时给的八进制或者十六进制给的就是补码
在打印的时候,用十进制打印,就是用的源码,如果是八进制和十六进制,用的就是补码。

在无符号的情况下对其打印如果是%d的需要进行转码

因为打印%d的时候变成了有符号的数

在这里插入图片描述

进制转换

char bin[128]={0};char bin[128]申请指定空间内存。={0}128字节的全部清空
_ltoa(要转换的变量,转换地址,转换几进制)                         :进制转换

在这里插入图片描述
小数转换成二进制
在这里插入图片描述

运算符

在这里插入图片描述

赋值运算

在这里插入图片描述

逻辑运算符

在这里插入图片描述
在这里插入图片描述

判断语句

if后面不能加这个分号符号 :  (;if (变量名> 条件)
{
	过了条件运行;
	//嵌套if
	if(变量名> 条件)
	{
	
	}
}

else if
{
	过了条件运行;
}
else
{
	过了条件运行;
}

三木运算符

C++中的三目运算符(也称条件运算符)是一种简单的条件语句,用于根据一个条件的真假值来选择不同的计算方式。

它的语法为:

条件表达式 ? 表达式1 : 表达式2;

其中,条件表达式为一个返回布尔值的表达式,如果它的结果为true,则执行表达式1,否则执行表达式2。

示例代码:

int x = 10, y = 20;
int max_num = (x > y) ? x : y; // 如果x>y,则max_num=x,否则max_num=y

在上面的例子中,如果x>y,则三目运算符返回x,否则返回y,最终将返回的值赋给max_num变量。

a > b ? a : b ; //如果a大于b则返回a,反之返回b
a < b ? a : b ; //如果a小于b则返回a,反之返回b

switch语句,执行多条件分支语句

判断只能是整型或者字符型,不可以是一个区间

C++中的switch语句用于多分支判断,语法如下:

switch(expression){
    case constant1:
        //代码块1
        break;
    case constant2:
        //代码块2
        break;
    default:
        //默认代码块
        break;
}

其中,expression是一个可求值的表达式,case后面的常量可以是整型、字符型、枚举型或者变量值,用于匹配expression的值,如果匹配成功,则执行相应的代码块,执行完毕后用break终止switch语句。如果所有的case都不匹配,则执行default代码块,如果没有default代码块,则switch语句不会做任何操作。

需要注意的是,case后面的常量必须是编译时常量,即不能使用变量或者函数调用的返回值。

switch(表达式)
{
	case 结果1:执行语句;break;
	case 结果2:执行语句;break;
	.....
	default:执行语句;break;

}

在这里插入图片描述

循环语句:while()

while(循环条件)
{
	执行循环内容;
}

do…while循环语句

do-while循环是一种后测试循环语句,它与while循环的区别在于它至少执行一次循环体。语法如下:
不管条件是否满足先执行一次循环语句,在进行判断看接下来的循环

do {
    // 循环体
} while (条件表达式);

在这里插入图片描述

for循环

在 C++ 中,for 循环用于重复执行一定次数的代码。for 循环的语法如下:

for (initialization; condition; increment) {
    // code to be executed
}
  • initialization - 在循环开始前执行一次的代码,通常用于初始化循环计数器。
  • condition - 每次迭代前都会被检查的条件。如果为 true,则执行循环体中的代码;否则跳出循环。
  • increment - 在循环体执行完之后执行的代码,通常用于递增或递减循环计数器的值。

下面是一个简单的 for 循环示例:

for (int i = 0; i < 10; i++) {
    cout << i << endl;
}

这个循环将执行 10 次,每次输出一个数字。

if判断

||:这个符号为或
if(判断条件 || 判断条件2 || 判断条件3)
{
	
}

跳出循环:break:break是一种控制语句,可用于中断循环语句(如for循环或while循环)或switch语句中的执行

#include <iostream>
using namespace std;

int main() {
  for (int i = 1; i <= 10; i++) {
    if (i == 6) {
      cout << "中断循环" << endl;
      break;
    }
    cout << i << endl;
  }
  return 0;
}

结束本次循环:continue

用于在循环结构中跳过当前迭代并进行下一次迭代。当continue语句出现在循环结构中的某个代码块内,它会立即终。

无条件跳转语句:goto

goto后面跟着一个标签(label),该标签必须定义在当前函数中的某个位置,并且标签后面必须紧跟一个语句。当程序执行到goto语句时,会立即跳转到标签所在的位置,并从该位置开始执行下一条语句
在这里插入图片描述

随机数

rand()在这里插入图片描述

数组

int 数组名[数组的长度] = {10,20,30,40};

统计数组占用的空间:sizeof

通过总体的数据空间除于单独空间等于数组的个数

数组元素的个数 = sizeof(数组)/sizeof(数组[0])

数组的逆置

可以通过循环交换数组元素的方法实现数组的逆置,具体步骤如下:

  1. 定义一个数组,例如 int arr[] = {1, 2, 3, 4, 5};

  2. 计算数组的长度,例如 int len = sizeof(arr) / sizeof(arr[0]);

  3. 定义两个指针,一个指向数组的开头,一个指向数组的结尾,例如 int *start = arr; int *end = arr + len - 1;

  4. 循环交换数组元素,直到指针 start 大于等于指针 end。

while (start < end) {
    int temp = *start;
    *start = *end;
    *end = temp;
    start++;
    end--;
}
  1. 最终数组 arr 的元素顺序将会被逆置。

完整代码:

#include <iostream>
using namespace std;

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int len = sizeof(arr) / sizeof(arr[0]);

    int *start = arr;
    int *end = arr + len - 1;

    while (start < end) {
        int temp = *start;
        *start = *end;
        *end = temp;
        start++;
        end--;
    }

    for(int i = 0; i < len; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    return 0;
}

数组的冒泡排序

#include <stdio.h> //std标准  io输入输出
#include <stdlib.h>
#include "my_tools.h"
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

	

int main() {
	int arr[9] = {8,2,6,4,3,1,5,7,9};
	cout << "排序前" << endl;
	for (int i = 0; i < 9; i++)
	{
		cout << arr[i] << "  ";

	}
	cout << endl;
	//开始冒泡程序
	for (int i = 0; i < 9; i++)
	{
		for (int j = 0; j < 9 - i - 1; j++)
		{
			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 < 9; i++)
	{
		cout << arr[i] << "  ";

	}
	cout << endl;
	system("pause");
		
}


	

第2种

#include <iostream>

using namespace std;

void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(arr[j], arr[j + 1]);
            }
        }
    }
}

int main() {
    int arr[] = {5, 2, 9, 4, 7, 3};
    int n = sizeof(arr) / sizeof(arr[0]);

    cout << "Original array: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }

    bubbleSort(arr, n);

    cout << "\nSorted array: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }

    return 0;
}

二维数组

C++中二维数组是由多个一维数组组成的数组。一般来说,使用二维数组可以方便地处理具有多个维度的数据,例如矩阵。

定义一个二维数组的语法如下:

数据类型 数组名[行数][列数];

例如,下面的代码定义了一个名为matrix的二维数组,它有3行和4列:

int matrix[3][4];

我们可以通过指定行数和列数来初始化二维数组,例如:

int matrix[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};

使用二维数组时,可以使用两个循环来遍历所有元素。例如,下面的代码遍历了一个3行4列的矩阵,并打印出每个元素的值:

for(int i=0; i<3; i++) {
    for(int j=0; j<4; j++) {
        std::cout << matrix[i][j] << " ";
    }
    std::cout << std::endl;
}
int arr[2][3]=
{
	{1,2,3},
	{4,5,6}
};

int arr[2][3] = {1,2,3,4,5,6,}

查看二维数组行数和列数多少

数组的行数 :  sizeof(数组)/sizeof(数组[0])
数组的列数 :  sizeof(数组[0])/sizeof(数组[0][0])

其中,sizeof(arr) 表示数组总共占用的字节数,sizeof(arr[0]) 表示数组中第一行占用的字节数。通过这两个值的比较即可得到行数和列数。注意,此方法仅适用于静态数组,对于动态分配的二维数组需要使用其他方式获取行数和列数。

二维数组的案例,用于存储学生的成绩信息并打印输出:

#include <iostream>
using namespace std;

int main() {
		
	 //onst是一个关键字,用于限制变量、指针或者函数的值或参数在程序的执行过程中不能被修改
    const int NUM_STUDENTS = 3; // 学生数量
    const int NUM_SUBJECTS = 2; // 科目数量

    // 声明二维数组用于存储学生的成绩信息
    int grades[NUM_STUDENTS][NUM_SUBJECTS];

    // 循环输入每个学生的成绩
    for (int i = 0; i < NUM_STUDENTS; i++) {
        cout << "请输入第 " << i+1 << " 个学生的成绩:" << endl;
        for (int j = 0; j < NUM_SUBJECTS; j++) {
            cout << "科目 " << j+1 << ":";
            cin >> grades[i][j];
        }
    }

    // 循环输出每个学生的成绩
    for (int i = 0; i < NUM_STUDENTS; i++) {
        cout << "第 " << i+1 << " 个学生的成绩:" << endl;
        for (int j = 0; j < NUM_SUBJECTS; j++) {
            cout << "科目 " << j+1 << ":" << grades[i][j] << endl;
        }
    }

    return 0;
}

头文件定义: 文件.h

#include <iostream>
using namespace std;
写入创建的函数,函数声明

函数声明.cpp中要调用头 文件.h文件

#include  文件.h

主函数文件也要调用 头 文件.h

#include  文件.h

写一个加法的函数

int main() {
    int a = 10, b = 20;
    int sum = add(a, b);  // 调用 add 函数计算 a 和 b 的和
    cout << "The sum of " << a << " and " << b << " is " << sum << endl;
    return 0;
}

写一个函数的调用的示例代码

#include <iostream>

// 定义一个函数
int add(int a, int b) {
    return a + b;
}

int main() {
    // 调用函数
    int result = add(2, 3);
    
    // 打印函数的返回值
    std::cout << "The result is: " << result << std::endl;
    
    return 0;
}

指针

int * p = NULL; //空指针用于给指针变量进行初始化,这个为空指针

int * p = 0xxx; //野指针就是非法指针,对指定地址没有权限

int a=10
int * p
p = &a //指针指向数据a的地址

c++中sizeof

c++中的野指针

C++ 中的野指针是指一个指针变量,它保存了一个无效或者未初始化的内存地址,即一个不受控制的地址。这种指针可能指向一个没有分配给你的内存位置,或者指向一个已经被释放的内存区域。野指针是一种常见的编程错误,可能会导致程序崩溃、未定义行为或者不可预测的结果。

以下是一个例子,展示了野指针的情况:

#include <iostream>

int main() {
    int *wildPtr;  // 未初始化的指针,成为野指针

    // 假设在这里发生了一些代码,没有为 wildPtr 分配内存

    // 尝试解引用野指针会导致未定义行为
    // int value = *wildPtr;  // 这行代码会导致问题

    return 0;
}

在这个示例中,指针 wildPtr 被声明为一个整数指针,但是没有被初始化或者分配内存。尝试解引用这个指针将会导致未定义行为,因为它指向了一个未知的内存地址。

为了避免野指针问题,你可以遵循以下几点:

  1. 初始化指针:在声明指针的同时,将其初始化为 nullptr,以确保它不包含任何无效地址。在 C++11 及之后的标准中,可以使用 nullptr 来初始化指针。

    int *ptr = nullptr;  // 初始化指针为 nullptr
    
  2. 指针使用前检查:在使用指针之前,先检查它是否为 nullptr,以避免解引用野指针。

    if (ptr != nullptr) {
        int value = *ptr;  // 只有在指针不为 nullptr 时解引用
    }
    
  3. 谨慎使用动态内存分配:使用 new 关键字分配内存时,要确保在不需要使用这块内存时使用 delete 释放它。避免忘记释放内存,以防止出现野指针。

    int *dynamicPtr = new int;
    // 使用 dynamicPtr
    delete dynamicPtr;  // 释放内存,避免野指针
    

总之,野指针是一个需要注意的问题,为了避免未定义行为和程序崩溃,始终确保你的指针在使用前都是有效和正确初始化的。

const修饰指针

常量指针:指针指向可以改,指针指向的值不能修改
const int * p = &a;


指针常量:指针指向不能修改,指针指向的值可以修改
int * const p = &a;

指针指向和指针指向的值都不能修改
const int * const p = &a

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

指针指向数组

创建一个数组
int arr[4] = {1,2,3,4};
创建一个指针,指向arr数组
int * p = arr
第一个元素为*p
p++
第二个元素

指针和函数

在这里插入图片描述

三种值的传递方式:值传递、引用传递和指针传递。

C++中有三种值的传递方式:值传递、引用传递和指针传递。

  1. 值传递:

值传递是将函数参数的值复制一份给函数的形参,形参和实参之间没有任何关系,函数运行结束后,形参的值也会被销毁,不会对实参产生影响。

示例代码:

#include <iostream>
using namespace std;
//形参,形参进行改变也改变不了实参的值
void swap(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}
//实参
int main()
{
    int x = 10, y = 20;
    swap(x, y);
    cout << "x = " << x << ", y = " << y << endl;
    return 0;
}

输出结果为:

x = 10, y = 20

可以看到,虽然在swap函数中交换了a和b的值,但是在main函数中x和y的值并没有被改变,因为是值传递,函数中的a和b只是x和y的拷贝。
在这里插入图片描述

  1. 引用传递:

引用传递是将函数参数的引用传递给函数的形参,形参和实参之间共用同一个内存地址,函数运行结束后,形参和实参都指向同一个内存地址,实际上是对实参进行的修改。

示例代码:

#include <iostream>
using namespace std;

void swap(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}

int main()
{
    int x = 10, y = 20;
    swap(x, y);
    cout << "x = " << x << ", y = " << y << endl;
    return 0;
}

输出结果为:

x = 20, y = 10

可以看到,使用引用传递的方式,函数中的a和b是x和y的引用,实际上是对x和y进行的操作,所以在交换之后,x和y的值得到了真正的修改。

  1. 指针传递:

指针传递是将函数参数的指针作为实参传递给形参,形参是指针类型,可以通过指针来操作实参的值,实际上和引用传递的方式十分相似。

示例代码:

#include <iostream>
using namespace std;

void swap(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main()
{
    int x = 10, y = 20;
    swap(&x, &y);
    cout << "x = " << x << ", y = " << y << endl;
    return 0;
}

输出结果和引用传递的方式相同:

x = 20, y = 10

总的来说,值传递只是传递了实参的一个副本,使用时要注意,如果需要在函数中修改实参的值,应该使用引用传递或指针传递的方式。

函数的声明

返回类型 函数名称(参数列表);

int add(int a, int b);

以下是关于函数声明的一些注释:

函数声明只需要描述函数的接口,不需要具体实现。
函数声明通常放在头文件中,以供其他文件使用。
如果函数在引用前没有声明,则编译器会报错。
函数可以在一个文件中声明,而在另一个文件中实现。
同一个文件中的函数可以在 main 函数之后定义,但是它们需要在 main 函数之前被声明。

函数的分文件编写

**作用:**让代码结构更加清晰

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

  1. 创建后缀名为.h的头文件
  2. 创建后缀名为.cpp的源文件
  3. 在头文件中写函数的声明
  4. 在源文件中写函数的定义

示例:

1:swap.h文件

//
#include<iostream>
using namespace std;

//实现两个数字交换的函数声明
void swap(int a, int b);

2:swap.cpp文件

//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;
}

3:main函数文件

//main函数文件
#include "swap.h"
int main() {

	int a = 100;
	int b = 200;
	swap(a, b);

	system("pause");

	return 0;
}

结构体:自定义数据类型

创建自定义数据类型
struct Struct{
	string name;
	int age;
	int score;
};

通过main函数调用自定义数据类型
int main(){
//方法1赋值
	struct Struct s1;
	s1.name = "张三"; //调用自定义的数据name
	s1.age = 18;		//调用自定义的数据age
	s1.score = 100;  //调用自定义的数据score

//方法2赋值
struct Struct s2 = {"张三",18,100};
}


//方法3:直接在定义函数后写上s3,对s3进行调用
struct Struct{
	string name;
	int age;
	int score;
}s3;

	s3.name = "张三"; //调用自定义的数据name
	s3.age = 18;		//调用自定义的数据age
	s3.score = 100;  //调用自定义的数据score



结构体数组

struct 结构体名 数组名[元素个数] = {{},{},{},{}}

创建自定义数据类型
struct Struct{
	string name;
	int age;
	int score;
};
使用main()函数进行数组的添加
main(){
	struct Struc stuarray[3] = 
	{
		{"张三",18,100}
		{"李四",19,82}
		........
	};
}
通过遍历结构体数组
for(int i =0 ;i<3,i++)
	{
		cout<<"姓名"<<stuarray[i].name
		<<"姓名"<<stuarray[i].age
		<<"姓名"<<stuarray[i].score<<endl;
	}


使用结构体指针

struct Struct{
	string name;
	int age;
	int score;
};
int main(){
	Struct s = {"张三",18,100};
	Struct * p = &s
	cout>> p->name>>endl;
	system("pause")
	return 0 ;
}

结构体嵌套结构体

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

struct teacher
{
	string name;
	int age;
	int score;
	struct student stu;   //嵌套上面结构体
}
main(){
	teacher t;
	t.name = "老师"
	....
	t.stu.name = "学生"
	.....
}


结构体做参数

注意如果要修改主函数中的数据,用值传递,反之用地址传递,
struct student
{
	string name;
	int age;
	int score;
};
//值传递
void printStudent1(struct student s)
{
	cout<<s.name<<....<<endl;
}
//地址传递
void printStudent2(struct student * p)
{
	p->age = 150;                  //这里的修改也可以对主函数上进行修改,如果是值函数传递,主函数不会修改而且还要进行备份,占用空间大 
	cout<<p -> name <<....<<endl;     //使用箭头传递 ->
}


main(){
	struct student s;
	s.name = "老师"
	printStudent1(s);
	printStudent2(&s);
}

结构体中的const使用场景

作用:用const来防止误操作
struct student
{
	string name;
	int age;
	int score;
};
//将函数中的形参改为指针,可以减少内存空间,而且不会复制新的副本出来
void printStudent1(const  student *s)   //为了防止误操作在形参中加入const的

{
	//s->age = 150;                  //这里的修改也可以对主函数上进行修改,如果是值函数传递,主函数不会修改而且还要进行备份,占用空间大 ,加入const之后就不能在这上面进行修改

	cout<<s->name<<....<<endl;     //使用的是指针地址用->指向
}


main(){
	struct student s;
	s.name = "老师"
	printStudent1(&s);
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

利用new关键字,可以将数据开辟到堆区

int * func()
{
	//利用nue关键字,开辟到堆区
	//指针本质也是局部变量,放在栈上,指针保存的数据存放在堆区
	int * p = new int(10)   //
	return p;
}
int main()
{
	//在堆区开辟数据
	int * p = func();  
	system("pause")
	
}

利用delete来手动释放

在这里插入图片描述

delete p;

静态变量

static  int  变量名 = 10;  //静态变量
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枭玉龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值