目录
作为一名程序员,指针是必须掌握的概念之一。在C语言中,指针是一个非常重要的概念,它可以使程序更加灵活和高效。在本篇博客中,我将详细介绍指针在C语言中的概念和使用方法。
1.指针的概念
在C语言中,指针是一种变量类型,它可以存储一个变量的内存地址。指针变量本身也是一个变量,它存储的是一个地址值,而不是实际的数据值。指针变量可以通过解引用操作来访问存储在其地址中的数据。
2.指针的声明
指针的声明需要指定指针类型和指针变量名。指针类型指定了指针所指向的变量类型。例如,int *ptr声明了一个指向int类型变量的指针变量ptr。指针变量名可以任意指定,注意指针声明后要初始化,未初始化的指针,指针指向的地址是任意的,这是非常非常危险的行为,如果刚好指向了,之前使用的地址,你又解引用修改了这个指针的值,可能导致程序不符合预期甚至崩溃,对于一开始不知道初始化为什么值的指针,可以初始化为NULL,例如,int *ptr=NULL。
3.指针的初始化
指针变量需要被初始化,才能使用。指针变量的初始化可以通过以下方式进行:
(1)将指针变量初始化为NULL,表示指针没有指向任何有效的内存地址。例如,int *ptr = NULL。
(2)将指针变量初始化为一个已知的地址。例如,int a = 10; int *ptr = &a;将指针变量ptr初始化为变量a的地址。
4.指针的使用
指针的使用包括指针变量的赋值和解引用操作。
(1)指针变量的赋值
可以通过以下方式为指针变量赋值:
int a = 10;
int *ptr = &a;
以上代码将指针变量ptr初始化为变量a的地址。
(2)指针的解引用操作
指针的解引用操作可以获取指针变量所指向的变量的值。例如,*ptr就是指针变量ptr所指向的变量的值。
int a = 10;
int *ptr = &a;
printf("%d\n", *ptr); // 输出10
5.指针的运算
指针可以进行一些运算,如加法和减法。指针的加法和减法操作的结果是一个新的指针,指向加减后的内存地址。
例如,因为ptr为int型的指针,ptr+1表示指针ptr向后移动一个int类型长度(4个字节)的内存地址,即指向下一个int类型变量的地址。同理如果为char 声明的指针,ptr+1表示指针ptr向后移动一个char类型长度(1个字节)的内存地址,即指向下一个char类型变量的地址。
6.指针数组
指针数组是一个包含指针变量的数组。每个指针变量都指向一个变量的地址。指针数组可以用来处理多个变量。
例如,以下代码定义了一个包含3个指针变量的指针数组,每个指针变量都指向一个int类型的变量。
int a =10;
int b = 20;
int c = 30;
int *ptr_arr[3] = {&a, &b, &c};
可以通过以下方式访问指针数组中的元素:
printf("%d\n", *ptr_arr[0]); // 输出a的值,即10
printf("%d\n", *ptr_arr[1]); // 输出b的值,即20
printf("%d\n", *ptr_arr[2]); // 输出c的值,即30
7.指向指针的指针
指向指针的指针是指一个指针变量存储的是另一个指针变量的地址。例如,int **pptr表示pptr指向一个指针变量,这个指针变量指向一个int类型变量的地址
int a = 10;
int *ptr = &a;
int **pptr = &ptr;
printf("%d\n", **pptr); // 输出a的值,即10
8.指针与数组的关系
在C语言中,数组名本质上是一个指向数组第一个元素的指针。因此,可以用指针来访问数组元素。例如,a[i]等价于*(a+i)。
int a[5] = {1, 2, 3, 4, 5};
int *ptr = a; // 将数组名a赋值给指针变量ptr
for(int i=0; i<5; i++){
printf("%d ", *(ptr+i)); // 输出数组元素
}
以上代码将输出数组a中的所有元素。
9.指针和函数的关系
指针在函数中的使用非常广泛。指针可以作为函数的参数传递,也可以作为函数的返回值。
例如,以下代码定义了一个函数swap,用来交换两个int类型变量的值。函数使用了指针作为参数,以实现交换操作
void swap(int *ptr1, int *ptr2){
int temp = *ptr1;
*ptr1 = *ptr2;
*ptr2 = temp;
}
可以通过以下方式调用swap函数:
int a = 10;
int b = 20;
swap(&a, &b);
以上代码将交换变量a和变量b的值。
10.指针的注意事项
在使用指针时需要注意以下几点:
(1)指针变量需要初始化后才能使用。
(2)指针变量需要指向有效的内存地址,否则会导致程序崩溃。
(3)指针变量解引用时需要注意指针指向的数据类型和大小。
(4)指针运算时需要注意指针指向的数据类型和大小,防止越界访问。
(5)指针的生命周期需要注意,防止使用已被销毁的指针。
================================================
进阶内容
11.常量指针和指针常量
常量指针和指针常量是两种不同类型的指针,它们都具有一定的限制。
常量指针(const pointer)是指针指向的内存区域的值不可改变,但指针本身可以改变。这意味着,可以使用常量指针来避免意外修改指向的数据。例如:
int x = 5;
const int *p = &x; // p是指向常量的指针,指向x的地址
*p = 7; // 错误:不能通过常量指针修改所指向的内存
int y = 6;
p = &y; // 正确:可以改变指针p的指向,使其指向y
指针常量(pointer const)是指针本身的值不可改变,但指针所指向的内存区域的值可以改变。这意味着,可以使用指针常量来防止指针被意外地修改。例如:
int x = 5;
int *const p = &x; // p是指针常量,指向x的地址
*p = 7; // 正确:可以通过指针常量修改所指向的内存
int y = 6;
p = &y; // 错误:不能改变指针p的指向
对于这个不理解的可以,看我前一篇还是两篇博客,其中详细介绍了const对于变量和指针的修饰效果和如何记忆区分。
12.void指针
void指针是一种特殊类型的指针,它可以指向任何类型的数据,但不能直接访问指向的数据。需要在使用时,将其强制类型转换为正确的指针类型。例如:
int i = 10;
float f = 3.14;
void *p; // 定义一个void指针
p = &i; // 将p指向i的地址
printf("%d\n", *(int*)p); // 使用强制类型转换将void指针转换为int指针,并输出所指向内存的值
p = &f; // 将p指向f的地址
printf("%f\n", *(float*)p); // 使用强制类型转换将void指针转换为float指针,并输出所指向内存的值
需要注意的是,void指针只能用于指向数据的地址,而不能进行指针运算。
13.空指针
空指针(null pointer)是指一个不指向任何内存地址的指针,也就是说,它指向了一个不存在的内存地址。在C语言中,空指针可以用一个特殊的值NULL来表示。例如:
int *p = NULL; // p是一个空指针
if (p == NULL) {
printf("p指向的内存地址不存在。\n");
}
使用空指针可以避免指针变量未初始化时指向任意内存地址的问题。需要注意的是,使用空指针访问所指向的内存是非法的,并且可能导致程序崩溃。因此,在使用指针时,需要确保指针不是空指针。
14.指针数组
指针数组是一个数组,其中每个元素都是指针类型。例如:
int a = 1, b = 2, c = 3;
int *p[] = {&a, &b, &c}; // 定义一个指针数组,每个元素都是int类型的指针
for (int i = 0; i < 3; i++) {
printf("%d\n", *p[i]); // 输出每个指针指向的值
}
指针数组可以用于存储一组指针,每个指针可以指向不同的内存地址。
15.数组指针
数组指针是指向数组的指针,它可以用于访问数组中的元素。例如:
int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};
int (*p)[2] = a; // 定义一个指向数组a的指针
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
printf("%d ", *(*(p+i)+j)); // 输出数组中每个元素的值
}
printf("\n");
}
数组指针也可以用于作为形参传递数组,以及在函数中定义动态数组等。
总结
指针是C语言中非常重要的概念,对于理解和操作内存具有关键作用。需要注意的是,在使用指针时,需要注意指针的正确使用和防止指针悬挂等问题。同时,可以使用常量指针、指针常量、void指针、空指针、指针数组和数组指针等来扩展指针的功能。最后能不能看在博主这么幸苦的份上点个关注,点个关注,不迷路。