C 语言学习日记・数据类型与结构体篇
一、整型数据与溢出
1. 取值范围
-
32 位
int:范围-2^31 ~ 2^31-1(-2147483648 ~ 2147483647) -
64 位
long long:范围-2^63 ~ 2^63-1,最多正确计算 20 的阶乘
2. 溢出现象
整数溢出属于 C 语言未定义行为,数值会发生截断错乱。例如计算 100! 时,持续累乘后二进制低位全部变为 0,最终输出结果为 0。
- 解决方案:小范围用
long long;超大数必须用数组模拟高精度乘法。
二、const 常量修饰
const修饰的变量为只读变量,定义后不可修改:
const int number = 10;
// number = 20; // ❌ 编译报错,只读变量不可修改
常用来定义数组长度、固定参数,提高代码可读性和安全性。
三、结构体与 typedef
方式 1:匿名结构体(定义类型同时直接创建变量,无类型名)
没有结构体标签名,只能当场定义变量,后面不能再定义新变量
#include <stdio.h>
// 匿名结构体
struct {
int a;
char b;
} t, ti; // 直接定义 t、ti 两个结构体变量
int main(void)
{
t.a = 10;
t.b = 'c';
printf("%d %c\n", t.a, t.b);
return 0;
}
方式 2:带标签名结构体(先声明类型,后定义变量)
有标签名
struct person,可以在任意地方重复定义变量
#include <stdio.h>
// 1.声明结构体标签 struct person
struct person {
int num;
char name[10];
};
int main(void)
{
// 2.使用标签定义变量,必须写 struct
struct person p = {20, "cyx"};
struct person p2; // 可以继续定义新变量
printf("%d %s\n", p.num, p.name);
return 0;
}
方式 3:typedef 给结构体起别名(工程最常用)
使用
typedef,后续不用写struct,直接用别名
#include <stdio.h>
// typedef + 匿名结构体,别名 Data
typedef struct {
int lead;
int data[100];
} Data;
int main(void)
{
// 直接用别名Data定义变量,不用写struct
Data h = {19, {1,2,3}};
Data *hi = &h;
printf("%d\n", (*hi).data[2]); // 写法1:解引用 + . ,括号不能丢
printf("%d\n", hi->data[2]); // 写法2:箭头 -> ,推荐
return 0;
}
关键对比总结
| 写法 | 是否需要写struct | 能否后续新建变量 |
|---|---|---|
| 方式 1 匿名结构体 | 变量处不用写 | ❌ 不能 |
| 方式 2 struct 标签名 | 定义变量必须写 struct | ✅ 可以 |
| 方式 3 typedef 别名 | 直接写别名,不用 struct | ✅ 可以 |
四、结构体初始化
按照成员定义的顺序,用大括号批量赋值:
// 普通结构体初始化
struct person p = {20, "cyx"};
// 包含数组成员的结构体,嵌套大括号初始化数组
Data h = {19, {1, 2, 3}};
-
初始化顺序必须和结构体成员的声明顺序一一对应
-
只初始化部分成员时,剩余成员自动初始化为 0
五、结构体成员访问
1. 普通结构体变量:点运算符 .
Data h = {19, {1, 2, 3}};
h.lead = 20; // 修改普通成员
h.data[1] = 10; // 修改数组型成员:变量名.数组名[下标]
-
结构体变量直接用
.访问内部成员 -
若成员是数组,再通过
[下标]访问数组的具体元素
2. 结构体指针:两种访问写法
当用指针指向结构体时,有两种等价的访问方式:
Data h = {19, {1, 2, 3}};
Data *hi;
hi = &h; // 指针指向结构体变量地址
写法 1:解引用 + 点运算符(必须加括号)
printf("%d\n", (*hi).data[2]);
-
括号不能省略:
.的优先级高于*,不加括号会先执行hi.data引发错误 -
逻辑:先对指针解引用得到结构体本身,再用
.访问成员
写法 2:箭头运算符 ->(推荐,最常用)
printf("%d\n", hi->data[2]);
-
->是结构体指针专属的访问运算符,等价于(*指针).成员 -
写法更简洁,是指针访问结构体成员的标准写法
六、常用格式符汇总
| 格式符 | 作用 | 参数要求 |
|---|---|---|
%d | 输出 / 输入十进制整数 | 传 int 变量值(scanf 需加 &) |
%c | 输出 / 输入单个字符 | 传 char 变量值 |
%s | 输出 / 输入字符串 | 传字符串首地址(不能加 *) |
%p | 输出内存地址 | 传指针 / 地址 |
%lld | 输出 long long 类型整数 | 传 long long 变量 |
七、易错踩坑清单
-
相等判断写错:if 条件中相等是
==,写成=会变成赋值语句,引发逻辑错误。 -
结构体成员访问:结构体里的数组成员,访问时是
变量名.数组名[下标],不要写错顺序。 -
类型不匹配:字符串只能初始化
char数组,不能直接赋值给int数组。 -
括号遗漏错误:
(*p).成员的括号绝对不能省,写成*p.member会编译报错。 -
访问符混淆:普通结构体变量用
.,结构体指针用->,不可混用。 -
初始化顺序错误:初始化值的顺序必须和结构体成员定义顺序一致,不能乱序。
-
数组成员初始化遗漏大括号:结构体里的数组成员,初始化时要用
{}单独包裹,例如{19, {1,2,3}}。 -
匿名结构体复用问题:法一的匿名结构体类型,不能在后续代码中再用来定义新变量。

379

被折叠的 条评论
为什么被折叠?



