说明:本文为个人学习总结,内容偏重基础与常见难点,仅供参考。

一、重点与难点

 指针本质:理解指针即内存地址,是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 转换为二进制时会无限循环,计算机只能表示它能表示的部分,因此有时候浮点数会出现精度丢失的问题。

五、运算符优先级

C语言运算符优先级和结合性一览表(从高到低,1 是最高,15 是最低)

优先级

运算符

名称或含义

使用形式

结合方向

说明

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)

十三、结束语句

1.break语句

在C语言中,可以使用break语句进行结束循环操作.

使用break语句时注意以下几点:

在没有循环结构的情况下,break不能用在单独的if-else语句中。

在多层循环中,一个break语句只跳出当前循环。

2.continue语句

在C语言中,可以使用continue语句进行中断后继续操作

continue语句的作用是结束本次循环开始执行下一次循环。

break语句与continue语句的区别是:

break是跳出当前整个循环,continue是结束本次循环开始下一次循环。

十四、其他重要概念

 static:修饰局部变量可延长其生命周期至程序结束。

 sizeof():获取变量或类型所占字节数。

 枚举:enum Season {Spring, Summer, Autumn, Winter};

 可变参数函数:需包含 <stdarg.h>,使用 va_list 系列宏。

更多推荐