C语言指针与结构体 - 课堂笔记

一、值传递 vs 地址传递

1. 值传递(传值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

void f(int p)
{
p = 100; // 修改的是局部变量 p,不影响 main 中的 i
}

int main()
{
int i = 88;
printf("i=%d\n", i); // 输出: i=88
f(i);
printf("i=%d\n", i); // 输出: i=88(不变)
}

特点:函数内部修改不影响外部变量


2. 地址传递(传址)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

void f(int *p)
{
*p = 100; // 通过指针修改主函数中 i 的值
}

int main()
{
int i = 88;
printf("i=%d\n", i); // 输出: i=88
f(&i); // 传入 i 的地址
printf("i=%d\n", i); // 输出: i=100(被修改)
}

特点:通过指针直接修改外部变量


二、数组与指针

1. 数组的三种遍历方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>

int main()
{
int a[5] = {1, 2, 3, 4, 5};

// 方式一:利用下标遍历
for (int i = 0; i < 5; i++)
printf("%d\n", a[i]);

// 方式二:利用数组名遍历(数组名就是首元素地址)
for (int i = 0; i < 5; i++)
printf("%d\n", *(a + i));

// 方式三:利用指针变量遍历
int *p = a;
for (int i = 0; i < 5; i++)
printf("%d\n", *(p + i));
}

2. 关键知识点

表达式 含义
a 数组名,表示首元素地址
*a 首元素的值 a[0]
a + i 第 i 个元素的地址
*(a + i) 第 i 个元素的值 a[i]
p + i a + i 等价

三、结构体

1. 结构体的定义

1
2
3
4
5
6
struct Student
{
int sid; // 学号
char name[200]; // 姓名
int age; // 年龄
};

2. 结构体变量的定义与初始化

1
struct Student st = {1000, "zhangsan", 20};

3. 访问结构体成员的三种方式

1
2
3
4
5
6
7
8
9
10
11
struct Student st = {1000, "zhangsan", 20};
struct Student *pst = &st;

// 方式一:直接通过变量名访问
st.sid = 99;

// 方式二:通过指针和 * 访问(注意括号)
(*pst).sid = 99;

// 方式三:通过指针和 -> 访问(最常用)
pst->sid = 99;

4. 结构体指针作为函数参数

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
#include <stdio.h>
#include <string.h>

struct Student
{
int sid;
char name[200];
int age;
};

void f(struct Student *pst) // 推荐:地址传递,效率高
{
pst->sid = 1000;
strcpy(pst->name, "zhangsan");
pst->age = 20;
}

void g(struct Student st) // 不推荐:值传递,效率低
{
// 修改的是副本,不影响原变量
}

void g2(struct Student *pst) // 推荐:地址传递
{
printf("%6d, %8s, %4d\n", pst->sid, pst->name, pst->age);
}

int main()
{
struct Student st;
f(&st); // 通过函数修改结构体
g2(&st); // 通过函数输出结构体
}

四、关键对比

传值方式 能否修改外部变量 效率
值传递 f(int p) ❌ 不能 较低(复制整个对象)
地址传递 f(int *p) ✅ 能 高(只传地址)
访问方式 示例
变量名.成员 st.sid
(*指针).成员 (*pst).sid
指针->成员 pst->sid

五、易错点

  1. 字符串赋值:不能直接用 = 给字符数组赋值,必须使用 strcpy()

    1
    2
    3
    4
    5
    // 错误
    st.name = "lisa";

    // 正确
    strcpy(st.name, "lisa");
  2. 指针访问结构体(*pst).sid 的括号不可省略,因为 . 优先级高于 *

九、完整代码下载

源代码文件:Pointers-and-Structs-in-C.c