C语言关键字篇
# 1.一些关键字
存储型关键字,不可以在定义变量时同时出现,只能出现一个。
auto——只用来修饰局部变量,一般省略。
register——将需要高频读取的变量放到寄存器中。此时的变量无法取地址(&)
register int a = 1;
static
- static修饰的全局变量和函数不可以被其他文件调用。static改变了全局变量的作用域,而没有改变生命周期。
- static修饰局部变量,static改变了局部变量的生命周期,而没有改变作用域。
extern——声明变量或函数。声明变量时,变量无法被赋值,因为变量声明实际不开辟空间。
// hello.h
#pragma once
#include <stdio.h>
extern int a; //变量外部调用时需要声明。变量必须加extern,因为头文件只能包含变量的声明
extern void PrintHello(); //函数外部调用不声明可以运行,但是会warning。(编译报警,链接可进行所以不报错)。
//函数可以不带extern,因为也能表示声明。
// hello.c
#include "hello.h"
void PrintHello()
{
printf("Hello World!\n");
}
int a = 6;
//main.c
#include "hello.h"
int main()
{
printf("a = %d\n", a);
PrintHello();
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- typedef
typedef int a[10]; // 此时a 为一个数组的类型,不推荐
a b; // 定义一个a类型的变量
2
- volatile
告知编译器,不要将变量进行优化(不要将变量加载到寄存器,每次仍旧是从内存中读取,这样可以感知变量在内存中的变化并对其进行修改)。while(a)
const
const修饰变量:本质是告诉编译器变量不可被修改,并不意味着变量是常量,可以使用指针对变量进行修改。const变量必须在定义的时候初始化。
const修饰指针:
int a = 1; const int *p = &a; // const在*之前,代表p指向的内容不能被修改;等价于int const*p = &a;int *p = 10(报错)。 int * const p = &a; // 修饰p,代表p的内容不可被修改, const int * const p = &a; const int *p = &a; int *pp = p; // pp指向的内容可以被修改,而p指向的内容不可以被修改,这样赋值会产生语言冲突,编译器报警。 int * const p = &a; int *pp = p; // 相当于把const变量赋值给pp
1
2
3
4
5
6
7
8
9
10
# 2.语句控制
- switch_case_default
switch(整型变量|整型表达式|整型常量)
{
case 1: // (必须是常量,const的变量不行);对于频繁可以匹配的case语句,可以往前放。
printf("1\n");
// break; 没有break时语句会顺序执行。
case 2:
printf("1\n");
break;
case 3:
printf("1\n");
break;
case 4:
printf("1\n");
break;
default:
break;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- goto:实现函数体内的跳转
int main()
{
int a = 0;
start:
printf("a = %d\n", a++);
if (a < 6)
{
goto start; //跳转到标签位置,其中标签位置可以再goto之前和之后
}
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
do_while:先运行一次,再循环判断。
for
for(;;){
// for循环的死循环结构。
}
2
3
- continue
对于do_while和while循环,continue到条件判断处;对于for循环中的continue,跳转到条件更新处。
# 3.数据类型
# 3.1内置类型
整型变量int(signed和unsigned)、long等在内存中以二进制补码的方式存储。
对于有符号数sighed
- 有符号的正数:原码=反码=补码。
- 有符号的负数,其反码为:符号位不变,其余各位按位取反。补码=反码+1。其数据范围为[-2n, 2n-1],n表示数据bit位的位数。出现-2n,如char类型为-128(1000 0000)可以看成符号位发生了溢出(11000 0000),但不影响补码的运算。
对于无符号数unsigned
- 原码=反码=补码
bool类型是C99引入的标准,使用需要包含<stdbool.h>头文件。一般bool类型的变量大小为1字节。
C语言关于浮点数类型默认使用的是double,对于小数向float类型变量赋值,如
float a = 3.14
,需要对数据类型进行指明,如3.14f
,否则会产生数据截断的警告。
// 关于数据类型后缀
(U\u)——unsigned int
(L\l)——long
(LL\ll)——long long
f——float
3dfh(H\h)——16进制
(0)23——8进制
10110(B\b)——2进制
2
3
4
5
6
7
8
浮点数存储的时候不是一个精确的值,会在数据的末尾产生一些莫名的位数,因此不能用==
直接对浮点数进行比较,会出现逻辑的漏洞。也不要出现<=
\ >=
若要比较两个浮点类型的大小,可以判断: $$ \left| x-y \right| < \varepsilon $$
#include <float.h>
fabs(x-y) < 精度(DBL_EPSILON,C语言宏定义double类型的最小精度; FLT_EPSILON)
// x ?= 0.0
fabs(x) < 精度
2
3
4
5
- void
void:不能定义变量,因为不知道为变量开出多少空间,编译器会强制对空类型进行约束。
- void可用来修饰函数的返回值,表示函数不需要返回值。这是一个占位符,编译器可以通过其来判断程序中是否含有非法的调用。如int a = fun();
- 修饰函数参数列表,表示函数不需要传参。若有传参编译器会作相应检测。fun(void)
void *: 可以定义void *的指针,因为指针的大小为4/8字节(32位和64位系统)。void *可以被任意类型的指针赋值,也可赋值任意类型的指针。
- vs中sizeof(void) = 0; Linux中sizeof(void) = 1。 因此VS中,void * p不可以对p进行++或--,因为不清楚移动多少字节指向哪个地址;但是Linux可以。p++ = p + sizeof(p)
- void *类型的指针变量无法解引用——解引用相当于是一个void类型的变量。
# 3.2 自定义类型
- union:其中定义的变量从低地址开始的(栈是从高地址开始压栈的)
- enum: 定义相关性较强的常量
enum Color{
RED,
YELLOW,
BLUE
};
enum Color col = RED;
2
3
4
5
6
7
enum color {
RED,
BLUE
};
int main()
{
//int RED = 10; // 可以被修改
printf("%d\n", sizeof(RED)); // ——》4,int型
printf("%d\n", RED);
return 0;
}
2
3
4
5
6
7
8
9
10
11
# 库函数
- getchar();读取标准输入的一个Ascii字符,会读入回车符号。返回值是int类型,若用char只能表示读取成功的256个Ascii字符,而无法判断读取失败的情况。
# 指针
- 操作系统是按字节序在内存中进行寻址的,对于int型4字节变量,指针指向的是地址最低的一个字节。