C语言学习——指针部分知识点归纳

C语言指针知识要点整理

一、指针基础概念

1. 什么是指针?

•指针是存储内存地址的变量​
•指针本身也有自己的内存地址
•通过指针可以间接访问和操作内存中的数据

2. 指针的声明和初始化

// 声明指针
int *p;        // 指向整型的指针
float *fp;     // 指向浮点数的指针
char *cp;      // 指向字符的指针
// 指针的初始化
int x = 10;
int *p = &x;   // p指向x的地址
// NULL指针
int *p = NULL; // 空指针,指向地址0

二、指针运算符

1. 取地址运算符 &

•获取变量的内存地址

int a = 5;
int *p = &a;  // p存储a的地址

2. 解引用运算符 *

•访问指针所指向地址的值

int a = 5;
int *p = &a;
int b = *p;   // b = 5
*p = 20;      // 通过指针修改a的值,现在a = 20

三、指针的运算

1. 算术运算

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;     // p指向arr[0]
p++;              // p现在指向arr[1],地址增加sizeof(int)字节
p--;              // p指向arr[0]
p = p + 3;        // p指向arr[3]
int *q = p - 2;   // q指向arr[1]
  1. 关系运算
int *p, *q;
if(p == q)  // 比较两个指针是否指向同一地址
if(p < q)   // 比较指针地址的大小
if(p != NULL) // 检查指针是否非空

四、指针与数组

1. 数组名就是指针

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;  // 等价于 int *p = &arr[0];
// 通过指针访问数组元素
*(arr + 2) = 10;     // arr[2] = 10
*(p + 3) = 20;       // arr[3] = 20

2. 指针遍历数组

int arr[5] = {1, 2, 3, 4, 5};
int *p;
// 方法1
for(p = arr; p < arr + 5; p++) {
    printf("%d ", *p);}
// 方法2
p = arr;
for(int i = 0; i < 5; i++) {
    printf("%d ", *(p + i));
}

五、多级指针

1. 二级指针

int a = 10;
int *p = &a;    // 一级指针
int **pp = &p;  // 二级指针,指向指针的指针
// 访问
printf("%d\n", a);    // 10
printf("%d\n", *p);   // 10
printf("%d\n", **pp); // 10

六、指针与函数

1. 指针作为函数参数(传地址)

// 交换两个变量的值
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
int main() {
    int x = 5, y = 10;
    swap(&x, &y);  
// 传递地址
    return 0;
}

2. 指针作为函数返回值

// 返回数组最大值的地址
int* findMax(int arr[], int n) {
    int *max = &arr[0];
    for(int i = 1; i < n; i++) {
        if(arr[i] > *max) {
            max = &arr[i];
        }
    }
    return max;  // 返回指针
}

七、指针与字符串

1. 字符指针

// 字符串字面量
char *str = "Hello";  // str指向字符串常量
// str[0] = 'h';  // 错误!不能修改字符串常量
// 字符数组
char arr[] = "World";  // 可以修改
arr[0] = 'w';         // 正确

2. 常用字符串函数

char str1[20] = "Hello";
char str2[] = "World";
char *p;
p = strcpy(str1, str2);  // 字符串复制
p = strcat(str1, str2);  // 字符串连接
int len = strlen(str1);  // 字符串长度
p = strchr(str1, 'l');   // 查找字符

八、特殊指针

1. 空指针 NULL

•表示指针不指向任何有效地址
•使用前应检查是否为NULL

int *p = NULL;
if(p != NULL) {
    *p = 10;  // 安全访问
}

2. 野指针

•指向无效内存地址的指针
•未初始化的指针
•已释放内存的指针

int *p;           // 野指针,未初始化
*p = 10;          // 危险!可能崩溃
int *p = (int*)malloc(sizeof(int));
free(p);          // 释放内存
*p = 20;          // 野指针,危险!
p = NULL;         // 好习惯:释放后置为NULL

3. void 指针

•通用类型指针,可指向任意数据类型
•不能直接解引用,需先转换为具体类型

int a = 10;
float b = 3.14;
void *vp;
vp = &a;  // 指向int
*(int*)vp = 20;  // 需要类型转换
vp = &b;  // 指向float
printf("%f\n", *(float*)vp);

九、指针与动态内存分配

  1. 动态内存管理函数
#include <stdlib.h>
// 分配内存
int *p = (int*)malloc(10 * sizeof(int));  // 分配10个int空间
if(p == NULL) {
// 处理内存分配失败
}
// 重新分配内存
p = (int*)realloc(p, 20 * sizeof(int));  // 调整为20个int
// 释放内存
free(p);
p = NULL;  // 好习惯

十、指针与结构体

1. 结构体指针

typedef struct {
    int id;
    char name[20];
    float score;
} Student;
Student s = {1, "Tom", 90.5};
Student *p = &s;
// 访问成员
(*p).id = 2;    // 方式1
p->id = 3;       // 方式2(更常用)
strcpy(p->name, "Jerry");

2. 指针在结构体中的使用

typedef struct Node {
    int data;
    struct Node *next;  // 指向自身类型的指针
} Node;
// 创建链表节点
Node *createNode(int value) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = NULL;
    return newNode;
}

十一、函数指针

1. 函数指针声明和使用

// 函数原型
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int main() {
    // 声明函数指针
    int (*funcPtr)(int, int);
    // 指向add函数
    funcPtr = add;
    printf("%d\n", funcPtr(5, 3));  // 8
    // 指向sub函数
    funcPtr = sub;
    printf("%d\n", funcPtr(5, 3));  // 2
    return 0;
}

2. 函数指针作为参数

int calculate(int a, int b, int (*operation)(int, int)) {
    return operation(a, b);
}

int result = calculate(10, 5, add);  // 15

十二、易错点和注意事项

1. 常见错误

// 错误1:使用未初始化的指针
int *p;
*p = 10;  // 段错误
// 错误2:返回局部变量的地址
int* badFunction() {
    int x = 10;
    return &x;  // x是局部变量,函数结束就销毁
}
// 错误3:指针类型不匹配
float f = 3.14;
int *p = &f;  // 错误类型
printf("%d\n", *p);  // 输出错误

2. 最佳实践

1.初始化指针​:声明时立即初始化
2.​检查NULL​:使用前检查指针是否为空
3.​匹配类型​:确保指针类型与指向的数据类型匹配
4.及时释放​:动态分配的内存要及时释放
5.​避免野指针​:释放内存后置为NULL
6.注意作用域​:不要返回局部变量的地址

十三、练习理解

指针与数组等价性

int arr[5] = {1, 2, 3, 4, 5};
// 以下表达式是等价的:
arr[2]    ≡ *(arr + 2)    ≡ *(2 + arr)    ≡ 2[arr]
// 是的,2[arr] 是合法的C语法!

指针的指针

int a = 10;
int *p = &a;
int **pp = &p;
int ***ppp = &pp;
// 访问a的值
printf("%d\n", a);      // 10
printf("%d\n", *p);     // 10
printf("%d\n", **pp);   // 10
printf("%d\n", ***ppp); // 10
posted @ 2025-12-23 22:56  朱雯  阅读(0)  评论(0)    收藏  举报