C语言学习笔记(个人总结版)
说明:本文为个人学习总结,内容偏重基础与常见难点,仅供参考。
一、重点与难点
指针本质:理解指针即内存地址,是C语言灵活性的核心。
内存布局:理解栈(局部变量)、堆(动态分配)、全局区(全局与静态变量)的区别。
结构体与位运算:掌握自定义数据类型与直接操作二进制位的能力。
二、推荐书籍
《C程序设计语言》
《C和指针》
三、C程序结构
一个C程序由头文件(.h) 和源文件(.c) 组成。(头文件要在调用函数之前)
程序有且只有一个 `main()` 函数,是程序执行的入口。
函数是实现逻辑的基本单元,包括:定义、声明、调用。
变量命名规则:
由字母、数字、下划线组成,首字符不能是数字。
不能使用C语言关键字(如 int、if 等)。
同一作用域内变量名不能重复。
四、变量与数据类型
基本类型(常见字节数,具体取决于系统):
char:1字节(字符)
int:通常4字节(整型)
long:通常4或8字节(长整型)
float:4字节(单精度浮点)
double:8字节(双精度浮点)
变量赋值方式:
1. 声明时赋值:int a = 10;
2. 先声明后赋值:int a; a = 10;
数据类型范围:
可表示数值范围与字节数相关,一般为:
范围 ≈ ±2^(字节数×8-1)
浮点数的二进制表示
一个浮点数可以表示为 (-1)^S * M * 2^E 的形式,其中:
-
S 是符号位,决定了数值的正负。
-
M 是尾数,代表数值的精度部分。
-
E 是指数,决定了数值的大小范围。
例如,十进制数 4.25 在二进制中表示为 100.01,可以用二进制科学计数法表示为 1.0001 * 2^2。在这个例子中,尾数是 1.0001,指数是 2,符号位为 0(代表正数)。
浮点数存储细节
在单精度浮点数(float)中,总共有 32 位,分为三个部分:(约7位有效数)
-
符号位:1 位,表示数值的正负。
-
指数位:8 位,存放指数部分。指数位使用移位存储(移码)来表示正负。存放无符号整数
-
尾数位:23 位,存放尾数部分。由于二进制科学记数法的尾数总是以 1 开头,因此存储时省略这个 1,实际上可以存储 24 位的尾数。
在双精度浮点数(double)中,总共有 64 位,分为三个部分:(约16位有效数)
-
符号位:1 位,表示数值的正负。
-
指数位:11 位,存放指数部分。指数位使用移位存储(移码)来表示正负。存放无符号整数
-
尾数位:52 位,存放尾数部分。
对尾数的特殊处理
1. 隐藏高位1。
2.低位补0,补齐23位或52位。
移位存储(移码)
移位存储是一种存储指数的方法,它通过给每个数加上一个偏置值(bias)来存储。这种方法使得指数有大小顺序,便于计算机进行浮点数的加减法。例如,8 位有符号整型的表示范围是 [-127, 127],在移位存储中,将每个数加上 127 作为偏置值存储。指数 + 偏移量 = 一个非负整数
在64位双精度类型中, 偏移量是1023。
浮点数精度丢失问题
由于计算机存储浮点数的位数是固定的,当转换十进制浮点数到二进制时,可能会出现无限循环的情况,导致精度丢失。例如,十进制的 0.6 转换为二进制时会无限循环,计算机只能表示它能表示的部分,因此有时候浮点数会出现精度丢失的问题。
五、运算符优先级
| 优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
|---|---|---|---|---|---|
| 1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | |
| () | 圆括号 | (表达式) | |||
| . | 成员选择(对象) | 对象.成员名 | |||
| -> | 成员选择(指针) | 对象指针->成员名 | |||
| 2 | - | 负号运算符 | -表达式 | 右到左 | 单目运算符 |
| (类型) | 强制类型转换 | (数据类型)表达式 | |||
| ++ | 自增运算符 | ++变量名 | 单目运算符 | ||
| -- | 自减运算符 | --变量名 | 单目运算符 | ||
| * | 取值运算符 | *指针变量 | 单目运算符 | ||
| & | 取地址运算符 | &变量名 | 单目运算符 | ||
| ! | 逻辑非运算符 | !表达式 | 单目运算符 | ||
| ~ | 按位取反运算符 | ~表达式 | 单目运算符 | ||
| sizeof | 长度运算符 | sizeof(表达式) | |||
| 3 | / | 除 | 表达式 / 表达式 | 左到右 | 双目运算符 |
| * | 乘 | 表达式*表达式 | 双目运算符 | ||
| % | 余数(取模) | 整型表达式%整型表达式 | 双目运算符 | ||
| 4 | + | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
| - | 减 | 表达式-表达式 | 双目运算符 | ||
| 5 | << | 左移 | 变量<<表达式 | 左到右 | 双目运算符 |
| >> | 右移 | 变量>>表达式 | 双目运算符 | ||
| 6 | > | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
| >= | 大于等于 | 表达式>=表达式 | 双目运算符 | ||
| < | 小于 | 表达式<表达式 | 双目运算符 | ||
| <= | 小于等于 | 表达式<=表达式 | 双目运算符 | ||
| 7 | == | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
| != | 不等于 | 表达式!= 表达式 | 双目运算符 | ||
| 8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
| 9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
| 10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
| 11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
| 12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
| 13 | ?: | 表达式1? 表达式2: 表达式3 | 右到左 | ||
| 14 | = | 赋值运算符 | 变量=表达式 | 右到左 | |
| /= | 除后赋值 | 变量/=表达式 | |||
| *= | 乘后赋值 | 变量*=表达式 | |||
| %= | 取模后赋值 | 变量%=表达式 | |||
| += | 加后赋值 | 变量+=表达式 | |||
| -= | 减后赋值 | 变量-=表达式 | |||
| <<= | 左移后赋值 | 变量<<=表达式 | |||
| >>= | 右移后赋值 | 变量>>=表达式 | |||
| &= | 按位与后赋值 | 变量&=表达式 | |||
| ^= | 按位异或后赋值 | 变量^=表达式 | |||
| |= | 按位或后赋值 | 变量|=表达式 | |||
| 15 | , | 逗号运算符 | 表达式,表达式,… | 左到右 |
同一优先级的运算符,运算次序由结合方向所决定。
口诀:括号最强,算术 > 比较 > 逻辑 > 赋值。
六、输入输出
scanf("%d", &a); —— & 为取地址符
printf 格式:
%d:有符号整数
%u:无符号整数
%f:浮点
%lf:双精度浮点
%c:字符,(在 %c前加空格会跳过空白字符(包括换行符和空格),确保每次读取的都是字母)
%s:字符串
%p:指针地址
七、随机数生成
#include <stdlib.h> (先导入库文件)
#include <time.h>
srand(time(NULL)); // 初始化随机种子
int num = rand(); // 生成随机数 (这相当一个数)
八、原码、反码、补码
原码:符号位 + 绝对值二进制
反码:正数同原码;负数符号位不变,其余取反
补码:正数同原码;负数为反码 + 1 ;补码的反码 + 1是原码
计算机中整数以补码形式存储。
九、数组与指针
数组长度:sizeof(arr) / sizeof(arr[0])
指针运算:
指针 ± 整数:移动若干元素
指针不能对整数做乘除法,可以做加减法(进行步进移动)
指针 − 指针:得到元素个数间隔
指针与指针之间不能做加、乘、除法,可以做减法(得到间隔步长)
十、指针进阶
数组指针:指向数组的指针 数据类型(*指针名)[一维数组长度]
int (*p)[5];
指针数组:元素是指针的数组 数据类型* 指针名[几个一维数组]
int *arr[5];
函数指针:指向函数的指针 返回值类型(*指针名)(形参类型)=函数名
int (*func)(int, int);
函数指针数组:存储多个函数指针
返回值类型(*指针名[几个函数])(形参类型)={函数名,函数名}
调用函数指针数组:(指针名[第几个数组-1])(实参)
只有形参完全相同而且返回值也要一样的函数,才能放到同一个函数指针数组当中
int (*funcArr[3])(int);
在C语言中,.和->都是用来访问结构体成员的运算符,但使用场景不同:
点运算符 .
用于:结构体变量本身(不是指针)
语法: 结构体变量.成员名
箭头运算符 ->
用于:指向结构体的指针
语法: 结构体指针->成员名
等价于: (*结构体指针).成员名
口诀:普通变量用点 . 指针变量用箭头 ->
十一、动态内存管理
动态内存分配 #include<stdlib.h>
malloc memory allocation(内存分配) 申请空间(连续)
calloc contiguous allocation (连续分配) 申请空间+数据初始化
realloc re-allcation(重新分配) 修改空间大小
free free (释放,自由) 释放空间
例如:
#include <stdlib.h>
void *malloc(size_t size); // 分配未初始化内存
void *calloc(size_t num, size_t size); // 分配并初始化为0
void *realloc(void *ptr, size_t size); // 调整已分配内存大小
void free(void *ptr); // 释放内存
使用后务必 `free()`,防止内存泄漏
十二、位运算
`&`:与(同1为1)
`|`:或(有1为1)
`^`:异或(相同为0,不同为1)
`~`:取反
`<<`:左移(相当于乘2)
`>>`:右移(相当于除2)
十三、结束语句
在C语言中,可以使用break语句进行结束循环操作.
使用break语句时注意以下几点:
在没有循环结构的情况下,break不能用在单独的if-else语句中。
在多层循环中,一个break语句只跳出当前循环。
在C语言中,可以使用continue语句进行中断后继续操作
continue语句的作用是结束本次循环开始执行下一次循环。
break语句与continue语句的区别是:
break是跳出当前整个循环,continue是结束本次循环开始下一次循环。
十四、其他重要概念
static:修饰局部变量可延长其生命周期至程序结束。
sizeof():获取变量或类型所占字节数。
枚举:enum Season {Spring, Summer, Autumn, Winter};
可变参数函数:需包含 <stdarg.h>,使用 va_list 系列宏。
更多推荐
所有评论(0)