10-指针进阶——char型,多级指针,void指针,const指针
文章目录
- 10-指针进阶——char型,多级指针,void指针,const指针
- 一、char 型指针
- 1.1 示例
- 二、多级指针
- 2.1 示例
- 三、 指针的万能拆解方法
- 3.1 示例
- 四、void 型指针
- 4.1 示例
- 4.2 void 关键字的作用
- 4.2.1 示例
- 五、const 指针
- 5.1 常指针
- 5.2 常目标指针
一、char 型指针
概念:字符指针(char*
)是一种特殊类型的指针,用来指向一个字符或字符数组,通常用于字符串处理。
1.1 示例
#include <stdio.h>
int main() {
char *msg = "Hello Even";
printf("%s\n", msg); // 输出字符串 "Hello Even"
return 0;
}
在上述代码中,msg
是一个字符指针,指向字符串常量 "Hello Even"
的首字符 'H'
。
二、多级指针
概念:多级指针是指针的指针。一个指针指向另一个指针时,就是多级指针。
- 一级指针:指向一个
普通变量
的地址。 - 二级指针:指向一个
指针变量
的地址。 - 三级指针:指向一个
二级指针变量
的地址。
2.1 示例
#include <stdio.h>
int main() {
int a = 100;
int *p1 = &a; // 一级指针
int **p2 = &p1; // 二级指针
int ***p3 = &p2; // 三级指针
printf("a = %d\n", a); // 输出 100
printf("*p1 = %d\n", *p1); // 输出 100
printf("**p2 = %d\n", **p2); // 输出 100
printf("***p3 = %d\n", ***p3);// 输出 100
return 0;
}
在这段代码中,p1
是一个一级指针,指向变量 a
;p2
是一个二级指针,指向 p1
;p3
是一个三级指针,指向 p2
。
三、 指针的万能拆解方法
每个指针都可以分为两部分:
- 第一部分:说明它是一个指针(*p)。
- 第二部分:说明它所指向的内容的类型(*p 以外的东西)。
3.1 示例
#include <stdio.h>
int main() {
char *p1; // 第一部分: *p1,第二部分: char, 说明 p1 指向 char 类型
char **p2; // 第一部分: *p2,第二部分: char *, 说明 p2 指向 char* 类型
int **p3; // 第一部分: *p3,第二部分: int *, 说明 p3 指向 int* 类型
char (*p4)[3]; // 第一部分: *p4,第二部分: char[3], 说明 p4 指向一个拥有3个元素的 char 数组
char (*p5)(int, float); // 第一部分: *p5, 第二部分: char(int, float), 说明 p5 指向一个返回 char 并需要 int 和 float 参数的函数
void *(*p6)(void *); // 第一部分: *p6, 第二部分: void *(void *), 说明 p6 指向一个返回 void* 并需要 void* 参数的函数
return 0;
}
在这个例子中:
p1
是一个指向char
类型的指针。p2
是一个指向char*
类型的指针,即指向char
指针的指针。p3
是一个指向int*
类型的指针,即指向int
指针的指针。p4
是一个指向拥有 3 个char
元素的数组的指针。p5
是一个指向一个返回char
类型并需要int
和float
参数的函数的指针。p6
是一个指向一个返回void*
并需要void*
参数的函数的指针。
总结:
- char 型指针:用于指向字符或字符串数组,常用于字符串处理。
- 多级指针:指针的指针,可以是一级、二级、三级等多级指针,用于更复杂的内存操作。
- 指针的万能拆解方法:可以将任何指针分解为两部分,一部分表示它是一个指针,另一部分表示它所指向的内容的类型。
指针的大小是固定的(在64位系统中为8字节),但它们所指向的数据类型各不相同
。
四、void 型指针
概念:void
型指针表示该指针的类型暂时不确定
,即它可以指向任何类型的数据。
要点:
- 无法直接索引目标:
void
型指针必须先进行强制类型转换,然后才能索引目标。 - 无法直接进行加减运算:
void
型指针不允许直接进行加减运算,因为编译器不知道如何移动指针。
4.1 示例
#include <stdio.h>
#include <stdlib.h>
int main() {
void *p = malloc(4); // 使用 malloc 申请 4 个字节的内存,并让 p 指向该内存的入口地址
*(int *)p = 250; // 强制类型转换为 int 型指针,然后解引用
printf("*p as int: %d\n", *(int *)p); // 输出 250
*(float *)p = 3.14; // 强制类型转换为 float 型指针,然后解引用
printf("*p as float: %f\n", *(float *)p); // 输出 3.140000
free(p); // 释放内存
return 0;
}
在上面的代码中,p
是一个 void
型指针,通过强制类型转换为 int
型指针或 float
型指针来访问数据。
注意:
以上写法 void * p , 在实际开发中不应该出现。以上代码只是为了说明语法问题。
4.2 void 关键字的作用
- 修饰指针:表示该指针指向了一个未知类型的数据。
- 修饰函数的参数列表:表示该函数不需要参数。
- 修饰函数的返回值:表示该函数没有返回值。
4.2.1 示例
void functionWithNoReturnValue(void) {
// 函数没有返回值,也不需要参数
}
int main() {
functionWithNoReturnValue();
return 0;
}
五、const 指针
概念:const
修饰指针有两种效果:
- 常指针:修饰的是
指针本身
,表示该指针变量无法修改。 - 常目标指针:修饰的是指针所指向的
目标
,表示无法通过该指针来改变目标的数据。
5.1 常指针
#include <stdio.h>
int main() {
char arr[] = "Hello";
char msg[] = "Even";
char * const p = arr;
// p = msg; // 编译错误:p 被 const 修饰,表示 p 是一个常量,无法修改它的内容(所指向的地址)
*(p + 1) = 'E'; // p 所指向的内容是可以通过 p 来修改的
printf("%s\n", p); // 输出 "HEllo"
return 0;
}
5.2 常目标指针
#include <stdio.h>
int main() {
char arr[] = "Hello";
char msg[] = "Even";
const char *p1 = arr;//常目标指针
p1 = msg; // p1 的指向是可以被修改的
// *(p1 + 1) = 'V'; // 编译错误:常目标指针不允许通过该指针来修改它所指向的内容
*(msg + 1) = 'V'; // 直接修改内容是可以的
printf("%s\n", p1); // 输出 "Even"
return 0;
}
总结:
- void 型指针:通用指针,可以指向任意类型的数据,但需要强制类型转换后才能操作。
- const 修饰指针:
- 常指针:指针本身不能修改(指向的地址不能变),但所指向的内容可以修改。
- 常目标指针:所指向的内容不能通过该指针修改,但指针本身可以指向其他地址。
在实际开发中,const
修饰符经常用于限制指针的权限,特别是常目标指针,用来确保数据的只读性,防止误修改。