C语言结构
C程序的表达式中引用了未赋初值的变量,可以通过编译并运行,但运行结果不一定是期望的结果。
C语言类型
CHAR | 1 字节 | -128 到 127 或 0 到 255 |
---|---|---|
unsigned char | 1 字节 | 0 到 255 |
signed char | 1 字节 | -128 到 127 |
char * | 32位:4 字节 64位:8 字节 | 是指针 |
int | 2 或 4 字节 | -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647 |
size | ? | 不能出现负数 |
unsigned int | 2 或 4 字节 | 0 到 65,535 或 0 到 4,294,967,295 |
short | 2 字节 | -32,768 到 32,767 |
unsigned short | 2 字节 | 0 到 65,535 |
long | 4 字节 | -2,147,483,648 到 2,147,483,647 |
unsigned long | 4 字节 | 0 到 4,294,967,295 |
指针的指向和赋值
pb = x pb = &x *pb = *x *pb = &x
这是C/C++语言中的指针相关操作说明:
- pb = x:这个语句将变量pb指向变量x所在的内存地址,相当于将x的地址赋值给了pb;
- pb = &x:这个语句把变量x的地址赋值给了变量pb,即让pb指向x的地址;
- *pb = *x:这个语句将pb所指向的内存地址中存储的值赋值给x所在的内存地址中存储的值,即使得x的值等于pb的值;
- *pb = &x:这个语句不能通过编译,因为&x是一个指向x的地址,*pb代表的是pb所指向的内存单元中存储的内容,它们的类型不匹配。
C语言的增值
++i与i++的区别和常见的用例
++i—>先加减再赋值
i++—>先赋值再加减
用例:
int x, y, z;
x = y = 10; // x与y的初值皆设为10
z = ++x || ++y; // 先将x自加1,再判断是否为0。由于++x后x为11,不为0,所以z被赋值为1。此时y未自增操作。
printf("x=%d, y=%d, z=%d", x, y, z); // 输出结果:x=11, y=10, z=1
```
因此,运行该段代码的输出结果为 `x=11, y=10, z=1`。
### 限定符
volatile——>强制在运行时访问变量的值,告诉编译器该变量的值随时可能发生改变,从而避免编译器产生优化代码,保证程序执行的正确性。
const——>将变量声明为常量,意味着它在程序执行期间不可更改。
restrict——>编译器可以知道指针所引用的内存块是程序中唯一访问该内存块的指针,从而进行优化。
_Atomic——>原子类型,支持原子性操作,在多线程环境下保证数据同步,并发访问时原子类型变量不会出现竞争问题。
函数实参和形参关系
形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。
实参出现在主调函数中,进入被调函数后,实参变量也不能使用。
形参和实参的功能是作数据传送。发生函数调用时, 主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。
具体说明
1.形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元。因此,形参只有在函数内部有效。 函数调用结束返回主调函数后则不能再使用该形参变量。
2.实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。
3.实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。
4.函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
5.形参和实参两种情况说明如下:
(1)当形参和实参不是指针类型时,在该函数运行时,形参和实参是不同的变量,他们在内存中位于不同的位置,形参将实参的内容复制一份,在该函数运行结束的时候形参被释放,而实参内容不会改变。
(2)而如果函数的参数是指针类型变量,在调用该函数的过程中,传给函数的是实参的地址,在函数体内部使用的也是实参的地址,即使用的就是实参本身。所以在函数体内部可以改变实参的值。
#### 实例1:实参和形参按值进行传递
include
void swap(int a,int b)
{
int t;
t=a;a=b;b=t;
}
main()
{
int i=3,j=5,p=&i,q=&j;
swap(p,q);printf("%d %d\n",p,*q);
}
void swap(int *a,int *b) 中的a、b是形参
swap(p,q)中的p、q是实参。
#### 数组中的实参和形参
数组中的参数:实参是数组名;形参是指针,其接受到的是实参数组的首地址。
C语言中,数组名代表该数组的起始地址,它指向该数组的开始位置,但是它的值不能被修改。
在函数的定义中,可以用数组名作为参数,被声明为数组的形参实际上是一个指针。
当实参向形参传递数组时,按值调用传递数组的首地址,数组元素的本身不被复制。
因此,如果函数调用时实参是数组名,则形参指针接受到的是实参数组的首地址。
## 程序语言翻译
机器语言程序和计算机程序并不是同一种东西,机器语言程序是一种直接由二进制指令组成的程序,而计算机程序则是高级语言转化为机器语言之后的可执行文件。**两者不能同时生成**。
### 编译、解释、汇编
#### 编译
编译程序分析源程序的阶段依次是词法分析、语法分析、语义分析(词、语、义)
编译程序将源程序翻译成与之等价的目标程序(汇编码或机器代码),经链接后形成可执行程序。
##### 编译程序的过程
编译程序是一种将高级语言程序翻译成目标程序的系统软件,它对源程序的翻译过程分为词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成,以及符号表管理和出错处理。
###### 源程序
可以被看成是一个字符串。
###### 分析源程序(词、语、义)
词法分析——>是编译过程的第一阶段,其任务是对源程序从前到后(从左到右)逐个字符地扫描,从中识别出一个个的“单词”符号。
语法分析——>任务是在词法分析的基础上,根据语言的语法规则将单词符号序列分解成各类语法单位,如“表达式”、“语句”、“程序”等。
语义分析——>主要检查源程序是否包含语义错误,并收集类型信息供后面的代码生成阶段使用。
###### 中间代码生成
###### 代码优化
###### 目标代码生成
###### 符号表管理
###### 出错处理
语句的出错处理不是排错,无法排查错误。
#### 解释
解释程序是逐句翻译执行源程序的语句,***不产生源程序的目标代码***,所以可进行逐条语句排错。
#### 汇编
汇编程序是将***汇编语言源程序翻译成机器指令和其他信息组成的目标程序***。
**不是任何一种汇编语言的每一个语句都能对应于一条机器语言指令的。**
***伪指令***语句经汇编后***不产生机器语言指令***。
汇编语言中有三类语句,即指令语句、伪指令语句和宏指令语句。
## 程序模块优化
模块设计追求强内聚、弱耦合。
### 耦合/内聚
模块之间的耦合是指模块之间依赖程度的度量,模块内聚是指模块内部各成份之间相互关联程度的度量。与其他模块之间存在强耦合的模块通常内聚性弱,强内聚的模块通常与其他模块之间存在弱耦合。
模块扇出数高,通常意味着模块内部的复杂性高,优化规则要求控制扇出数不能太高。
将模块的作用范围限制在模块的控制范围之内,是为了限制将来可能修改的范围,以提高程序的可修改性和可测试性,从而提高可维护性。
模块之间接口复杂,意味着程序模块之间的耦合性高,出错机会高,所以必须注意降低模块之间接口的复杂性。