目录
//基础知识
1.内存基本概念
内存是由多个字节组成的一堆,线性、连续存储空间;
字节是计算机内存、外存分配存储空间的基本单位;
对于内存的众多字节,计算机系统是通过编号进行管理的;
编号与字节是一一对应关系;
2.数据总线
在CPU和内存之间的多电线,用来在CPU和内存之间传输数据,
数据传输方向是双向的:CPU->内存(写数据)、内存->CPU(
读数据),数据总线根数与CPU字长是一致的。
3.地址总线
在CPU和内存之间的多电线,用来确定数据传输的内存的位置,
数据传输只有从CPU到内存这个方向,是单向;地址总线的根数
实质上就是计算机系统用来对字节进行编号管理的二进制的位数!
内存字节编号(地址)最终体现在地址总线上,即,在内存中,并
不存在特别的存储空间用来表达地址值。内存中的每个字节的地址
并不存在于内存中。
//内存管理初步知识
1. 软件必须先调入内存方可执行;
2. OS是计算机资源管理者,内存的使用也是在OS的管理下进行的;
3. 软件在执行前,须先向OS申请存储空间;在有足够内存空间时,
OS将分配一段空间供软件使用;
4. 软件在运行过程中,其所分配得到的存储空间不再分配给其它软件;
5. 软件只能在其所分配得到的存储空间中进行操作,不能对其他空间
操作,如果出现操作不属于该软件的空间,OS会认为出现了“非法
内存访问”错误,软件会被强制停止。
6. 软件在运行完毕后,将提醒OS回收其所占用的存储空间(但不会清空
该空间内容);OS会回收该空间以便再次分配给其他软件;
//c语言数据类型
代号 大小 识别方式
char 1字节 ASCII 字符型
short 2字节 补码 短整型
int 4字节 补码 整型
long 4字节 补码 长整型
float 4字节 浮点 单精度
double 8字节 浮点 双精度
* 4字节 字节编号 地址(指针)
_Bool 1字节 ture(1)/flase(0)
unsigned 无符号数 unsigned int b;
signed 有符号数 int a; <=> signed int a;
十进制表达方式: 3 65
八进制表达方式: 03 0101
十六进制表达方式:0x3 0x144
格式符
"%o":无符号八进制;"%x":无符号十六进制(小写);"%X":无符号十六进制(大写)
格式符:%d/i int 有符号十进制数(i是老写法)
格式符:%o unsigned int 无符号8进制数
格式符:%u unsigned int 无符号10进制数
格式符:%x/X unsigned int 无符号16进制数
格式符:%f float (float)
格式符:%lf double (long float)
格式符:%e/E double
格式符:%le double 按照科学计数法输出
格式符:%g/G double 有效位数(%.8g表示单精度浮点数保留8位有效数字)
格式符:%c char
格式符:%s/S char*/wxhar_t* 字符串以'\0'结尾
格式符:%p void* 以16进制形式输出指针
格式符:%n int* 到此字符之前为止,一共输出的字符个数,不输出文本
格式符:%m 无 打印errno值对应的出错内容
科学计数法:23.4e5 => 23.4*10^5;23E-3 => 23*10^(-3)
e(E)两侧缺一不可,幂指数不能为小数!
标志flag
字符 字符名称 说明
- 减号 左对齐,右边填充空格(默认右对齐)。
+ 加号 在数字前增加符号 + 或 -。
0 数字零 将输出的前面补上0,直到占满指定列宽为止。
(不可以搭配使用"-")。
空格 输出值为正时加上空格,为负时加上负号。
# # 号 type是o、x、X时,增加前缀0、0x、0X;type是e、E、f、g、G时,
一定使用小数点;type是g、G时,尾部的0保留。
示例:
printf("%5d\n",1000); //默认右对齐,左边补空格
printf("%-5d\n",1000); //左对齐,右边补空格
printf("%+d %+d\n",1000,-1000); //输出正负号
printf("% d % d\n",1000,-1000); //正号用空格替代,负号输出
printf("%x %#x\n",1000,1000); //输出0x
printf("%.0f %#.0f\n",1000.0,1000.0)//当小数点后不输出值时依然输出小数点
printf("%g %#g\n",1000.0,1000.0); //保留小数点后后的0
printf("%05d\n",1000); //前面补0
printf("%.3f\n",3.1242344534); //保留小数点后3位输出->3.124
//语言处理程序
(基本名).(扩展名)
1.编辑c程序代码;这一步生成*.c的文件;
2.编译,将产生一个Debug目录,及一个最终的可执行文件*.exe;
3.执行该文件。
//ASCII
'0' = 48; 'A' = 65; 'a' = 97
C语言中,除了输出操作会涉及到点阵信息图像外,
其他所有对字符的操作,都仅仅是对其编号进行的。
//五大部件及其数据关系
1.输入(I)、输出(O)、内存(M)、控制器(C)、算逻部件(ALU)
2.a.I/O设备通常都是低速设备(相较于CPU)。如果CPU直接控制
I/O设备,会造成CPU资源浪费,使得计算机只能“串行”运行。
b.为解决此问题,提出“申请/响应”机制,使得多个计算机设备,
在宏观角度处于“并行”状态。
c.为解决高速设备与低速设备速度上的匹配,引入“缓冲区”机制,
使得慢速设备所接受的数据,在高速设备来不及处理时,先保存
在这些“缓冲区”中,等待高速设备的后续处理;
d.在并行状态下,必然会出现多个申请同时发出的现象;为保证
计算机整体的安全性,需要对这些申请进行“优先级”排列。
//计算机指令体系
1.一条计算机指令是由指令编号(指令码)和多个数据(地址码)组成;
2.软件对应的源程序代码,都要经过“编译/解释”被翻译成符合上述某种
指令的集合;
3.软件必须先调入内存方可执行;这个软件的指令和数据在运行之前,就
已经被存储到内存中了。
4.一条指令执行过程:
a.控制器从内存取出一条指令;
b.根据指令体系,控制器能够识别该指令的指令码部分,并且能
进一步知道该指令所需要的地址码的个数、该指令功能;
c.根据指令功能,通过相关电路发出一定序列的微操作指令,完成
指令功能;
d.由于事先定义了指令体系,控制器能根据当前指令编号,得出当前
指令长度,从而进一步知道下一条指令所在位置,并自动将下一条
指令获取,形成“自动执行”。
//#include <math.h>
abs(x) |x| int x;
fabs(x) |x| double x;
sqrt(x) 求x的算术平方根;
pow(x,y) x的y次方;
exp(x) e的x次方;
log(x) ln(x);
log10(x) lg(x);
sin(x) sin(x);
cos(x) cos(x);
//运算符
1.() +、- *、/、% +、-
正 负 加 减 ->优先级降低 单目运算优先级都高于
所有双目及三目运算符;
2.> < >= <= != == (关系运算符)
关系运算符优先级低于算术运算符;
3.! && || (逻辑运算符)
"!"优先级最高的单目运算符; "&&"与"||"优先级低于关系运算符; "&&"优先级高于"||"
4.赋值运算符
不能对常量和表达式赋值!;
"="优先级仅高于",";
"="运算过程是从右向左进行的;
//有关变量名命名规范(非强制)
变量名是单单词,首字母大写; int Value;
变量名是多单词,首单词首字母小写,后面单词首字母大写;unsigned char ucPort;
最好在变量名前跟随该变量类型缩写前缀;
5."++"与"--"
++i 置前自增:先对i增1,然后用增1后的值,参加所有后续运算;
i++ 滞后自增:先用i原值参加所有的后续运算,然后再对i增1;
条表中的滞后自增(自减),先用变量原值进行判断,在判断完毕后,立刻自增(自减);
滞后自增(减)(在不是函数参数括号中时),遇到",",立刻自增(减)!
6.三目运算符
条表?表达式1:表达式2;
三目运算符优先级仅高于赋值运算符;
7.逗号表达式
","优先级最低,用来分隔多个表达式的,逗号运算的结合性是从左至右
由","组成的逗号表达式的运算结果是,最后一个表达式的值;
//c语言对于“函数参数”的处理过程是:从右向左!;
#include "stdio.h"
void fn(int a,int b,int c)
{
printf("%d,%d,%d", a, b, c);
}
void main()
{
int a = 3;
fn(a++, a++, a++);
}
输出结果为5,4,3
//两个重要补充
1.数据类型转换
1)自动类型转换
若参加某一次运算的数据类型不一致,C语言会进行自动的数据类型转换;
规则:短类型向长类型转换;
转换过程极力避免数据丢失现象;
char -> short -> int -> float -> double
2)强制类型转换(单目运算符)
数据类型转换的运算符:(数据类型名称)表达式
(double)1/i; <=> ((double)1)/i; <=> 1/(double)i
3)自动强制类型转换
“自动强制类型转换”只发生在“赋值表达式”中:当赋值运算两侧数据类型
不一致,C语言会‘自动’将赋值运算符右侧的“表达式”的值,按照左侧的变
量的数据类型进行‘强制’转换工作。
2.短路运算-仅发生在"&&"与"||"运算中
0 && A -> 0; 若在"&&"左侧出现 0 或在"||"左侧
1 || A -> 1; 出现 1,则"&&"与"||"右侧表达式被无视。
//一维数组
1.定义:type arrayName[非浮点常量(表达式)];
定义数组的语句,与数组元素引用的语句采用不同的语法规则和原则,
绝对不可以混用!
2.引用:数组下标越界c编译软件无法察觉!
3.赋初值:不完全赋初值,其余值为0;
不明确声明数组元素,但又不赋初值,这是语法错误!
4.存放数据特点:从下标为0的第一个元素空间存放;
连续存放数据;
上述两个原则必须动态成立!
//二维数组
1.赋初值:
a. int a[3][4];=>int[4] a[3]; 假设type为int[4],则左式可看作:
type a[3];说明a是一个一维数组,每个元素类型是type,即int[4]。
b. int a[][4]={...};=>int[4] a[]={...};由于int[4]明确说明,
应将初值中的数据,每4个划为一组,可以无二义性的操作。
c. int a[3][]={...};=>int[] a[3]={...};由于int[]没有说明长度,
即数据类型不确定,不能构成正确有效的数据类型。
//字符数组与字符串
1.关于“以0结束”的问题:
char s[4]={'A','B','C','0'};是字符数组,不是字符串
char s[5]={'A','B','C','0',0};是字符数组,是字符串
char s[5]={'A','B','C','0'};是字符数组,是字符串
char s[5]="ABC0";<=>char s[4]={'A','B','C','0'};<=>char s[5]={'A','B','C','0',0}
char s[]="ABCDEFG";printf("%d,\n",sizeof(s));=8
c语言对于字符串处理遵循遇0则止!构造字符串时,必须在字符串的最后写上0结束标志。
2.数组与指针区别
数组名是常量,指针名是变量。二者都可以进行指针加法操作和使用数组表示法。
但只有指针表示法可以递增操作。
//指针
1.两个要素
a. 首地址:相关变量在内存中所占用的多个字节连续存储空间中的第一个字节编号!
b. 指类:指针所指向的内存空间的数据类型。
2.'&'与'*'
a. '&':单目运算符;比++、--优先级低。
b. 不能对常量和表达式进行操作!
c. 参与运算的指针的指类必须保持一致!
d. 若a的值是b的首地址,则:
称为“a指向b”;a的指类就是b的数据类型。
e. '*':单目运算符,优先级同'&'。
f. *某,在'='左侧,念做:“某”所指向的空间;
*某,在'='右侧,或在"表达式"中,念做:“某”所指向的空间的值;
e. 变量定义语句中的‘*’,不是指向运算符!,仅仅是变量为指针类型的说明符!
eg:int i = 3,*p = &i;
3.指针其它运算
1).指针与整型量加减
type *p;p+1,指向移动距离是指针的指类空间长度。
2).指针与指针相减
p - p' => int
指针-指针,结果绝对值是:两个指针所指向的空间之间的指类元素个数。
3).c语言拒绝进行两个指针的相加
4.数组名称是常量,可以参加所有指针相关运算!
int a[10];*(a+i) <=> a[i]
5.指针与字符串
1).字符串常量本质:是该字符串的首地址常量。
//关键字
1.const
限定符-用于限定一个变量为只读
2.#define
预处理器处理的替换机制
通常使用大写:eg:#define SIZE 5;(名称前带c_或k_前缀表示常量)
3.continue
执行到该语句会跳过本次迭代的剩余部分,并开始下一轮迭代。
如果continue语句在嵌套循环内,则只会影响包含该语句的内层循环。
4.break
执行到循环中的break语句,会终止包含它的循环,并执行下一阶段。
如果break语句在嵌套循环内,则只会影响包含该语句的内层循环。
break还可用于因其他原因退出循环的情况。
5.#
#是c语言“预编译”的标识符,预编译意思是:在对源程序代码进行编译
前所做的工作!预编译工作与最终可执行文件的执行完全不同!
6.static
static创建的对象具有静态存储期,载入程序创建对象,当程序结束时对象消失。
若static用于文件作用域申明,作用域受限于该文件。若static用于块作用域的
申明,作用域受限于该块。
static可以表明变量是内部链接还是外部链接,
eg: static int dodgers = 3
变量dodgers属于文件私有,该文件中的任意函数都可使用它。
7._Thread_local
_Thread_local申明一个对象时,每个线程都获得该变量的私有备份。
8.auto
auto说明符表明变量是自动存储期,只能用于块作用域的变量申明中,由于
在块中申明的变量本身就具有自动存储期,所以使用auto主要是明确表达要
使用与外部变量同名的局部变量的意图。
表明有意覆盖一个外部变量定义,或强调不要把该变量改为其他存储类别。
auto是存储类别说明符,在C++与C用法不同。
9.extern
extern表明申明的变量定义在别处,如果包含extern的申明具有文件作用域,则引用
的变量必须具有外部链接。若包含extern的申明具有块作用域,则引用的变量可能
具有外部链接或内部链接。
eg: extern int tern
extern告诉编译器该函数中任何使用tern的地方都引用同一个定义在函数外部的变量。
10.register
register只作用于块作用域的变量,它把变量归为寄存器存储类别,请求最快速度访问,
该变量,同时还保护该变量的地址不被获取。
//函数
1.函数申明
1)确定函数名称、参数、返回值。
2)函数名称的本质是该函数的入口地址常量(指针常量)。
3)库函数申明
#include<XXXX.h>:将XXXX.h的内容(c程序)复制一份,代替
#include<XXXX.h>,XXXX.h内容与我们所编写的源代码内容合
并编译生成最终的可执行文件。
2.函数定义;
函数申明或定义没有明确表示函数类型,c编译软件默认int类型。
return意思是:返回,即回到主调函数。
结束被调用函数的执行。
在return语句后面的语句不会被执行,
3.函数引用(调用);
4.函数体
函数体是用{}括起来的,{}具有高度独立性。
关于局部变量:在{}里定义的所有变量,以及该函数的所有形参变
量,都称之为局部变量。局部变量只有在该函数被调用时才申请空间,且
局部变量将随着定义它的函数的运行结束而释放空间!
局部变量只能被定义它的函数所引用,不能被其他任何函数所引用,
无论这些函数是否存在调用和被调用的关系!!
//作用域
块:一对{}括起来的代码区域,定义在块中的变量具有块作用域。
块作用域变量的可见范围是从定义出到包含该定义的块的末尾。
函数的形参申明在函数的左花括号之前,但它们也具有作用域,
属于函数体这个块。
申明在内层块的变量,其作用域仅局限于该申明所在的块。
C99允许在块中的任意位置申明变量。
函数作用域:仅用于goto语句的标签,即使一个标签首次出现在函数
的内层块中,它的作用域也延伸到整个函数。
函数原型作用域:用于函数形参,范围是从形参定义到原型申明结束,
编译器在处理函数原型中的形参时只关心它的类型,
形参名通常无关紧要,只有在变长数组,形参名才有用。
文件作用域:变量的定义在函数的外面,范围从它的定义到该定义所在的
文件末尾。(文件作用域变量也叫全局变量)
//链接
C变量存在三种链接方式:外部链接、内部链接和无连接
1.具有块作用域、函数作用域或函数原型作用域的变量都
是无连接变量。这些变量都属于定义它们的块、函数或
函数原型私有。
2.具有文件作用域的变量可以是外部链接或内部链接。外部
链接可以在多个文件程序中使用,内部链接只能在一个翻
译单元中使用。
(翻译单元:一个源代码文件和它所包含的头文件。)
//存储期
1.静态存储期
若对象具有静态存储期,那它在程序执行期间一直存在,文件作用域变量具有静态
存储期,对于文件作用域变量,关键字static表明其链接属性,而非存储期。以static、
申明的文件作用域变量具有内部链接。所有的文件作用域变量都具有静态存储期。
2.线程存储期
用于并发程序设计,程序执行可被分为多个线程。具有线程存储期的对象,从被申明到
线程结束一直存在,以关键字_Thread_local申明一个对象时,每个线程都获得该变量的
私有备份。
3.自动存储期
块作用域通常具有自动存储期。当程序进入定义这些变量的块时,为这些变量分配内存;
当退出这个块时,释放刚才为变量分配的内存。
4.变长数组稍有不同,它们的存储期从申明处到块的结尾,而不是从块的开始到块的结尾。