C关键字、符号细节

1、关键字细节

1.1、关键字分类

关键字 说明
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 :说明变量在程序执行中可被隐含地改变 

1.2、register

存储金字塔

C关键字、符号细节_第1张图片

                                                距离CPU越近的存储硬件,速度越快

寄存器存在的本质:

        在硬件层面上,提高计算机的运算效率;因为不需要从内存里读取数据

register 修饰变量:

        尽量将所修饰变量,放入CPU寄存区中,从而达到提高效率的目的

什么样的变量可以采用register:

        1. 局部的(全局会导致CPU寄存器被长时间占用)

        2. 不会被写入的(写入就需要写回内存,后续还要读取检测的话,register就无意义)

        3. 高频被读取的(提高效率所在)

        4. 如果要使用,不要大量使用,因为寄存器数量有限

1.3、static

全局变量和函数的两个结论:

        1. 全局变量,是可以跨文件,被访问的

        2. 全局函数,是可以跨文件,被访问的

static的作用:

        1. 修饰全局变量,该全局变量只能在本文件内被使用

        2. 修饰函数,该函数只能在本文件内被使用

总结:static修饰全局变量,影响的是作用域的概念,函数类似;而生命周期是不变的

1.4、float 变量与0比较

#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这个单词翻译过来是'ε'的意思,数学上,就是极小的正数

1.5、goto

基本使用

#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指向的内存里的值的代码
....

1.6、const

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扩展)下,可以

1.7、typedef

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 都是存储类型关键字

2、符号细节

2.1、注释符号

#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;
}

2.2、接续符和转义符

续行功能

#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;
}

2.3、单引号和双引号

单引号是字符,双引号是字符串
#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;
}

2.4、逻辑运算符

短路

#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;
}

2.5、深度理解取余/取模运算

        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;
}

你可能感兴趣的:(c语言,开发语言)