工作室网站源码,jquery特效网站,用什么网站做ppt,工业和信息化部发短信是怎么回事✨博客主页何曾参静谧的博客#x1f4cc;文章专栏「C/C」C/C程序设计#x1f4da;全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C」C/C程序设计「Win」Windows程序设计「算法」数据结构与算法「File」数据文件格式 目录 一、术语…
✨博客主页何曾参静谧的博客文章专栏「C/C」C/C程序设计全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C」C/C程序设计「Win」Windows程序设计「算法」数据结构与算法「File」数据文件格式 目录 一、术语介绍二、指针声明与赋值2.1、指针声明2.2、指针赋值 三、多级指针四、指针运算4.1、指针的加法运算4.2、 指针的减法运算4.3、 指针的递增和递减运算4.4、 比较运算 五、常量与指针5.1、常量指针5.2、指针常量5.3、常量指针常量 六、数组与指针6.1、重命名数组类型6.2、数组指针6.2.1、一维数组指针6.2.2、二维数组指针6.2.3、多维数组指针 6.3、指针数组 七、函数与指针7.1、重命名函数类型7.2、函数参数传递为指针7.3、函数返回值为指针7.4、函数指针7.5、回调函数应用 八、堆空间与指针8.1、动态分配内存 九、数据结构与指针十、类与指针十一、void* 指针十二、指针阅读技巧十三、注意事项 一、术语介绍 指针的本质 是一种特殊的变量 指针声明赋值和访问 在声明指针时需要使用 * 符号来表示该变量是一个指针变量使用符号来取变量的地址。可以将变量的地址赋给指针例如 int value 10; int* ptr value;这样 ptr 将指向 value 的内存地址。通过指针可以访问变量的值例如 *ptr 20; 可以将指针所指向的变量的值改为 20。 野指针和悬挂指针 如果指针没有被初始化或者指向已经释放的内存地址就称为野指针。悬挂指针是指指针在程序的生命周期内超出了其所指向的变量的作用域而仍然保持有效。int* ptr NULL; 常量与指针 目的是是指针的值与地址不被更改。 数组与指针 指针可以用于处理数组。通过将指针与索引结合使用可以遍历数组元素、访问特定位置的元素或者实现动态数组。 函数与指针 函数参数传递通过指针作为函数参数可以在函数中对传入的变量进行修改。这样可以传递复杂的数据结构减少数据的拷贝开销。 函数返回值函数可以返回指针以便在函数外部使用函数内部创建的对象。这在需要保留函数内部创建的对象并在其他地方使用时非常有用。 函数指针指针可以指向函数从而允许通过指针调用特定的函数。这使得函数可以像数据一样被传递、存储和操作。 动态内存分配 使用 new 运算符可以动态地在堆heap上分配内存并返回指向该内存的指针。通过这种方式可以在运行时动态地分配和释放内存例如 int* value new int;。使用 delete 运算符来释放通过 new 运算符分配的内存。这样可以确保在不再需要某段内存时将其还给系统避免内存泄漏。 数据结构 指针广泛用于实现各种数据结构如链表、树、图等。通过指针可以动态连接和操作多个对象。 硬件交互 在一些底层编程领域指针常用于直接访问内存地址从而与硬件或操作系统进行交互。 二、指针声明与赋值
2.1、指针声明
//*指针声明以下两种都可以。
数据类型 *变量名; int *a;
数据类型* 变量名; int* a;个人采用这种比较直观2.2、指针赋值
int number 5;
int* ptr number;//指针的定义与赋值图片素材来源动画讲编程 三、多级指针 int main() {int number 5;int* ptr1 number;int** ptr2 ptr1;int*** ptr3 ptr2;
}四、指针运算 指针运算是对指针进行数学运算以在内存中导航和访问数据。指针运算包括指针的加法、减法和比较操作。 4.1、指针的加法运算 当一个指针与一个整数相加时这个整数会乘以指针所指向类型的大小以字节为单位然后将结果加到指针中。例如 int* ptr somePointer;
ptr ptr 3; // 将指针向后移动 3 个 int 的大小在上述例子中ptr 指针向后移动了 3 个 int 大小的距离。 4.2、 指针的减法运算 当两个指针相减时它们之间的距离以数组元素或对象的个数为单位将被计算并返回结果作为整数。例如 int* ptr1 somePointer1;
int* ptr2 somePointer2;
int diff ptr1 - ptr2; // 计算两个指针之间的距离在上述例子中diff 将包含 ptr1 和 ptr2 之间的元素或对象个数。 4.3、 指针的递增和递减运算 可以使用递增或递减运算符直接修改指针的值使其指向下一个或上一个元素。例如 int* ptr somePointer;
ptr; // 将指针移动到下一个 int在上述例子中ptr 指针被递增使其指向下一个 int。 4.4、 比较运算 可以通过比较两个指针的大小关系来确定它们是否指向相同的内存区域或者在内存中的位置先后关系。例如 int* ptr1 somePointer1;
int* ptr2 somePointer2;
if (ptr1 ptr2) {// ptr1 在 ptr2 之前
} else if (ptr1 ptr2) {// ptr1 在 ptr2 之后
} else {// ptr1 和 ptr2 指向相同的内存位置
}在上述例子中我们可以根据指针之间的比较结果执行相应的操作。 需要注意的是指针运算必须在合法的内存地址范围内进行。还要注意在进行指针运算时一定要确保不会发生指针指向未分配的内存或者超出可访问范围的情况。 五、常量与指针 口诀左数右指const在左边时数据为常量const在右边时指针为常量 5.1、常量指针 常量指针地址可变指向数据不可变 const int* p;int const* p; #include stdio.h
int main(){int i 0;const int* p1 i;int const* p2 i;*p1 1; // compile errorp1 NULL; // ok*p2 2; // compile errorp2 NULL; // okreturn 0;
}5.2、指针常量 指针常量地址不可变指向数据可变 int* const p; #include stdio.h
int main(){int i 0;int* const p3 i;*p3 3; // okp3 NULL; // compile errorreturn 0;
}5.3、常量指针常量 常量指针常量地址不可变指向数据不可变 const int* const p; #include stdio.h
int main(){int i 0;const int* const p4 i;*p4 4; // compile errorp4 NULL; // compile errorreturn 0;
}六、数组与指针 数组的类型是由元素类型和数组大小共同决定的。 数组声明数组类型int array[5]int[5]int matrix[3][3]int[3][3]
6.1、重命名数组类型
//格式
typedef type(name)[size];
//数组类型
typedef int(AINT5)[5];
typedef doubel(ADOUBLE)[10];
//数组定义
AINT5 iArray;
ADOUBLE dArray;6.2、数组指针 数组指针是一个指针指向对应类型的数组。 int arr[] {1, 2, 3, 4, 5}; int* ptr arr; 6.2.1、一维数组指针 一维数组指针是指向一维数组的指针变量。它可以用于访问和操作一维数组中的元素。在C中可以使用指针来表示一维数组指针。 #include iostream
int main() {int arr[] {1, 2, 3, 4, 5};int* ptr arr; // 声明一个指向整型的指针并指向数组的第一个元素// 访问一维数组中的元素std::cout *ptr std::endl; // 输出1std::cout *(ptr 2) std::endl; // 输出3// 修改一维数组中的元素*ptr 100;*(ptr 2) 300;// 打印修改后的值std::cout *ptr std::endl; // 输出100std::cout *(ptr 2) std::endl; // 输出300return 0;
}在上述示例中我们首先定义并初始化了一个整数类型的一维数组int arr[]。然后我们声明了一个指向整数的指针int* ptr。 接下来我们将指针ptr指向数组的第一个元素数组名即为指向第一个元素的指针这样我们就可以使用ptr来访问和修改一维数组中的元素了。 使用一维数组指针时可以使用解引用操作符*来访问指针指向的元素值可以使用指针算术运算如来访问其他索引处的元素。例如ptr 2将指针移动两个位置然后通过解引用操作符来访问相应的元素。 6.2.2、二维数组指针 二维数组指针是指向二维数组的指针变量。它可以用于访问和操作二维数组中的元素。在C中可以使用指针数组或双重指针来表示二维数组指针。 #include iostream
int main() {int arr[3][4] {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};int (*ptr)[4] NULL; // 声明一个指向包含4个整数的数组的指针ptr arr; // 将指针指向二维数组// 访问二维数组中的元素std::cout ptr[0][0] std::endl; // 输出1std::cout ptr[1][2] std::endl; // 输出7// 修改二维数组中的元素ptr[0][0] 100;ptr[1][2] 200;// 打印修改后的值std::cout ptr[0][0] std::endl; // 输出100std::cout ptr[1][2] std::endl; // 输出200return 0;
}在上述示例中我们首先声明并初始化了一个3x4的二维整数数组int arr[3][4]。然后我们声明了一个指向包含4个整数的数组的指针int (*ptr)[4]。 接下来我们将指针ptr指向二维数组arr这样我们就可以使用ptr来访问和修改二维数组中的元素了。 使用二维数组指针时可以使用类似于二维数组的语法来访问和修改元素可以使用ptr[i][j]的形式。在内存中二维数组元素在一维地址空间中是按行连续存储的。 6.2.3、多维数组指针 多维数组指针是指向多维数组的指针变量。它可以用于访问和操作多维数组中的元素。在C中可以使用多级指针来表示多维数组指针。 #include iostream
int main() {int arr[2][3][4] {{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}},{{13, 14, 15, 16},{17, 18, 19, 20},{21, 22, 23, 24}}};int (*ptr)[3][4] NULL; // 声明一个指向包含3个二维数组的指针变量ptr arr; // 将指针指向三维数组// 访问三维数组中的元素std::cout *(*(*(ptr 1) 2) 3) std::endl; // 输出24// 修改三维数组中的元素*(*(*(ptr 0) 1) 2) 100;// 打印修改后的值std::cout *(*(*(ptr 0) 1) 2) std::endl; // 输出100return 0;
}在上述示例中我们首先声明并初始化了一个2x3x4的三维整数数组int arr[2][3][4]。然后我们声明了一个指向包含3个二维数组的指针int (*ptr)[3][4]。 接下来我们将指针ptr指向三维数组arr这样我们就可以使用ptr来访问和修改三维数组中的元素了。 使用三维数组指针时可以使用多级解引用操作符*来访问指针指向的元素值。例如*(*(*(ptr 1) 2) 3)将移动指针到下一个二维数组然后移动到下一个一维数组最后通过解引用操作符访问该一维数组的第4个元素。 6.3、指针数组 指针数组是一个数组其中元素都是指针。 type* pArray[n]; int* pointerArray[] {a, b, c}; // 声明并初始化指针数组 //下面是一个简单的示例展示了如何声明、初始化和使用指针数组
#include iostream
int main() {int a 10;int b 20;int c 30;int* pointerArray[] {a, b, c}; // 声明并初始化指针数组// 访问指针数组的元素并打印对应值std::cout *pointerArray[0] std::endl; // 输出10std::cout *pointerArray[1] std::endl; // 输出20std::cout *pointerArray[2] std::endl; // 输出30// 修改指针数组元素的值*pointerArray[0] 100;*pointerArray[1] 200;*pointerArray[2] 300;// 打印修改后的值std::cout *pointerArray[0] std::endl; // 输出100std::cout *pointerArray[1] std::endl; // 输出200std::cout *pointerArray[2] std::endl; // 输出300return 0;
}在上述示例中通过定义int* pointerArray[]来声明一个指针数组。使用花括号初始化将变量a、b和c的地址作为指针数组的元素进行存储。 然后我们通过解引用操作符*来访问指针数组中的元素并输出对应的值。可以直接修改指针数组元素指向的值通过解引用操作符*修改对应内存地址上的值。最后打印修改后的值进行验证。 七、函数与指针 函数的本质是一段内存中的代码占用一片连续内存。 函数名就是函数体代码的起始地址函数入口地址。 如Type(*pFunc)(Type1,Type2) func; 与Type(*pFunc)(Type1,Type2) func;两者等价。 函数声明函数类型int sum(int a, int b)int (int,int)void swap(int* a,int* b)void (int*,int*)void fun(void)void (void)
7.1、重命名函数类型
#include iostream// 原始的函数类型声明
typedef int (*MathFunction)(int, int);// 定义一个函数类型为 MathFunction 的函数
int add(int a, int b) {return a b;
}int subtract(int a, int b) {return a - b;
}int main() {// 声明函数指针并初始化MathFunction mathFuncPtr nullptr;// 指向 add 函数mathFuncPtr add;std::cout add(3, 2) mathFuncPtr(3, 2) std::endl;// 指向 subtract 函数mathFuncPtr subtract;std::cout subtract(3, 2) mathFuncPtr(3, 2) std::endl;return 0;
}7.2、函数参数传递为指针 函数参数传递为指针是一种常见的方式用于在函数中对变量进行修改或者引用变量的原始值。通过将指针作为参数传递给函数函数可以直接访问和修改指针所指向的内存地址上的数据。 #include iostream// 通过指针修改变量值
void incrementByPointer(int* num) {// 使用解引用操作符(*)修改指针所指向的内存中的值(*num);
}// 通过指针交换两个变量的值
void swapByPointer(int* a, int* b) {int temp *a;*a *b;*b temp;
}int main() {int num 10;int a 5, b 3;std::cout 初始值num num std::endl;incrementByPointer(num);std::cout 调用incrementByPointer后的值num num std::endl;std::cout 初始值a a , b b std::endl;swapByPointer(a, b);std::cout 调用swapByPointer后的值a a , b b std::endl;return 0;
}在上述代码中我们定义了两个函数incrementByPointer 和 swapByPointer。这两个函数都接受指针作为参数以实现对变量的修改。 在 incrementByPointer 中我们通过解引用操作符 * 来访问并修改指针所指向内存中的值。 在 swapByPointer 中我们使用指针来交换两个变量的值。通过解引用操作符 *我们可以访问指针所指向内存中的值并进行交换操作。 在主函数中我们声明了一个变量 num并调用 incrementByPointer 函数来增加其值。同样地我们声明了两个变量 a 和 b并调用 swapByPointer 函数来交换它们的值。 7.3、函数返回值为指针 函数返回值为指针是一种常见的方式用于从函数中返回动态分配的内存或者返回指向其他数据结构的指针。通过将函数的返回类型声明为指针函数可以返回一个指向特定类型数据的内存地址。 #include iostream// 返回动态分配内存的指针
int* createArray(int size) {int* arr new int[size];for (int i 0; i size; i) {arr[i] i 1;}return arr;
}// 返回指向全局变量的指针
int* getGlobalVariable() {static int globalVar 10;return globalVar;
}int main() {// 调用函数返回动态分配内存的指针int* dynamicArray createArray(5);for (int i 0; i 5; i) {std::cout dynamicArray[i] ;}std::cout std::endl;delete[] dynamicArray; // 释放动态分配的内存// 调用函数返回指向全局变量的指针int* pointerToGlobalVar getGlobalVariable();std::cout 全局变量的值 *pointerToGlobalVar std::endl;return 0;
}在上述代码中我们定义了两个函数createArray 和 getGlobalVariable。这两个函数都返回指针类型的值。 在 createArray 函数中我们使用 new 操作符动态分配一个整型数组并为其赋初值。然后我们返回这个动态分配内存的指针。 在 getGlobalVariable 函数中我们声明了一个静态局部变量 globalVar并将其地址返回。 在主函数中我们调用 createArray 函数创建一个包含一些数字的整型数组并打印数组中的每个元素。注意我们在使用完动态分配的内存后使用 delete[] 释放了这块内存。 接着我们调用 getGlobalVariable 函数获取全局变量的值并通过指针访问该变量的值。 7.4、函数指针 函数指针是指向函数的指针变量。它可以用于调用函数实现函数的动态绑定和回调等功能。函数指针的声明和使用方式与其他指针类型类似。 #include iostream
// 声明一个函数指针类型该函数接受两个整数参数并返回一个整数
typedef int (*ArithmeticFunction)(int, int);// 定义两个用于演示的加法和乘法函数
int add(int a, int b) {return a b;
}int multiply(int a, int b) {return a * b;
}int main() {// 声明一个函数指针变量并将其指向add函数ArithmeticFunction ptr add;// 使用函数指针调用函数int result ptr(2, 3); // 等同于调用add(2, 3)std::cout result std::endl; // 输出5// 将函数指针指向multiply函数ptr multiply;// 使用函数指针调用函数result ptr(2, 3); // 等同于调用multiply(2, 3)std::cout result std::endl; // 输出6return 0;
}在上述示例中我们首先通过typedef关键字定义了一个名为ArithmeticFunction的函数指针类型。该函数指针类型接受两个整数参数并返回一个整数。 接下来我们定义了add和multiply两个函数用于演示函数指针的用法。 在main函数中我们声明了一个函数指针变量ptr并将其初始化为add函数。然后使用函数指针变量调用add函数将结果输出。 接着我们将函数指针变量ptr指向multiply函数并再次使用函数指针调用multiply函数将结果输出。 函数指针可以在运行时动态地指向不同的函数可以将函数指针作为参数传递给其他函数实现回调功能或根据条件选择不同的函数执行逻辑等。 7.5、回调函数应用 通过函数指针作为参数使相同的代码实现不同功能 #include iostream
int add(int a, int b){return a b;
}
int mul(int a, int b){return a * b;
}
int calculate(int a[], int len, int(*cal)(int, int)){int ret a[0];for(int i1; ilen; i){ret cal(ret, a[i]);}return ret;
}
int main(){int a[5] {1,2,3,4,5};std::cout 1 ... 5 calculate(a, 5, add) std::endl; // 输出15std::cout 1 * ... * 5 calculate(a, 5, mul) std::endl; // 输出120return 0;
}八、堆空间与指针 堆空间是程序中预留且可用的内存区域 8.1、动态分配内存 c语言库#include stdlib.h 申请内存void* malloc(unsigned bytes)判断是否申请成功 释放内存void free(void* p)不可多次释放 //int* arr (int*)malloc(size * sizeof(int)); // 动态分配内存
//free(arr); // 释放动态分配的内存
#include stdio.h
#include stdlib.hint main() {int size 5;int* arr (int*)malloc(size * sizeof(int)); // 动态分配内存if (arr ! NULL) {// 使用动态分配的内存int i 0;for (i 0; i size; i) {arr[i] i 1;printf(%d , arr[i]);}printf(\n);free(arr); // 释放动态分配的内存}return 0;
}C使用new和delete进行内存动态分配和释放 int* p new int(10);
delete[] p;九、数据结构与指针 数据结构是一种组织和存储数据的方式它定义了数据元素之间的关系以及对这些数据元素进行操作的规则。指针是一种特殊的数据类型用于存储变量的内存地址。通过使用指针我们可以有效地在数据结构中操作和访问数据。 #include iostream// 定义一个简单的链表结构
struct Node {int data;Node* next;
};// 在链表末尾插入新节点
void insertNode(Node* head, int value) {// 创建新节点Node* newNode new Node;newNode-data value;newNode-next nullptr;if (head nullptr) {// 链表为空将新节点设为头节点head newNode;} else {// 找到链表末尾并将新节点插入Node* temp head;while (temp-next ! nullptr) {temp temp-next;}temp-next newNode;}
}// 遍历并打印链表中的每个节点
void printLinkedList(Node* head) {Node* temp head;while (temp ! nullptr) {std::cout temp-data ;temp temp-next;}std::cout std::endl;
}// 释放链表占用的内存
void deleteLinkedList(Node* head) {Node* temp head;while (temp ! nullptr) {Node* nextNode temp-next;delete temp;temp nextNode;}head nullptr;
}int main() {// 创建一个空链表Node* head nullptr;// 向链表中插入节点insertNode(head, 1);insertNode(head, 2);insertNode(head, 3);// 打印链表中的节点printLinkedList(head);// 删除链表释放内存deleteLinkedList(head);return 0;
}在上述代码中我们定义了一个简单的链表结构 Node其中的 next 成员是一个指向下一个节点的指针。 通过使用指针我们可以在 insertNode 函数中创建新的节点并将其插入链表的末尾。在 printLinkedList 函数中我们遍历链表中的每个节点并打印出节点的值。 主函数中我们首先创建一个空链表并通过调用 insertNode 函数向链表中插入节点。最后我们调用 printLinkedList 函数来打印链表中的节点值。 十、类与指针 类指针是指向类对象的指针变量。使用类指针可以操作、访问和传递类对象以实现动态创建和管理类实例的功能。 #include iostream
#include string
// 定义一个简单的Person类
class Person {
public:std::string name;int age;void introduce() {std::cout My name is name and I am age years old. std::endl;}
};int main() {// 声明一个指向Person类对象的指针Person* ptr;// 创建一个Person类对象并将指针ptr指向该对象Person person;person.name Alice;person.age 25;// 指向person类ptr person;// 通过类指针访问和操作类对象ptr-introduce();// 修改类对象的属性ptr-age 30;// 再次通过类指针访问和操作类对象ptr-introduce();return 0;
}在上述示例中我们定义了一个简单的Person类该类具有name和age属性以及一个introduce成员函数用于打印个人信息。 在main函数中我们首先声明了一个指向Person类对象的指针ptr。然后我们创建了一个名为person的Person类对象并通过指针ptr将其地址赋值给指针。 通过类指针ptr我们可以访问和操作类对象的成员。例如调用ptr-introduce()函数打印类对象的信息。 我们还可以通过类指针修改类对象的属性如ptr-age 30;。 类指针在实际应用中非常有用它允许动态创建和管理类对象。通过类指针可以在运行时创建和销毁对象以及在不同的函数之间共享和传递对象。 十一、void* 指针 void* 指针只能保存地址不能获取数据。 void* 可以与其他数据指针互相赋值。 int a 5;
void* p a;十二、指针阅读技巧 右左法则Right-Left Rule是一种用于解析复杂的C或C声明的技巧。它帮助程序员理解声明中各个部分的含义。 右左法则的规则如下 从变量名或标识符开始从右向左阅读声明。遇到括号时首先解析括号内的内容。解析指针(*)和数组([])符号注意左结合性。例如int* a[]应该解析为“a是一个数组其中元素是指向整数的指针”。解析函数参数列表及返回类型注意左结合性。例如int (*func)(int)应该解析为“func是一个指针指向一个函数该函数接受int类型的参数并返回一个int类型的值”。 int* (*funcPtr)(char*, double);// 使用右左法则解析上述声明
// funcPtr 是一个指针指向一个函数
// 该函数接受一个char*类型的参数和一个double类型的参数
// 并返回一个指向整数的指针在上述示例中我们有一个复杂的声明int* (*funcPtr)(char*, double)。根据右左法则我们可以逐步解析该声明。 从变量名funcPtr开始它是一个指针。指针指向一个函数使用括号括起来 (char*, double)。函数接受一个char*类型的参数和一个double类型的参数。函数返回一个指向整数的指针int*。 int (*p1)(int*,int (*f)(int*));
int (*p2[5])(int*);
int (*(*p3)[5])(int*);
int*(*(*p4)(int*))(int*);
int (*(*p5)(int*))[5];十三、注意事项 检查空指针 在使用指针之前应该始终进行空指针检查确保指针有有效的内存地址。可以使用条件判断语句比如 if (pointer ! NULL) 来检查指针是否为空。 避免野指针 避免使用未初始化或已释放的指针这被称为野指针。使用野指针可能会导致程序崩溃或产生不可预测的结果。在使用指针之前应该确保其已经正确初始化并且在不需要使用指针时及时释放内存。delete p; p NULL: 防止内存泄漏 在动态分配内存时要记得在不再需要使用内存时释放它以避免内存泄漏。内存泄漏会导致程序占用越来越多的内存最终可能导致系统性能下降或崩溃。使用free()函数C语言或delete运算符C来释放动态分配的内存。 确保类型匹配 指针与所指向的对象或变量的类型必须匹配。例如一个整型指针应该指向整型变量而不是字符或其他类型的变量。使用不匹配类型的指针可能会导致内存访问错误或数据损坏。 避免越界访问 指针通过存储变量的内存地址来访问其值。在使用指针时应该确保不对超出指针范围的内存进行访问。越界访问可能会导致程序错误、数据损坏和安全漏洞。 指针赋值问题 不同类型的指针是不能够进行赋值的。void*指针可以与其他数据指针相互赋值但不可以直接获取内存数据