目录
重点:为何for新用法遍历中会出现“int (&row)[4]而不是int row[4]”?
Void类型的指针
Void指针的重要性质
① void*可以通过static_cast转化为其他任何类型的指针;
② void*类型的指针不可以使用解引用运算符*使其指向对应的内存;
③ void*类型的指针虽然可以和非void指针相互强制类型转换,但是最好不要从void*转化为非void指针。
Void*的用法
// C++复合类型.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <string>
using namespace std;
void ShowInf(void* Data)
{
const char* StringData = static_cast<const char*>(Data);
cout << StringData << endl;
}
int main()
{
string Name{ "45s4a54ad" };
ShowInf((void*)Name.c_str()); // 用void*作为形参进行参数传递
int var = 9;
void* ptr = &var;
//cout << *ptr << endl; //不可以对于void*类型的指针使用解引用操作
//ptr++; //不可以进行指针的偏移
cout << static_cast<int*>(ptr) << endl; // 强制类型转换(但这样不太安全)
}
神奇的bool型变量
当bool型变量用于指针时,可以判断指针是否非空。
指针的隐式转换
#include <iostream>
using namespace std;
int main()
{
void* ptr = nullptr;
if (ptr) // 此时ptr隐式转换为布尔型变量,即true/false
{
cout << "指针为空" << endl;
}
}
指针的显式转换
#include <iostream>
using namespace std;
int main()
{
void* ptr = nullptr;
bool trueorfalse = ptr;
if (trueorfalse) // 此时ptr转化为了布尔型变量,即true/false
{
cout << "指针为空" << endl;
}
}
如何创建指针的引用?
指针的引用与引用的指针
我们要明确两点:
① 指针指向的是一个内存区域;
② 引用是不分配内存的,变量的引用就相当于生成一个该变量的别名。
因此,存在指针的引用,但是不存在引用的指针(引用没有内存区域,指针无从下手)。
代码示例
#include <iostream>
using namespace std;
int main()
{
int var = 10;
int* ptr = &var;
int* &ptr1{ ptr }; // 指针的引用
cout << *ptr1 - *ptr << endl;
}
数组指针与指针数组的区别
区别说明
指针数组指的是数组内部的元素全为指针型变量;
数组指针指的是指向特定形式数组的指针。
代码示例
#include <iostream>
using namespace std;
int main()
{
int *arr[10] = { nullptr };
int(*arr1)[10]; // 必须指向有10个元素的数组
int arr2[10] = { 0 }, arr3[3] = { 0 };
//arr1 = &arr3; // 指向的数组不符合要求
arr1 = &arr2; // 指向的数组符合要求
}
C风格字符数组的操作
C风格字符串处理函数简介
函数调用格式 | 函数功能 |
Int Strcmp(const char* var1, const char* var2) | 比较字符型数组var1与var2 |
Const char* Strchr(const char* var1, const char var2) | 在var1中查找特定字符var2并返回地址 |
Char* Strcpy(char* var1, const char* var2) | 将var2拷贝至var1中并返回拷贝后的var2 |
Char* Strcat(char* var1, const char* var2) | 将var2连接至var1中并返回连接后的var1 |
代码示例
#include <iostream>
using namespace std;
int main()
{
const char name1[] = "sasasa", name2[] = "suaisais";
char name3[30], *CharPlace; // C风格字符串的劣势就在于"必须预留充分的空间供后续字符串操作使用"
int StringLength;
bool Comp;
strcpy(name3, name1); // 将name1复制到name3当中
cout << "拷贝后name3为" << name3 << endl;
strcat(name3, name2); // 将name2拼接至name3之后
cout << "拼接后的name3为" << name3 << endl;
StringLength = strlen(name3);
cout << "name3的长度为" << endl;
Comp = strcmp(name2, name1); // name2与name1比较
cout << "name2与name1谁更大:" << Comp << endl;
CharPlace = const_cast<char*>(strchr(name2, 's')); // 找出第一个s字符出现的位置并且返回指针地址
cout << "name2中第一个's'的相对地址为" << CharPlace - name2 + 1 << endl;
}
轻松访问数组的开头与结尾
易错点解析
Begin(数组首地址) 返回数组的第一个元素的地址
End(数组首地址) 返回数组最后一个元素地址的后一个地址
代码示例
#include <iostream>
using namespace std;
int main()
{
int arr[5] = { 0,1,2,3,4 };
cout <<"数组的首元素为"<< *begin(arr) << endl;
cout << "数组的末尾元素为" << *(end(arr) - 1) << endl;
}
For函数的新用法
For函数中参数的不同类型
For(DataType var: 数组首地址arr) | 数组元素采用值传递的方式将值传递给var |
For(DataType &var: 数组首地址arr) | var变量是数组arr中元素的引用 |
代码示例
#include <iostream>
using namespace std;
int main()
{
int arr[] = { 0,1,2,3,4,5 };
for (int var: arr) // 从begin(arr)遍历到end(arr)-1
{
cout << var << endl;
}
}
多维数组
多维数组简介
所谓所谓数组只不过是多个一维数组的组合,多维数组最大的难点就在于数组的遍历,这里给出三种数组遍历方式:指针遍历,引用遍历,for新用法遍历。
三种多维数组遍历方式
#include <iostream>
using namespace std;
int main()
{
int arr[][4] = { 1,2,3,4,5,6,7,8 };
// 引用遍历
int(&arr2)[4] = arr[0]; // 使用引用的方式遍历第一行元素
for (int& var: arr2)
{
cout << var << endl;
}
// 指针遍历
int (*ptr)[4] = arr;
for (; ptr != arr+2; ptr++) // 行遍历
{
int* ptr1 = *ptr;
for (; ptr1 != (*ptr) + 4; ptr1++) // 列遍历
{
cout << *ptr1 << endl;
}
}
// for新用法
int(&row)[4] = arr[0];
for (int (&row)[4]: arr) // 行循环
{
for (int var: row) // 列循环
{
cout << var << endl;
}
}
}
重点:指针遍历解析
Int (*Ptr)[4] 定义了一个只能指向4个整形元素的数组指针,最外层的for循环是行循环每次++移动4个int变量占用的内存空间,最里层for循环为列循环在每行地址的基础上每次++一个int变量占用的空间。
重点:为何for新用法遍历中会出现“int (&row)[4]而不是int row[4]”?
因为我们知道静态数组不可以进行一次性赋值操作,因此我们用int &row[4]来引用arr数组的每一行,在在此基础上访问每一行的每一列元素。