关键字 | 说明 |
auto | 声明自动变量 |
short | 声明短整型变量或函数 |
int | 声明整型变量或函数 |
long | 声明长整型变量或函数 |
float | 声明浮点型变量或函数 |
double | 声明双精度变量或函数 |
char | 声明字符型变量或函数 |
struct | 声明结构体变量或函数 |
union | 声明共用数据类型 |
enum | 声明枚举类型 |
typedef | 用以给数据类型取别名 |
const | 声明只读变量 |
unsigned | 声明无符号类型变量或函数 |
signed | 声明有符号类型变量或函数 |
extern | 声明变量是在其他文件正声明 |
register | 声明寄存器变量 |
static | 声明静态变量 |
volatile | 说明变量在程序执行中可被隐含地改变 |
void | 声明函数无返回值或无参数,声明无类型指针 |
if | 条件语句 |
else | 条件语句否定分支(与 if 连用) |
switch | 用于开关语句 |
case | 开关语句分支 |
for | 一种循环语句 |
do | 循环语句的循环体 |
while | 循环语句的循环条件 |
goto | 无条件跳转语句 |
continue | 结束当前循环,开始下一轮循环 |
break | 跳出当前循环 |
default | 开关语句中的“其他”分支 |
sizeof | 计算数据类型长度 |
return | 子程序返回语句(可以带参数,也可不带参数)循环条件 |
数据类型关键字(12个)
char :声明字符型变量或函数
short :声明短整型变量或函数
int : 声明整型变量或函数
long :声明长整型变量或函数
signed :声明有符号类型变量或函数
unsigned :声明无符号类型变量或函数
float :声明浮点型变量或函数
double :声明双精度变量或函数
struct :声明结构体变量或函数
union :声明共用体(联合)数据类型
enum :声明枚举类型
void :声明函数无返回值或无参数,声明无类型指针
控制语句关键字(12个)
1. 循环控制(5个)
for :一种循环语句
do :循环语句的循环体
while :循环语句的循环条件
break :跳出当前循环
continue :结束当前循环,开始下一轮循环
2. 条件语句(3个)
if : 条件语句
else :条件语句否定分支
goto :无条件跳转语句
3. 开关语句 (3个)
switch :用于开关语句
case :开关语句分支
default :开关语句中的“其他”分支
4. 返回语句(1个)
return :函数返回语句(可以带参数,也看不带参数)
存储类型关键字(5个)
auto :声明自动变量,一般不使用
extern :声明变量是在其他文件中声明
register :声明寄存器变量
static :声明静态变量
typedef :用以给数据类型取别名
其他关键字(3个)
const :声明只读变量
sizeof :计算数据类型长度
volatile :说明变量在程序执行中可被隐含地改变
存储金字塔
距离CPU越近的存储硬件,速度越快
寄存器存在的本质:
在硬件层面上,提高计算机的运算效率;因为不需要从内存里读取数据
register 修饰变量:
尽量将所修饰变量,放入CPU寄存区中,从而达到提高效率的目的
什么样的变量可以采用register:
1. 局部的(全局会导致CPU寄存器被长时间占用)
2. 不会被写入的(写入就需要写回内存,后续还要读取检测的话,register就无意义)
3. 高频被读取的(提高效率所在)
4. 如果要使用,不要大量使用,因为寄存器数量有限
全局变量和函数的两个结论:
1. 全局变量,是可以跨文件,被访问的
2. 全局函数,是可以跨文件,被访问的
static的作用:
1. 修饰全局变量,该全局变量只能在本文件内被使用
2. 修饰函数,该函数只能在本文件内被使用
总结:static修饰全局变量,影响的是作用域的概念,函数类似;而生命周期是不变的
#include
#include
int main()
{
double x = 1.0;
double y = 0.1;
printf("%.50f\n", x - 0.9);
printf("%.50f\n", y);
if ((x - 0.9) == y)
{
printf("you can see me!\n");
}
else{
printf("oops\n");
}
system("pause");
return 0;
}
结论:因为精度损失问题,两个浮点数,绝对不能使用==进行相等比较
伪代码
if((x-y) > -精度 && (x-y) < 精度)
{
}
伪代码-简洁版
if(fabs(x-y) < 精度)
{
fabs是浮点数求绝对值
}
精度:
1、自己设置,后面如果有需要,可以试试,通常是宏定义。
2、使用系统精度,暂时推荐
#include 使用下面两个精度,需要包含该头文件
DBL_EPSILON //double 最小精度
FLT_EPSILON //float 最小精度
代码调整后
#include
#include 必须包含math.h,要不然无法使用fabs
#include 必须包含,要不然无法使用系统精度
#include
int main()
{
double x = 1.0;
double y = 0.1;
printf("%.50f\n", x - 0.9);
printf("%.50f\n", y);
if (fabs((x - 0.9) - y) < DBL_EPSILON)原始数据是浮点数,我们就用DBL_EPSILON
{
printf("you can see me!\n");
}
else
{
printf("oops\n");
}
system("pause");
return 0;
}
两个精度定义
#define DBL_EPSILON 2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0
*/
#define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0
*/
XXX_EPSILON是最小误差,是:XXX_EPSILON+n不等于n的最小的正数。
EPSILON这个单词翻译过来是'ε'的意思,数学上,就是极小的正数
基本使用
#include
#include
int main()
{
int i = 0;
START:
printf("[%d]goto running ... \n", i);
Sleep(1000);
++i;
if (i < 10)
{
goto START;
}
printf("goto end ... \n");
system("pause");
return 0;
}
问题:
struct people *p = NULL;
....
goto start;
p = (struct people *)malloc(....) goto被跳过,没有初始化
....
start:
使用p指向的内存里的值的代码
....
const修饰变量
#include
#include
int main()
{
const int i = 10;
i = 20; 报错,代表变量i不可以直接被修改
system("pause");
return 0;
}
const修饰变量真的不能被修改吗?
#include
#include
int main()
{
const int i = 10;
int *p = (int*)&i;
printf("before: %d\n", i);
*p = 20;
printf("after: %d\n", i);
system("pause");
return 0;
}
结论:const修饰的变量并非是真的不可被修改的常量
那const修饰变量,意义何在?
1. 让编译器进行直接修改式检查
2. 告诉其他程序员(正在改你代码或者阅读你代码的)这个变量后面不要改,也属于一种“自描述”含义
const修饰的变量,可以作为数组定义的一部分吗?
#include
#include
int main()
{
const int n = 100;
int arr[n];
system("pause");
return 0;
}
在vs2013(标准C)下直接报错了,但是在gcc(GNU扩展)下,可以
typedef 与 #define 的区别
问题1:
typedef int * ptr_t;
ptr_t p1,p2;
问:p1,p2分别是什么类型
#define PTR_T int*
PTR_T p1, p2;
问:p1,p2分别是什么类型
问题2:下面关于typedef部分的代码对吗?
#include
#include
#define INT32 int
typedef int int32;
int main()
{
unsigned int32 a = 10; C中typedef不支持这种类型的扩展,不能当成简单的宏替换
unsigned INT32 a = 20; 宏简单替换,可以
printf("%d\n", sizeof(struct stu));
system("pause");
return 0;
}
typedef static int int32_t 不行,typedef 和 static 都是存储类型关键字
#include
#include
int main()
{
int /* */ i; //正确
char *s = "abcdefgh //hijklmn"; //正确
//Is it a\
valid comment? //正确
in/* */t j; //报错
system("pause");
return 0;
}
注意:注释被替换,本质是替换成空格
C风格注释无法嵌套
#include
#include
int main()
{
/*
/*printf("hello world");
printf("hello world");*/
*/
system("pause");
return 0;
}
/*总是与离它最近的*/匹配
y=x/*p
#include
#include
int main()
{
int x = 10;
int y = 0;
int z = 5;
int *p = &z;
y = x/*p;
system("pause");
return 0;
}
续行功能
#include
#include
int main()
{
int a = 1;
int b = 2;
int c = 3;
试试在\之后带上空格,行不行?
试试在\之前带上空格,行不行?
建议:不要带
if (a == 1 &&\
b == 2 &&\
c == 3)
{
printf("hello world!\n");
}
system("pause");
return 0;
}
转义
C中,有一些字符,就是他的字面意思,比如'n','b','t'。
也有一些字符,本身就是特殊含义的,比如:" , ', \
转义的本质含义是:字面转特殊,或者特殊转字面
基本演示
#include
#include
int main()
{
printf("\""); //特殊转字面
printf("h\tello b\nit!\n"); 字面转特殊
system("pause");
return 0;
}
\n vs \r
各自区别
#include
#include
int main()
{
int i = 10;
while (i >= 0)
{
Sleep(1000);
printf("%2d\r", i--);
}
printf("\n倒计时结束!\n");
system("pause");
return 0;
}
单引号是字符,双引号是字符串
#include
#include
不同编译器,会有细微的差别
int main()
{
printf("%d\n", sizeof(1));
printf("%d\n", sizeof("1"));
C99标准的规定,'a'叫做整型字符常量(integer character constant),被看成是int型
printf("%d\n", sizeof('1'));
char c = '1';
printf("%d\n", sizeof(c));
system("pause");
return 0;
}
特殊情况
#include
#include
int main()
{
printf("%d\n", sizeof('')); 报错
printf("%d\n", sizeof("")); 空串大小是多少
system("pause");
return 0;
}
短路
#include
#include
#pragma warning(disable:4996) 特殊处理安全问题的方法
int show()
{
printf("you can see me!\n");
return 1;
}
int main()
{
int a = 0;
scanf("%d", &a);
a == 10 || show();
system("pause");
return 0;
}
1. 浮点数(或者整数相除),是有很多的取整方式的
2. 如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r| < |d|;其中,q 被称为商,r 被称为余数
3. 在不同语言,同一个计算表达式,“取模”结果是不同的;我们可以称之为分别叫做正余数和负余数
4. 具体余数r的大小,本质是取决于商q的。而商,又取决于除法计算的时候,取整规则
5. 取余vs取模: 取余尽可能让商,进行向0取整。取模尽可能让商,向-∞方向取整
6. 参与取余的两个数据,如果同符号,取模等价于取余
7. 如果参与取余的两个数据符号不同,在C语言中(或者其他采用向0取整的语言如:C++,Java),余数符号,与被 除数相同(因为采用的向0取整)
#include
#include
int main()
{
printf("%d\n", 2 / (-2)); //-1
printf("%d\n", 2 % (-2)); //2=(-1)*(-2)+r
system("pause");
return 0;
}
#include
int main()
{
printf("%d\n", -10 / 3); //结果:-3
printf("%d\n\n", -10 % 3); //结果:-1 -10=(-3)*3+(-1)
printf("%d\n", 10 / -3); //结果:-3
printf("%d\n\n", 10 % -3); //结果:1 10=(-3)*(-3)+1
system("pause");
return 0;
}