【数据结构与算法】第2篇:C语言核心机制回顾(一):指针、数组与结构体

一、写在前面

上一篇我们把环境搭好了,这一篇开始,花两三篇的时间把C语言里和数据结构最相关的知识点过一遍。

如果你已经对指针、结构体很熟了,这篇可以快速浏览,当个复习。但如果这些概念还模糊,建议耐心看完,因为后面的链表、树全都要靠它们。


二、指针:C语言的灵魂

2.1 什么是指针

指针就是一个变量,它存的是地址,不是具体的数值。

c

复制代码
int a = 10;
int *p = &a;  // p存的是a的地址

画个图理解一下:

text

复制代码
变量a:  [10]    地址假设是 0x1000
指针p:  [0x1000] 地址假设是 0x2000

p里面存的是0x1000,通过*p就能找到a,拿到10。

2.2 指针的运算

指针的加减运算,不是简单的地址加1,而是加上它所指向类型的大小

c

复制代码
int arr[] = {10, 20, 30, 40};
int *p = arr;  // p指向arr[0]

printf("%p\n", p);    // 假设输出 0x1000
printf("%p\n", p+1);  // 输出 0x1004,因为int占4字节

关键点:

  • p+1 跳过了4个字节,指向了arr[1]

  • p++ 也是同样的效果,指针向后移动一个元素

这个特性特别重要,后面遍历数组、操作链表节点全靠它。

2.3 指针和数组的关系

数组名在很多情况下可以当作指针用,但它们不完全一样。

c

复制代码
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;

printf("%d\n", arr[2]);   // 输出3
printf("%d\n", p[2]);     // 也是3,p可以像数组一样用
printf("%d\n", *(arr+2)); // 也是3,arr可以像指针一样用

关键区别

  • arr是常量,不能改变指向,比如arr++会报错

  • p是变量,可以随意改,比如p++是合法的

访问数组元素的本质:arr[i] 其实等价于 *(arr + i)


三、结构体:自定义数据类型

3.1 基本用法

结构体可以把多个不同类型的数据打包在一起。

c

复制代码
struct Student {
    char name[20];
    int age;
    float score;
};

// 使用
struct Student s1 = {"张三", 20, 85.5};
printf("%s的分数是%.1f\n", s1.name, s1.score);

3.2 结构体指针

操作结构体时,经常用指针,因为传指针比传整个结构体效率高。

c

复制代码
struct Student s1 = {"李四", 21, 90.0};
struct Student *p = &s1;

// 两种访问方式
printf("%s\n", (*p).name);   // 写法麻烦,不常用
printf("%s\n", p->name);     // 箭头操作符,推荐

记住p->name 等价于 (*p).name

3.3 内存对齐(重点)

这是一个容易踩坑的点。结构体的大小不是成员大小的简单相加。

c

复制代码
struct Example1 {
    char c;   // 1字节
    int i;    // 4字节
};

printf("%d\n", sizeof(struct Example1));  // 输出8,不是5

为什么是8?因为编译器会做内存对齐

  • char c占1字节,但为了int i对齐到4字节边界,c后面会空出3个字节(填充)

  • 最终占1+3+4 = 8字节

c

复制代码
struct Example2 {
    int i;    // 4字节
    char c;   // 1字节
};

printf("%d\n", sizeof(struct Example2));  // 输出8,还是8?

这个也是8,但原因不同:int占4,char占1,整体大小需要是最大成员(4)的倍数,所以补3个字节,还是8。

c

复制代码
struct Example3 {
    char c1;  // 1
    char c2;  // 1
    int i;    // 4
};

printf("%d\n", sizeof(struct Example3));  // 输出8(1+1+2填充+4)

对齐规则

  1. 每个成员相对于结构体起始地址的偏移量,必须是该成员大小的整数倍

  2. 结构体的总大小,必须是最大成员大小的整数倍

写数据结构时要注意:如果结构体内有指针,指针在64位系统占8字节,对齐会影响整个结构体的大小。


四、typedef:给类型起别名

typedef能让代码更简洁,尤其是后面写链表,不用每次都写struct Node

c

复制代码
// 不用typedef
struct Node {
    int data;
    struct Node *next;
};
struct Node n1;  // 每次都要写struct

// 用typedef
typedef struct Node {
    int data;
    struct Node *next;
} Node;

Node n1;  // 简洁多了

还有一种写法更常见:

c

复制代码
typedef struct Node {
    int data;
    struct Node *next;
} Node, *PNode;  // PNode是指向Node的指针类型

Node n1;
PNode p = &n1;   // p是Node*类型

五、一个综合例子

把前面学的串起来,定义一个学生结构体,用指针操作:

c

复制代码
#include <stdio.h>
#include <string.h>

typedef struct Student {
    char name[20];
    int age;
    float score;
} Student;

void printStudent(Student *p) {
    printf("姓名:%s,年龄:%d,分数:%.1f\n", 
           p->name, p->age, p->score);
}

int main() {
    Student s1;
    strcpy(s1.name, "王小明");
    s1.age = 19;
    s1.score = 88.5;
    
    Student *p = &s1;
    printStudent(p);
    
    // 演示指针运算(数组)
    Student class[3] = {
        {"张三", 20, 85},
        {"李四", 21, 90},
        {"王五", 19, 87}
    };
    
    Student *q = class;
    printf("第一个学生:%s\n", q->name);
    printf("第二个学生:%s\n", (q+1)->name);  // 指针移动
    
    return 0;
}

输出:

text

复制代码
姓名:王小明,年龄:19,分数:88.5
第一个学生:张三
第二个学生:李四

六、小结

这一篇讲了三个核心概念:

概念 要点
指针 存地址,加减运算跳过的字节数取决于指向的类型
数组 数组名可当指针用,但是常量不能改指向
结构体 自定义类型,大小要考虑内存对齐
typedef 简化类型名,让代码更简洁

这些是写数据结构的基石,下一篇我们会讲动态内存分配(malloc和free),学会之后就可以开始手写链表了。


七、思考题

  1. 下面的结构体占多少字节?(假设是32位系统,指针4字节)

c

复制代码
typedef struct {
    char a;
    int *p;
    char b;
} Test;
  1. 为什么结构体要有内存对齐?不直接按顺序存?
相关推荐
zyhomepage2 小时前
科技的成就(七十二)
开发语言·人工智能·科技·算法·内容运营
dapeng28702 小时前
C++代码重构实战
开发语言·c++·算法
xu_wenming2 小时前
为什么要在项目中加入 ESP‑NN(神经网络)
mcu·物联网·算法·iot
程序员小郭832 小时前
Spring Ai 05 ChatClient Advisor 实战(日志、提示词增强、内容安全)
java·开发语言·前端
juleskk2 小时前
3.22 复试训练
算法
还不秃顶的计科生2 小时前
力扣第84题:完全平方数
算法·leetcode·职场和发展
tryCbest2 小时前
Python之FastAPI 开发框架(第三篇):高级特性与实战
开发语言·python·fastapi
BestOrNothing_20152 小时前
Ubuntu 22.04 下使用 VS Code 搭建 ROS 2 Humble 集成开发环境
c++·vscode·python·ros2·ubuntu22.04
2301_776508722 小时前
分布式系统监控工具
开发语言·c++·算法