暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

数据库内核开发新手入门系列(四)初识C语言的指针

原创 Salvatore-zz 2025-03-11
147

前言:

    上一期我们分享了C语言中的程序结构,本篇我们来介绍C语言中指针的基础知识。

Part 1:理解内存与地址:

1. 什么是内存?

  • 内存就像一栋巨大的写字楼,每个房间(内存单元)都有一个门牌号(地址),房间内可以存放数据(如数字、字符等)。

  • 每个房间的大小固定(例如1字节),不同类型的数据需要不同数量的房间(如int占4字节,char占1字节)。

2. 变量如何存储?

  • 当声明变量 int a = 10;,相当于:

    • 在写字楼中预订一个连续的房间(4个字节)。

    • 给这些房间贴上标签“a”。

    • 将值10存入这些房间。

  • 变量的地址就是这些房间的“起始门牌号”。

Part 2:指针的本质

1. 指针是什么?

  • 指针是一个变量,但它存储的不是普通数据,而是另一个变量的地址

  • 比喻:指针就像一张“小纸条”,上面写着某个房间的门牌号(地址),而不是房间里的物品(数据)。

2. 指针的声明与初始化

int a = 10;     // 普通变量
int *p = &a;    // 指针变量p,存储a的地址
复制

我们看上面的例子,int *pp是一个指向int类型的指针。其中&a是取地址运算符,是用来获取变量a的地址。

3. 指针的“解引用”(*操作符)

printf("%d", *p);  // 输出10(通过p找到a的值)
*p = 20;           // 通过p修改a的值为20
复制

上面的例子中,*p的含义和作用是根据指针p中存储的地址找到其在内存对应的位置并进行操作。

Part 3:指针的常见用法

    示例1:指针与变量:

为了更好的理解指针和内存地址对应的关系,我们可以用画图或者表格的形式来展示,方便我们理解。

int a = 10; // 假设a的地址是0x1000

int *p = &a; // p的值是0x1000

还用上述的示例,那再内存中,图示大概是这个样子:

    示例2:修改指针指向的值

int a = 10, b = 20;
int *p = &a;    // p指向a
p = &b;         // 现在p指向b
*p = 30;        // 修改b的值为30
复制

这个例子中,我们可以详细的看下内存的变化过程,我逐步拆解分析下,

初始状态

  • a 的值为 10,地址假设为 0x1000

  • b 的值为 20,地址假设为 0x2000

  • 指针 p 初始化为 &a(即 0x1000)。

内存地址图如下:

执行 p = &b

  • p 的值变为 0x2000(即 b 的地址)。此时内存地址变化如下

执行 *p = 30

  • 通过 p 修改 b 的值为 30

最终结果

  • a 的值保持为 10(未被修改)。

  • b 的值变为 30(通过指针修改)。

Part 4:指针的常见用途(分场景详解)

场景1:函数参数传递(修改实参)

void swap(int *x, int *y) {
    int temp = *x;
    *x = *y;
    *y = temp;
}

int main() {
    int a = 1, b = 2;
    swap(&a, &b);  // 传递地址
    printf("a=%d, b=%d", a, b);  // 输出a=2, b=1
    return 0;
}
复制
  • Tips:如果不传指针,函数内部无法修改外部的变量。

场景2:动态内存分配

int *arr = (int*)malloc(5 * sizeof(int));  // 申请5个int的空间
if (arr != NULL) {
    for (int i = 0; i < 5; i++) {
        arr[i] = i * 10;  // 通过指针操作数组
    }
    free(arr);  // 必须手动释放内存!
}
复制
  • Tips:传统数组大小固定,动态分配允许程序运行时决定内存大小。

Part  5:指针的常见陷阱以及问题

1. 空指针(NULL Pointer)

int *p = NULL;  // 明确初始化为空
if (p != NULL) {
    *p = 10;    // 安全操作
}
复制

2. 野指针(Dangling Pointer)

int *p;
{
    int a = 10;
    p = &a;     // p指向局部变量a
}               // a的作用域结束,内存被释放
*p = 20;        // 危险!操作已释放的内存
复制

3. 指针类型不匹配

double d = 3.14;
int *p = &d;    // 错误!类型不匹配
复制

4. 指针可以进行运算操作

    a. 指针的加减

int arr[3] = {10, 20, 30};
int *p = arr;

p++;        // p指向arr[1]
p--;        // p回到arr[0]
p += 2;     // p指向arr[2]
复制

Tipsp + n 的实际地址是 p + n * sizeof(数据类型)

    b. 指针比较

int *p1 = &arr[0];
int *p2 = &arr[2];
if (p1 < p2) {  // 比较地址大小
    printf("p1在p2之前");
}
复制

    示例3:指针的综合应用示例

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 基础指针操作
    int num = 42;
    int *p = &num;
    printf("num的值: %d, 地址: %p\n", num, &num);
    printf("p存储的地址: %p, 通过p访问的值: %d\n", p, *p);

    // 动态内存分配
    int *dynamicArr = (int*)malloc(3 * sizeof(int));
    if (dynamicArr != NULL) {
        dynamicArr[0] = 10;
        *(dynamicArr + 1) = 20;  // 等价于dynamicArr[1] = 20
        dynamicArr[2] = 30;
        for (int i = 0; i < 3; i++) {
            printf("dynamicArr[%d] = %d\n", i, dynamicArr[i]);
        }
        free(dynamicArr);
    }

    // 指针与函数
    void addTen(int *x) {
        *x += 10;
    }
    int value = 5;
    addTen(&value);
    printf("addTen后的值: %d\n", value);  // 输出15

    return 0;
}
复制

    这个例子感兴趣的朋友可以自己玩一下试试,最后的输出结果如下:

num的值: 42, 地址: 0x7ffd1234abcd
p存储的地址: 0x7ffd1234abcd, 通过p访问的值: 42
dynamicArr[0] = 10
dynamicArr[1] = 20
dynamicArr[2] = 30
addTen后的值: 15
复制

最后:

        虽然是慢工但是不是什么细活 我们下期见。




最后修改时间:2025-03-18 10:20:31
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论