怎么做网站 先简单的聊一下,wordpress 悬赏功能,百度提交入口网站怎么看,潍坊的网站开发公司在C语言中#xff0c;指针是一个非常重要的概念#xff0c;它提供了直接访问内存地址的能力。指针变量用于存储内存地址#xff0c;而不是数据值#xff0c;在某种意义上和门牌号具有相似含义#xff1a;指针是一个变量#xff0c;其存储的是另一个变量的内存地址#x…在C语言中指针是一个非常重要的概念它提供了直接访问内存地址的能力。指针变量用于存储内存地址而不是数据值在某种意义上和门牌号具有相似含义指针是一个变量其存储的是另一个变量的内存地址这个内存地址唯一的标识用于指向特定的内存位置。门牌号也是用来唯一标识一个具体的房屋或地址的但指针的使用要复杂得多涉及到内存的管理、指针的运算、野指针的避免等多个方面。在处理数组、字符串、动态内存分配以及函数参数传递等方面使得程序员们能够编写出更灵活、更高效的代码。
指针的概念
指针是一个变量其值为另一个变量的地址即直接指向内存中的某个位置指针的声明需要在变量类型前加上星号*像int *ptr;就声明了一个指向整数的指针变量ptr。
指针的用途和功能 动态内存管理C语言允许程序员在运行时动态地分配和释放内存通过指针来实现如使用malloc、calloc和realloc等函数分配内存使用free函数释放内存。 数组操作指针可以用来遍历数组因为数组名本质上是一个指向数组首元素的指针。使用指针进行数组操作比使用数组索引更加高效。 字符串处理在C语言中字符串是通过字符数组实现的。因此字符串操作如复制、拼接等可以通过指针操作来实现。 函数参数传递通过使用指针作为函数参数可以在函数内部修改外部变量的值实现数据的双向传递。 指向函数的指针指针也可以指向函数这使得可以将函数作为参数传递给其他函数或者通过指针调用函数。 指向指针的指针C语言允许创建指向指针的指针这在进行复杂数据结构如链表、树等的操作时非常有用。
指针操作的大概流程如下
指针的基础操作
声明并初始化指针
在定义指针前需要先声明一个整数变量(我定义的value)并初始化随后声明一个指向整数的指针变量(我声明的是pointer很多人习惯使用p)并初始化为value的地址 int value 10; int * pointer value;在C语言中这里的三种写法都是可以的
int* pointer value;
int * pointer value;
int *pointer value;随后即可通过访问指针来查询这个整型变量(value)的值 printf(通过指针访问的值: %d \n, *pointer); 完整代码如下
#include stdio.h int main() { int value 10; int *pointer value; printf(通过指针访问的值: %d\n, *pointer); return 0;
}输出内容通过指针访问的值: 10
修改指针指向的值
在C语言中,如果已经声明并初始化了一个指针可以做到只修改指针所指向的值原变量的数值不会改变。就好比结婚一样老实的Java程序员大锤和小美去民政局登记结婚为一个变量声明并初始化了一个指针但大锤满足不了小美了(原数值因为各种原因在某项功能中需要进行改动)小美又不想离婚(修改原变量值)于是小美就找到了老王来满足她(修改指针所指向的值)以后小美还可以找老陈、老宋、老李(多次修改指针所指向的值),但是这样会造成1.大锤没法活了(程序崩溃)2.孩子不是大锤亲生(野指针)3.家丑外扬(内存泄漏4.小美被玩坏了(数据损坏)。根据刚才的代码继续编写
#include stdio.h int main() { int value 10; int *pointer value; printf(通过指针访问的值: %d\n, *pointer); // 修改指针指向的值 *pointer 20; printf(修改后通过指针访问的值: %d\n, *pointer); printf(直接访问变量value的值: %d\n, value); return 0;
}输出内容可以看出指针所指向的值发生了更改而原变量的值未发生任何变化
取地址和解引用操作
在C语言中取地址操作是将变量的地址赋值给指针而解引用操作则是通过指针访问它所指向的变量的值。这两个操作在C语言的指针使用中非常重要它们允许我们通过指针间接地访问和操作内存中的数据。
修改一下之前的代码通过运算符将value的地址赋给了pointer进行了取地址操作
#include stdio.h int main() { int value 20; int *pointer; // 在指针变量中存储value的地址即取地址操作 pointer value; printf(value变量的地址: %p\n, value); printf(通过pointer指针访问value变量的值: %d\n, *pointer); return 0;
}输出中的0x7ffdee0e6ddc是变量value在内存中的地址内存地址是操作系统分配给程序用于存储数据的物理或虚拟内存位置每个程序运行时操作系统都会为其分配一块内存空间程序中的变量就存储在这块空间的特定地址上同时每次程序运行时操作系统可能会分配不同的内存地址给程序中的变量0x7ffdee0e6ddc这个地址只是在这次运行程序时有效下次运行时可能会有所不同。
指针的算术运算
指针的算术运算分为指针加减运算和指针相减运算 指针加减运算指针可以进行加减运算其结果是指针向前或向后移动若干个元素的距离不是字节移动的字节数取决于指针指向的数据类型。 指针相减运算两个指针相减的结果是两个指针之间相隔的元素个数要求两个指针指向同一块内存区域。 以下代码定义了两个数组一个short类型的dataset数组和一个double类型的bills数组每个数组都有SIZE 4个元素。然后它定义了两个指针变量pti和ptf分别指向这两个数组的起始位置,随后代码进入一个循环遍历这两个数组。在每次迭代中它都会计算并打印出pti和ptf指针在加上index值后的地址。这里pti index和ptf index分别表示pti和ptf指针向前移动index个short或double元素的位置。由于指针的加减运算是以它指向的数据类型的大小为单位进行的所以pti每次增加2个字节因为short类型通常占2个字节而ptf每次增加8个字节因为double类型通常占8个字节。在打印指针地址时代码将指针转换为void*类型。这是因为printf函数使用%p格式说明符来打印指针而%p期望一个void*类型的参数。将指针转换为void*类型可以确保无论指针指向什么类型的数据都能以统一的方式打印其地址。
#include stdio.h #define SIZE 4 int main()
{ short dataset[SIZE]; short *pti; short index; double bills[SIZE]; double *ptf; pti dataset; ptf bills; printf(%23s %15s\n, short pointers, double pointers); for (index 0; index SIZE; index) { printf(pointers %d: %10p %10p\n, index, (void*)(pti index), (void*)(ptf index)); } return 0;
}代码会在终端输出以下内容 short double
pointers 0: 0x7ffc8b926ef8 0x7ffc8b926f00
pointers 1: 0x7ffc8b926efc 0x7ffc8b926f10
pointers 2: 0x7ffc8b926f00 0x7ffc8b926f20
pointers 3: 0x7ffc8b926f04 0x7ffc8b926f30 指针的比较
在C语言中可以使用关系运算符如、、等来比较两个指针比较的是它们所指向的地址的大小。 这里定义了一个长度为10的数组array随后声明了三个指针ptr1、ptr2、ptr3,ptr1指向array的第3个元素 ,ptr2指向array的第6个元素 ,ptr3与ptr1指向相同的地址
#include stdio.h int main() { int array[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int *ptr1, *ptr2, *ptr3; ptr1 array[2]; // ptr1指向array的第3个元素 ptr2 array[5]; // ptr2指向array的第6个元素 ptr3 ptr1; // ptr3与ptr1指向相同的地址 // 比较ptr1和ptr2 if (ptr1 ptr2) { printf(ptr1 ptr2\n); } else { printf(ptr1 ptr2\n); } // 比较ptr1和ptr3 if (ptr1 ptr3) { printf(ptr1 ptr3\n); } else { printf(ptr1 ! ptr3\n); } // 比较ptr2和ptr1 if (ptr2 ptr1) { printf(ptr2 ptr1\n); } else { printf(ptr2 ptr1\n); } return 0;
}代码运行后再终端输出
ptr1 ptr2
ptr1 ptr3
ptr2 ptr1指针与数组
在C语言中数组名可以视为指向数组首元素的指针因此可以使用指针来遍历数组元素可以使用指针算术运算来访问数组中的元素。 以下代码中的dqys不仅代表了一个包含12个整数的数组同时也可以被看作是一个指向int类型的指针它指向dqys数组的第一个元素在随后的for循环中使用了指针算术运算来遍历数组dqys。表达式dqys index表示指针dqys向前移动index个int类型元素的位置。因为dqys是一个指向int的指针所以每次递增都会使指针地址增加sizeof(int)个字节。通过解引用操作符*可以获取该地址处的值即数组dqys中索引为index的元素的值。当index为0时*(dqys 0)就相当于dqys[0]它表示数组的第一个元素其值为31。同理*(dqys 1)则相当于dqys[1]它表示数组的第二个元素其值为28:
#include stdio.h#define MONTHS 12int main()
{int dqys[MONTHS] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int index;for (index 0; index MONTHS; index){printf(%2d 月有 %d 天. \n, index 1, *(dqys index));}return 0;
}代码输出内容如下 1 月有 31 天. 2 月有 28 天. 3 月有 31 天. 4 月有 30 天. 5 月有 31 天. 6 月有 30 天. 7 月有 31 天. 8 月有 31 天. 9 月有 30 天.
10 月有 31 天.
11 月有 30 天.
12 月有 31 天. 指针与函数
C语言中允许指针指向函数这使得可以将函数作为参数传递给其他函数或者通过指针调用函数同时也可以通过将指针作为函数参数传递可以在函数内部修改外部变量的值。 这里的modifyValue函数接收一个int类型的指针作为参数并通过该指针修改外部变量的值。add函数用来返回两个整数的和。executeFunction函数接收一个函数指针作为参数并通过该函数指针调用函数。随后在main函数中首先使用modifyValue函数通过指针修改外部变量的值。然后声明了一个函数指针functionPointer并将其指向add函数。最后将该函数指针作为参数传递给executeFunction函数并通过该函数指针调用add函数。
#include stdio.h // 定义一个函数该函数接收一个int类型的指针作为参数
void modifyValue(int *value) { //函数接收一个int类型的指针作为参数*value 10; // 通过指针修改外部变量的值
} int add(int a, int b) { // 函数用来返回两个整数的和 return a b;
} void executeFunction(int (*func)(int, int), int a, int b) { // 接收一个函数指针作为参数并调用该函数int result func(a, b); // 通过函数指针调用函数 printf(结果为: %d\n, result);
} int main() { int variable 0; printf(数值修改后: %d\n, variable); modifyValue(variable); // 将变量的地址传递给函数以修改其值 printf(数值修改前: %d\n, variable); // 使用函数指针调用函数 int (*functionPointer)(int, int) add; // 声明一个函数指针并将其指向add函数 executeFunction(functionPointer, 5, 3); // 将函数指针作为参数传递给executeFunction函数 return 0;
}动态内存分配
在C语言中提供了malloc和free函数用于动态内存分配和释放。malloc函数用于分配指定大小的内存空间并返回一个指向该空间的指针free函数用于释放已分配的内存空间。 下面代码中先声明了一个int类型的指针ptr并将其初始化为NULL。然后使用malloc函数动态分配了足够存储5个整数的内存空间并将返回的指针赋值给ptr。随后使用指针算术运算访问和修改动态分配的内存空间中的内容。之后使用for循环打印出动态分配的内存空间中的内容。最后使用free函数释放了已分配的内存空间并将ptr重新设置为NULL避免空指针。
#include stdio.h
#include stdlib.h int main() { int *ptr NULL; // 声明一个int类型的指针并初始化为NULL int n 5; // 存储5个整数 ptr (int*)malloc(n * sizeof(int)); // 使用malloc函数动态分配内存空间分配了n个int大小的内存空间并将返回的指针转换为int类型的指针 // 检查malloc函数是否成功分配了内存如果内存分配失败就退出程序 if (ptr NULL) { printf(内存分配GG了\n); return 1; } // 使用指针访问和修改动态分配的内存空间中的内容通过指针算术运算访问数组元素并赋值 for (int i 0; i n; i) { *(ptr i) i 1; } // 通过指针算术运算访问数组元素并打印动态分配的内存空间中的内容 for (int i 0; i n; i) { printf(%d , *(ptr i)); } printf(\n); // 使用free函数释放ptr指向的内存空间 free(ptr); ptr NULL; // 释放内存后ptr变成了悬空指针建议将ptr重新设置为NULL以避免悬空指针的问题 return 0;
}多级指针、指针数组、const指针、void指针
在C语言中出了基础的指针以下的几种指针方式也很常见 多级指针指向指针的指针用于实现更复杂的数据结构和操作如动态内存分配中的二维数组。 指针数组数组中的元素是指针类型常用于存储多个字符串或指向函数的指针。 const指针指向常量的指针或指针常量用于限制指针的指向或指针所指向的值不可修改。 void指针通用指针类型可以指向任意类型的数据但在使用前通常需要类型转换。
#include stdio.h
#include stdlib.h int main() { // 多级指针指向指针的指针 int value 10; int *ptr1 value; int **ptr2 ptr1; int ***ptr3 ptr2; int ****ptr4 ptr3;int *****ptr5 ptr4;int ******ptr6 ptr5;int *******ptr7 ptr6;printf(通过多级指针访问值%d\n, *******ptr7); // 存储字符串 char *strings[] {Hello, Gayboy, GGBond}; int i; for (i 0; i 3; i) { printf(指针数组中的字符串%s\n, strings[i]); } const int constValue 20; const int *constPtr constValue; // *constPtr 30; 不能修改指向常量的指针所指向的值 printf(指向常量的指针%d\n, *constPtr); // 指针常量int anotherValue 30; int *const constPtr2 anotherValue; // constPtr2 value; 这样就是错误的指针常量的值不可修改 *constPtr2 40; printf(指针常量的指向值%d\n, *constPtr2); // 最后设一个通用指针 int intValue 50; float floatValue 3.14f; void *voidPtr; voidPtr intValue; printf(通过void指针访问int值%d\n, *(int *)voidPtr); voidPtr floatValue; printf(通过void指针访问float值%f\n, *(float *)voidPtr); return 0;
}运行结果如下