C--Grammar
1.C--basic data type
1.1 常量
1.2 输出格式
1.2.1 普通的格式化输出
%d //整型输出
%ld //长整型输出
%o //以八进制数形式输出整数
%x //以十六进制数形式输出整数,或输出字符串的地址
%u //以十进制数输出unsigned型数据(无符号数)
注意:%d与%u的区别是,有无符号(正负号)和数值范围(%u范围大)不同,也就是极限的值不同,不然数值打印出来会出错。
%c //用来输出一个字符
%s //用来输出一个字符串
%f //用来输出实数,以小数形式输出,默认情况下保留小数点6位
%.5f //用来输出实数,保留小数点5位
%e //以指数形式输出实数eg:a=3e+10<=>3*10^10;
注意:e的前面和后面的值必须是整数
%g //根据大小自动选f格式或e格式,且不输出无意义的零
1.2.2 整数的格式化输出
一个C程序是默认右对齐的。
%+d(加号可省略)表示右对齐。
形如%-d,负号表示左对齐
int main() {
int a =987, b =987654;
printf("%5d\n", a); // 右对齐,且最少取5位整数,如果变量a多余5位则全取,不足5位使用空格左边补全;
printf("%05d\n", a); // 在上一个的基础上加一个0,使用0代替空格,在左边补齐位数;
printf("%-5d\n", a); // 左对齐,不足位数,使用空格补全;
printf("%-05d\n", a); // 左对齐,不足位数,还是用空格补全;
//注意:这里不再补0,这是因为本来是左对齐,如果补0的话,这个值的尾部会补一些0,这个值就会发生改变,建议读者和第四行的代码对比一下;
printf("%5d\n", b); // 变量b的值超过5位则全部取;
return 0;
}
运行结果如下:
987
00987
987
987
987654
1.2.3 小数的格式化输出
#include <stdio.h>
int main() {
double a = 123.456, b = 21.12;
printf("%.2f\n", a); // 取变量a的值的后2位小数,且第三位四舍五入;
printf("%.3f\n", b); // 取变量b的值的后3位小数,且不足三位则用0补全;
printf("%4.2f\n", b); // 取至少4位字符,2位从b的左边开始取2位,剩余2位<整数2位+小数点1位,所以三位全部输出;
printf("%7.2f\n", b); // 取至少7位字符, 2位小数,剩余5位>整数2位 + 小数点1位, 多出来的2位用空格补全;
//注意:小数点也占一位字符;
return 0;
}
运行结果如下:
123.46
21.120
21.12
21.12
1.2.4 字符数组的格式化取值
#include <stdio.h>
#include <time.h>
int main() {
char str[50];
char s[5] = { 'a', 'b', 'c' };
printf("%s==\n", s); // 打印完整的字符数组(字符串)
printf("%2s==\n", s); // 打印至少2个字符
printf("%5s==\n", s); // 打印至少5个字符,不足的用空格在左边补齐
printf("%-5s==\n", s); // 打印至少5个字符,不足的用空格在右边补齐
printf("%4.2s==\n", s); // 总共输出4个字符,但是有2个需要在s1里面从左取,剩余的字符
用空格默认在左边补全
printf("%.2s==\n", s); // 总共输出2个字符,这2个字符从s1里面的左边开始取
return 0;
}
运行结果如下:
abc==
abc==
abc==
abc ==
ab==
ab==
2.scanf运行原理
1.系统会将用户输入的内容放到缓冲区
2.scanf从输入缓冲区逐个取出内容赋值,若输入缓冲区不为空,scanf会一直从缓冲区获取,而不要求输入。
2.1 刷新缓冲区
2.1.1 利用fflush方法清空缓冲区(不是所有平台都能使用)
格式: fflush(stdin);
C和C++的标准里从来没有定义过 fflush(stdin)。
MSDN 文档里清除的描述着"fflush on input stream is an extension to the C standard'
(fflush 是在标准上扩充的函数,不是标准函数,所以不是所有平台都支持)
2.1.2 利用setbuf方法清空缓冲区(所有平台有效)
格式: setbuf(stdin,NULL);
3.sizeof运算符
4.类型转换
5.switch
1.语义
计算”表达式”的值,逐个与其后的"常量表达式"值相比较,当”表达式”的值与某个"常量表达式”的值相等时,即执行其后的语句,然后跳出switch语句
如果"表达式”的值与所有case后的"常量表达式"均不相同时,则执行default后的语句。
2.注意点
6.函数注意点
1.函数的不可以重复,但函数的生命可以重复
2.函数的声明可以写在函数外面,也可以写在函数里面
3.当调用函数出现在主调用函数之前时,在主调函数中也可以不对被调函数再做声明
4.如果被调函数的返回值是整型试,可以不对被调函数做说明,而直接调用。
7.main函数分析
1.参数
int argc:
系统在启动程序时调用main函数时传递给argv的个数
const char * argv[]
: 系统在启动程序时传入的值,默认情况下系统只会传入一个值,这个值就是main函数执行文件的路径
8.进制转换
9.位运算符
程序中的所有数据在计算机内存中都是以二进制的形式储存的
位运算就是直接对整数在内存中的二进制位进行操作
10.数组
11.字符串
内存中以\0结束,所占字节比实际多一个
12.指针
13.结构体
结构体变量占用的内存空间永远是所有成员中占用内存最大成员的倍数(对齐问题)
注意是按照结构体中变量依次分配空间的。
14.共用体
15.全局变量和局部变量
15.1 auto关键字
只能修饰局部变量,若局部变量没修饰符,默认就是auto
auto int num; 等价于 int num;
15.2 register关键字
只能修饰局部变量,将内存中变量提升到CPU寄存器中存储,使访问速度更快。
但CPU寄存器有限,通常不同平台和编译器在优化阶段会自动转换为auto
register int num;
16.static关键字
16.1 对局部变量作用
1.延长局部变量生命周期,从程序启动到程序结束
2.定义变量的代码在整个程序运行期间仅会执行一次
16.2 对全局变量作用
16.2.1 内部变量
只能在本文件中访问的变量
16.2.2 外部变量
1.可以在其它文件中访问的变量,默认所有全局变量都是外部变量
2.默认情况下,多个同名的全局变量共享一块空间,会导致全局变量污染,但可以通过static关键字避免这个问题。
static关键字修饰的外部变量只能在当前文件访问。
17 extern关键字
17.1 对局部变量
1.不能用于局部变量
2.extern代表声明一个变量,而不是定义一个变量,变量只有定义才会开辟存储空间
。
17.2 对全局变量
18.const关键字
让变量的值不可修改。但可以通过指针修改。
修饰符const可以用在类型说明符前,也可以用在类型说明符后
int const x=2; 或 const int x=2;
19.内存管理
进程被加载导内存中的布局如下图:
19.1 栈内存(Stack)
栈中存放任意类型额变量,但必须是auto类型修饰的,随用随开,用完即销。内存的分配和销毁由系统自动完成
,无需人工干预,但栈最大尺寸固定,会存在栈溢出现象。
19.2 堆内存(Heap)
堆内存中可以存放任意类型数据,但需要自己申请和释放
空间巨大,实际会受内存大小和内存是否连续。
堆申请内存函数:
常见的初始化方法是 void * malloc(size_t Size);
所在文件 stdlib.h
函数功能 申请堆内存空间并返回,所申请的空间并未初始化
memset 字节初始化.
参数 size_t size 表示要申请的字符数
返回值 void * 成功返回非空指针指向申请的空间,失败返回 NULL