什么是指针?
初级理解
简单来说,指针就是存储内存地址的变量。就像普通变量存储数据值一样,指针变量存储的是内存中某个位置的地址。
1 2
| int var = 10; int *ptr = &var;
|
在这段代码中:
• &var 表示获取变量var的内存地址
• int * 声明了一个指向整型的指针变量
• ptr 现在存储了var的内存地址
指针的基本操作
- 声明指针
指针的声明需要指定它所指向的数据类型:
1 2 3
| int *int_ptr; float *float_ptr; char *char_ptr;
|
- 取地址操作符(&)
&操作符用于获取变量的内存地址:
1 2
| int num = 5; int *p = #
|
- 解引用操作符(*)
*操作符用于访问指针所指向的值:
指针的用途
指针在C语言中有多种重要用途:
- 动态内存分配:通过
malloc、calloc等函数动态分配内存
- 数组操作:数组名本质上就是一个指针
- 函数参数传递:通过指针可以实现"按引用传递"
- 数据结构实现:链表、树等数据结构都需要使用指针
- 字符串处理:C语言中的字符串本质上是字符指针
指针与数组的关系
在C语言中,数组名实际上就是一个指向数组第一个元素的指针:
1 2 3 4
| int arr[5] = {1, 2, 3, 4, 5}; int *p = arr;
printf("%d", *(p+2));
|
多级指针
指针可以指向另一个指针,形成多级指针:
1 2 3 4 5
| int var = 10; int *ptr = &var; int **pptr = &ptr;
printf("%d", **pptr);
|
指针的常见错误
初学者在使用指针时常犯的错误包括:
- 野指针:未初始化的指针
- 空指针解引用:对NULL指针进行解引用
- 内存泄漏:分配的内存没有释放
- 指针越界:访问超出分配的内存范围
指针的高级应用
随着对指针理解的深入,你可以看到更高级的指针应用:
- 函数指针:指向函数的指针
- 结构体指针:指向结构体的指针
- 指针数组:存储指针的数组
- 回调函数:通过函数指针实现
指针是C语言的核心概念,虽然初学时可能有些困难,但它是值得投入时间掌握的技能。理解指针不仅能帮助你写出更好的C代码,还能加深你对计算机内存管理的理解。记住:指针就是内存地址,而内存地址就是访问数据的门户。
深入理解
指针变量是存储指针的变量,指针是内存地址这个实际是不严谨的,尽管很多的教材书籍,视频教材等都这么说,只是让初学者更加简单的理解,但是你后面学习计算机组成原理和操作系统后就会明白,指针并不等同于内存地址,而是有一个相应的映射
或者说:
高级语言高级在哪?就是它把底层的东西通过抽象,提供一个简单的接口,人们不用去管它实际是怎么工作的,指针就是如此,它本质是内存地址的抽象,C语言通过指针操作,对内存进行访问控制
指针之面向对象
面向对象是一种编程范式,不是语言功能,很多人说C++和C的区别是C++是面向对象而C是面向过程,这句话是错的,下面演示一下C的面向对象的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <stdlib.h> #include <stdio.h>
typedef struct Student Student; struct Student{ const char* name; int age; float score; const char* (*getName)(Student* student); int (*getAge)(Student* student); float (*getScore)(Student* student); };
static const char* getNameImpl(Student* student) { return student->name; }
static int getAgeImpl(Student* student) { return student->age; }
static float getScoreImpl(Student* student) { return student->score; }
Student* createStudent(const char* name, int age, float score) { Student* student = (Student*)malloc(sizeof(Student)); student->age = age; student->score = score; student->name = name; student->getAge = getAgeImpl; student->getName = getNameImpl; student->getScore = getScoreImpl; return student; }
void freeStudent(Student* student) { free(student); }
int main() { Student* student = createStudent("Alice", 20, 95.5f); printf("Name: %s\n", student->getName(student)); printf("Age: %d\n", student->getAge(student)); printf("Score: %.2f\n", student->getScore(student)); freeStudent(student); return 0; }
|
名字那里一般不直接拷贝字面量指针,这里只是简单起见这么写
函数实现用static是控制访问性只在本文件内有效,这里简单起见没有拆开到头文件
输出:
1 2 3
| Name: Alice Age: 20 Score: 95.50
|
显而易见,C中也是可以实现面向对象的