数组

连续内存,相同数据类型
数组名地址

一维数组

定义 2.3.初始化
一维数组定义

数组名

  • 整个数组在内存中的长度
  • 首地址
sizeof(arr) // 整个数组占用内存空间
sizeof(arr[0]) // 每个元素占用内存空间
sizeof(arr) / sizeof(arr[0]) // 数组中**元素个数**

// 首地址
cout<< arr <<endl; // 十六进制
cout<< (int)arr <<endl; // 转换为十进制

二维数组

定义:列数要确定
![[二维数组定义.png]]

数组名

  • 查看二维数组所占内存空间
  • 获取首地址
int arr[2][3] = {
	{11,12,13},
	{21,22,23}
};

// 1. 内存空间
cout<< sizeof(arr) << endl; // 二维数组所占内存空间

cout<< sizeof(arr[0]) << endl; // 第一行

cout<< sizeof(arr[0][0]) << endl; // 第一个元素

// 行数
cout<< sizeof(arr) / sizeof(arr[0]) <<endl;
// 列数
cout<< sizeof(arr[0]) / sizeof(arr[0][0]) <<endl;

// 2. 首地址
cout<< arr <<endl; // 十六进制
cout<< (int)arr <<endl; // 转换为十进制

函数

函数定义

返回值类型 函数名 (参数列表)
{
	// 函数体
	return
}

函数声明

提前告诉编译器函数的存在

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

函数调用

使用定义好的函数
语法:函数名(参数);

值传递

函数调用时,实参数值传入给形参

值传递时,如果形参改变,不会影响实参
因为是另外开辟的空间,只不过将实参的值赋值给形参了而已

函数分文件编写

.h 头文件 : 函数声明
.cpp 源文件 :函数定义

指针

作用:间接访问内存

内存有地址编号,十六进制,从0开始记录
指针变量存的就是地址

定义和使用

// 数据类型 * 变量名
int a = 10;
int * p = &a; // & 取地址符,将变量a的地址,赋值给p

输出p:a地址
输出*p:解引用 ,输出地址指向的(指针指向内存中的数据)

指针所占内存空间

指针也是一种数据类型
指针存的是地址(十六进制数),在32位操作系统(x86)下,占用4个字节空间(64位 x64占8个字节)

// 实验:
cout<<sizeof(char *)<<endl;
cout<<sizeof(int *)<<endl;
cout<<sizeof(float *)<<endl;
cout<<sizeof(double *)<<endl;
// 都是4个字节

空指针和野指针

  1. 空指针 NULL:指针变量指向内存中编号为0的空间
    用途:初始化指针变量
    注意:空指针指向的内存不可访问
int * p = NULL;

cout<< *p << endl; // 访问空指针报错

内存编号0~255为系统占用内存,不允许用户访问

  1. 野指针:指针变量指向非法的内存空间
int * p = (int *)0x1100; // 指针变量p指向 内存编号为0x1100 的空间

cout<< *p << endl; // 访问野指针报错 没有申请内存

编译没问题(语法正确),但运行时报错

  1. 总结:空指针和野指针都不是我们申请的空间,因此不要访问
// 正确做法
// 1. 指向已有变量(见指针的定义和使用)
// 2. 动态申请(new)
int *p = new int(10); 
// 3. 初始化为nullptr(c++11后)
int *p = nullptr;

const修饰指针

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

int a = 10;
const int * p = &a;
// 指针的**指向**可以修改,但指针指向的**值**不能修改
p = &b; // ✅️
*p = 20; // ❌️

就是原先指向的值不能修改
![[常量指针.png]]

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

相当于p是常量,它的指向不能改

const int * const p = &a;

指针的指向,和指向的值,都不能改

指针和数组

利用指针访问数组中元素

int * p = arr; // arr 数组名本身就是地址,不用 &
// 访问第一个元素
cout << * p << endl;

// 利用指针遍历数组
for(int i=0;i<10;i++){
	cout<< *p <<endl;
	p ++ ; // 移动几个字节 取决于指针类型(int-4 char-1)
}

指针和函数

指针作函数参数,可以修改实参

[[#值传递]]
vs
地址传递

void swap(int *p1, int *p2)
{
	int temp = *p1; // 解引用 -> 指向a内存空间的值
	*p1 = *p2;
	*p2 = temp;
}

int main(){
	int a = 10;
	int b = 20;
	
	swap(&a, &b); // 传递地址
	
	cout<<a<<b; // a = 20 , b = 10 改变实参,完成交换
}

指针、数组、函数案例:冒泡排序

![[指针、数组、函数:冒泡案例.png]]

结构体

用户自定义的数据类型,可以存储不同的数据类型

定义和使用

语法:struct 结构体名 {结构体成员列表};
通过结构体创建变量
![[结构体变量.png]]

struct student
{
	// 成员列表
}s1; // 结构体变量

操作符“."访问成员

结构体数组

语法:

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

结构体指针

通过指针访问结构体中成员

需要用操作符 ->

struct student{
	// 结构体定义
	string name;
	int age;
};

int main(){
	struct student s1 = {"吴彦祖"18}; // 定义结构体变量 s1
	
	struct student *p = &s1;
	
	cout << p->name <<endl<< p->age <<endl;
}

结构体嵌套结构体

在结构体中定义另一个结构体作为成员

结构体做函数参数

传递方式:

  • 值传递:函数内部"."访问成员
  • 地址传递:函数内部"->"访问成员(利用指针
    不想修改主函数中的数据,用值传递,反之用地址
    地址传递还可以节省空间

结构体中const使用

用const:防止误操作
不能修改

结语

由于程序流程结构过于简单,所以没有进行叙述,有c语言基础足够(如果没有可以去听一下网课进行掌握~)
下篇会讲程序中的内存分区~有助于理解实参和形参的区别
以及引用(语法上是指针的省略)、
函数的默认参数重载~

更多推荐