C语言32个关键字详解

以下内容建议大家收藏,全是干货,建议反复观看!!!
Let's  Go ! ! !
首先我们把 C89(C90) 的所有关键字进行一下分类,方便大家理解。
数据类型关键字(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
上面我们把32个关键字进行的详细的分类,下面我们对于单个用法进行介绍,go! go! go!
优质内容推荐,建议每天学习:[字符串函数讲解]   [C语言三子棋游戏]  [操作符详细讲解]

char

字符变量是用类型符char定义字符变量,char的主要作用就是声明字符型变量或函数。

char类型是个1字节,它的取值范围是[-128 , 127]  (-2^7 --- 2^7-1)。

下面我们举几个例子

1. 用char类型定义几个字符串,并且输出

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

2.  同时我们也可以定义char类型的变量,用整型(%d)输出。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

short

类型名为 short int 或 short,声明短整型变量或函数。

short类型为2个字节,它的取值范围是[-32768 , 32767] (-2^15 --- 2^15-1)。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

int

int为基本整型,声明整型变量或函数 。

int类型为4个字节,它的取值范围是[-2147483648 , 2147483647] (-2^31 --- 2^31-1)。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_17,color_FFFFFF,t_70,g_se,x_16

long

1、长整型:long int

long int类型为4个字节。

它的取值范围是[-2147483648 , 2147483647] (-2^31 --- 2^31-1)。

2、双长整型:long long int

long long int类型为8个字节。

它的取值范围是[-9223372036854775808 , 9223372036854775807] (-2^63 --- 2^63-1)。

对于long 类型来说,我们输出的时候有特殊的符号来输出,看案例

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

signed

声明有符号类型变量或函数。
我们知道计算机只认识0和1,所以任何数据到1计算机的底层都会换成0,1,那负数怎么存储呢?肯定这个“-”号是无法存入内存的,怎么办?很好办,做个标记。把基本数据类型的最高位腾出来,用来存符号,同时约定如下:最高位如果是1,表明这个数是负数,其值为除最高位以外的剩余位的值添上这个“-”号;如果最高位是0,表明这个数是正数,其值为除最高位以外的剩余位的值。
#include <stdio.h>
int main(){
	signed int jj = 1124;  //定义有符号的变量
	printf("%d\n", jj);
	return 0;
}

需要说明的是,signed关键字也很宽宏大量,你也可以完全当它不存在,缺省情况下,编译器默认数据为signed类型(char类型数据除外)。

unsigned

unsigned表示的是无符号数据类型,声明无符号类型变量或函数。

被unsigned修饰的变量,其取值范围一定是大于0的。

1、无符号整形    unsigned int            4字节   0 ~ 4294967295

2、无符号短整型 unsigned short int   2字节   0 ~ 65535

3、无符号长整形 unsigned long int    4字节   0 ~ 4294967295

4、无符号字符型  unsigned char       1字节    0 ~ 255

下面我们看几个例子:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 下面我们来来练习一下

#include <stdio.h>
int main(){
	int i = -20;
	unsigned int j = 10;
	printf("%d\n", i + j);  //结果为多少?
	return 0;
}

解析:输出有符号的数据

-20:

1000 0000 0000 0000 0000 0000 0001 0100 原码

1111 1111 1111 1111 1111 1111 1110 1011 反码

1111 1111 1111 1111 1111 1111 1110 1100 补码

10:

0000 0000 0000 0000 0000 0000 0000 1010  原码&&反码&&补码

-20+10

1111 1111 1111 1111 1111 1111 1110 1100                          

0000 0000 0000 0000 0000 0000 0000 1010  +     (1+1,进1,变0)

-------------------------------------------------------------------------------------------------------------------

1111 1111 1111 1111 1111 1111 1111 0110 补码

1111 1111 1111 1111 1111 1111 1111 0101 反码

1000 0000 0000 0000 0000 0000 0000 1010 原码 (-10)

我们想要了解无符号类型的运算,我们先要会二进制的运算呀!

再来两例子练练

//code1
#include <stdio.h>
int main(){
    char a = -128;
	printf("%u\n", a); //输出无符号的数据
	return 0;
}


//code2
#include <stdio.h>
int main(){
    char a = 128;
	printf("%u\n", a); //输出无符号的数据
	return 0;
}

float

float类型也被叫做单精度浮点类型,声明浮点型变量或函数。

float类型为4个字节,它的数值取值范围为[-3.4*10^-38 ~ 3.4*10^38]。

小小提示:在vs里面浮点数默认为double类型,解决方法看案例

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 解决方法:我们在定义的数后面加上一个f,就不会出现这样的警告啦

#include <stdio.h>
int main(){
	float n = 3.14f;
	printf("%f", n);
	return 0;
}

double

double类型也被叫做双精度浮点类型,声明浮点型变量或函数。

double类型为8个字节,它的取值范围为[-1.7*10^-308 ~ 1.7*10^308]。

也有双长精度 long  double,与double类型差不多。

#include <stdio.h>
int main(){
	double n = 3.14;
	printf("%lf", n);
	return 0;
}

注意:关于浮点类型的小细节,重点来啦。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 补充内容:关于 %f 和 %lf 的使用

%f和%lf分别是float类型和double类型用于格式化输入输出时对应的格式符号。
其中:
float,单精度浮点型,对应%f。
double,双精度浮点型,对应%lf。

在用于输出时:
float类型可以使用%lf格式
double类型如果使用了%f格式可能会导致输出错误。

在用于输入时:
double 类型使用了%f格式,会导致输入值错误。
float类型使用double类型不仅会导致输入错误,还可能引起程序崩溃。

struct

struct表示的是一种结构体,结构体是一种构造类型,它是由若干个成员组成。其成员可以是一个基本类型数据,也可以是一个构造体类型。struct是声明结构体变量或函数。

下面我们来定义一些基本的结构体

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_18,color_FFFFFF,t_70,g_se,x_16

案例1:

#include <stdio.h> 
iint main(){
	struct Student{
		long int Num;
		char Name[20];
		char Sex[20];
		char Class[20];
		long long int Tel;
	}
	S1 = { 2019, "李四", "男", "网络1902班", 11245201314 },
	S2 = { 2020, "张三", "女", "网络1902班", 13145201124 };
	printf("学号:%ld\n姓名:%s\n性别:%s\n班级:%s\n电话号码:%lld\n", S1.Num, S1.Name, S1.Sex, S1.Class, S1.Tel);
	printf("\n");
	printf("学号:%ld\n姓名:%s\n性别:%s\n班级:%s\n电话号码:%lld\n", S2.Num, S2.Name, S2.Sex, S2.Class, S2.Tel);
	return 0;
}

 案例2:

//手动输入10个学生的学号,姓名,成绩,并且输出。
#include <stdio.h>
int main(){
	int i;
	struct Student{
	    int num;
	    char name[20];
	    int score;
	}student[10];
	for (i = 0; i < 10; i++){
		scanf("%d%s%d", &student[i].num, &student[i].name, &student[i].score);
	}
	printf("\n");
	for (i = 0; i < 10; i++){
		printf("%3d %3s %3d\n", student[i].num, student[i].name, student[i].score);
	}
	return 0;
}

案例3:

//1、输入两个学生的学号,姓名,成绩。
//2、输出成绩高的那一位学生的所有信息。
//3、当成绩一样时,两位学生的基本信息都输出。

#include <stdio.h>
int main(){
	struct Student{
		int num; //学号
		char name[20]; //姓名
		double sore; //成绩
	}student1, student2; //定义两个结构体变量
	scanf("%d%s%lf", &student1.num, &student1.name, &student1.sore);
	scanf("%d%s%lf", &student2.num, &student2.name, &student2.sore);
	printf("\n");
	printf("The Higher is:\n");
	if (student1.sore > student2.sore){
		printf("No:%d\nname:%s\nsore:%0.1lf\n", student1.num, student1.name, student1.sore);
	}
	else if (student2.sore > student1.sore){
		printf("No:%d\nname:%s\nsore:%0.1lf\n", student2.num, student2.name, student2.sore);
	}
	else{
		printf("No:%d\nname:%s\nsore:%0.1lf\n", student1.num, student1.name, student1.sore);
		printf("No:%d\nname:%s\nsore:%0.1lf\n", student2.num, student2.name, student2.sore);
	}
   return 0;
}

来一个小总结吧:关于struct的三种输出方式 。  直接上代码  Go!

#include <stdio.h>
struct stu{
	int num;
	char name[10];
	char sex;
	int score;
};

int main(){
	struct stu kg = { 2019112130, "憨憨", 'W', 100 };
	struct stu *p = &kg;

	//下面三种输出的结果是一样的
	printf("%d %s %c %d\n", kg.num, kg.name, kg.sex, kg.score);
	printf("%d %s %c %d\n", (*p).num, (*p).name, (*p).sex, (*p).score);
	printf("%d %s %c %d\n", p->num, p->name, p->sex, p->score);

	return 0;
}

union

union也被称为共同体。union 维护足够的空间来放置多个数据成员中的 ”一种”,而不是为每个数据成员配置空间。在union中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址。声明共用体(联合)数据类型。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

enum

enum表示的是枚举类型,利用关键字enum可以声明枚举变量,这也是一种数据类型。使用该类型可以定义枚举型变量,一个枚举变量包含了一组相关的标识符,其中每一个标识符都都对应一个整数值,称为枚举常量。

声明枚举类型。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 这里初始化的值有我们自己来定义,后面的逐个真假。

#include <stdio.h>
enum Color{
	red = 1,
	blue,
	green,
	yellow
};
int main(){
	enum Color color;
	scanf("%d", &color);
	switch (color){
	case red:
		printf("red\n");
		break;
	case blue:
		printf("blue\n");
		break;
	case green:
		printf("green\n");
		break;
	case yellow:
		printf("yellow\n");
		break;
	}
	return 0;
}

void

void类型修饰符(type specifier)表示“没有值可以获得”。因此,不可以采用这个类型声明变量或常量。

1、void用于函数声明,没有返回值的函数,其类型为 void。

#include <stdio.h>
void Add(int x,int y){
	printf("%d\n", x + y);
}
int main(){
	int gg = 11;
	int jj = 24;
	Add(gg,jj);
	return 0;
}

2、void不能用来声明变量或常量

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 3、void是没有返回值的,在void函数里面不能使用return来返回数据。

#include <stdio.h>

void new_line(){ //函数1
	printf("didi\n");
}

void three_line(){ //函数2
	int i = 0;
	for (i = 0; i <= 3; i++){ //循环调用4次函数1
		new_line();
		}
}

int main(){
	three_line(); //输出函数2
	return 0;
}

for

for表示的是一个循环语句,可以控制一个循环,并且在每一次循环时修改循环变量。在循环语句中for应该是最为灵活的,不仅可以用于循环次数已经确定的情况,而且还可以用于循环次数不确定而只给出循环结束条件的情况。

每个for语句包含了3个用分号隔开的表达式。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_19,color_FFFFFF,t_70,g_se,x_16

我们可以控制变量的自增和自减的大小   代码如下 :

//code1:自增
#include <stdio.h>
int main(){
	int i;
	for (i = 0; i < 10; i++){ //每次循环i+1
		printf("%d ", i);
	}
	printf("\n");
	for (i = 0; i < 10; i+=2){ //每次循环i+2
		printf("%d ", i);
	}
	printf("\n");

	for (i = 0; i < 10; i += 3){ //每次循环i+3
		printf("%d ", i);
	}
	return 0;
}


//code1:自减
#include <stdio.h>
int main(){
	int i;
	for (i = 10; i > 0; i--){ //每次循环i-1
		printf("%d ", i);
	}
	printf("\n");
	for (i = 10; i > 0; i-=2){ //每次循环i-2
		printf("%d ", i);
	}
	printf("\n");

	for (i = 10; i > 0; i -= 3){ //每次循环i-3
		printf("%d ", i);
	}
	return 0;
}

我们想一下,在for循环中,3个条件都可以省略吗?

1、省略变量初始化

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

上面因为我们没有对初始化的变量进行赋值,所以报错,我们可以在for循环外面将变量进行赋值,那就不会出现报错啦!

#include <stdio.h>
int main(){
	int i = 0;  //在for循环外面对变量进行赋值
	for (; i < 10; i++){
		printf("%d ", i);
	}
	return 0;
}

 2、省略循环的判断条件

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

由上面的实验我们知道,for循环进入了一个死循环了,所以判断条件不能省略。

3、省略变量更新

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 由上面的实验我们知道,for循环还是进入了一个死循环了。

但是我们可以在for循环里面进行变量更新:

#include <stdio.h>
int main(){
	int i;
	for (i = 0; i < 10; ){
		printf("%d ", i);
		i++;  //在for循环里面进行变量更新
	}
	return 0;
}

 4、在for循环里面我们3个条件都不要,看看会怎么样了!

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

很明显看到,又是一个死循环了。

#include <stdio.h>
int main(){
	int i = 1;
//下面两个都是死循环的语句
	for ( ; ; ){
		
	}

	while (1){

	}

	return 0;
}

总结:在for循环中,变量初始化和变量更新我们可以省略,但是我们不能省略判定条件,不然for就会进入到一个死循环。

例子:求1-100内所有数的和

#include <stdio.h>
int main(){
	int i = 0;
	int sum = 0;
	for (i = 1; i <= 100; i++){
		sum += i;
	}
	printf("%d\n", sum);
	return 0;
}

do

do...while是一个比较特殊的循环,因为在有些条件下,不论条件是否满足,循环过程必须至少执行一次。

do...while语句就是先执行循环体语句的内容,然后判断循环条件是否成立。

下面我们看一个例子:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 所以我们知道了就算不满足判断条件,循环过程必须至少执行一次。

注意:在使用do...while语句时,条件放在while关键字后面的括号中,最后必须加上一个分号。

例子:我们使用do...while来计算1-100之间所有数的和

#include <stdio.h>
int main(){
	int n = 1;
	int sum = 0;
	do{
		sum += n;
		n++;   //这里我们让n进行自加

	} while (n <= 100);

	printf("%d\n", sum); //用sum来计算总和
	return 0;
}

while

while循环语句首先检查一个条件,也就是括号中的表达式。当条件为真时,就执行紧跟其后的语句或者语句块。每执行一遍程序,都将回到while语句处,重新检验条件是否满足。如果一开始就不满足,则跳过循环体中的语句,直接执行后面程序代码。如果第一次检验时满足,那么在第一次或其后的循环过程中,必须得有使条件为假的操作,否则循环将无法终止。

例如下面的代码就是一个死循环

while(iSum<100){
     iSum+=1;
}


while(1){

}

例子:我们使用while循环来计算1-100之间所有数的和

#include <stdio.h>
int main(){
	int n = 1;
	int  sum = 0;
	while (n <= 100){
		sum += n;
		n++;
	}
	printf("%d\n", sum); //计算总和
	return 0;
}

来一点难度的:用二分法找出找出数组中是否存在你要找的那个数,如果有,输出他的下标,如果没有的话,就输出找不到。

#include <stdio.h>  
int main(){
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int sz = sizeof(arr) / sizeof(arr[0]);//计算元素个数
	int k = 7;  //被查找的元素
	int left = 0;//左下标
	int right = sz - 1;//右下标

	while(left<=right){
		int mid = (left + right) / 2;
		if (arr[mid] > k){
			right = mid - 1;
		}
		else if (arr[mid] < k){
			left = mid + 1;
		}
		else{
			printf("找到该元素,下标是:%d\n", mid);
			break;
		}
	}
	if (left > right){
		printf("找不到!\n");
	}
	return 0;
}

break

有时候会遇到这样的情况,不管表达式检验的结果如何,都需要强制结束循环,这时候我们就可以使用break语句。

break语句终止并跳出循环,继续执行后面的代码。

下面是一个死循环。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 但是我们可以用break来解决这个死循环

#include <stdio.h>
int main(){
	while (1){
		printf("blue");	
		break;    //直接结束循环,就不会进入死循环
	}
	return 0;
}

在很多地方我们都可以用break语句来结束循环,大家可以自己去试一试。

continue

在某些情况下,程序需要返回到循环头部继续执行,而不是像break那样跳出循环。

continue的主要作用就是结束本次循环。就是跳过循环体中尚未执行的部分,直接执行下一次循环的操作。 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

#include <stdio.h>
int main(){
	int i;
	for (i = 0; i < 10; i++){
		if (i == 5){
			continue;
			//当i=5时,直接跳过
		}
		if (i == 8){
			continue;
			//当i=8时,直接跳过
		}
		printf("%d ", i);
	}
	return 0;
}

注意:continue语句和break语句的区别:continue语句只能结束本次循环,而不是终止整个循环的执行;break语句则是结束整个循环过程,不再判断执行循环的条件是否成立。

if

if是一种条件语句。If语句通过对表达式进行判断,根据判断的结果决定是否进行相应的操作。

if后面括号中的表达式就是要进行判断的条件,后面的语句部分则是对应的操作。如果if判断括号中的表达式为真,就执行后面语句操作;如果为假值,那么不会执行后面语句部分。
watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_14,color_FFFFFF,t_70,g_se,x_16

#include <stdio.h>
int main(){
	int  n;
	printf("input the num:");
	scanf("%d", &n);   //手动输入一个数,进行判断
	if (n > 10){
		printf("该数大于10\n");
	}
	if (n < 10){
		printf("该数小于10\n");
	}
	return 0;
}

else

if...else语句。在if后的括号中判断表达式的结果,如果判断的结果为真,则执行紧跟if后语句块中的内容;如果判断的结果为假,则执行else语句后的语句块内容。也就是说,当if语句检验的条件为假时,就执行相应的else语句后面的语句或者语句块。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

#include <stdio.h>
int main(){
	int  n;
	printf("input the num:");
	scanf("%d", &n);   //手动输入一个数,进行判断
	if (n > 10){
		printf("该数大于10\n");
	}
	else{
		printf("该数小于10\n");
	}
	return 0;
}

例子:给一个不多于5位的正整数,求出它是几位数;

#include <stdio.h> 
int main() { 
	int s;
	printf("请输入一个不大于5位的整数:");
	scanf("%d", &s);    //手动输入一个数
	if (s < 10){
		printf("这是一个1位数\n");
	}
	else if (10 <= s && s <= 99){
		printf("这是一个2位数%d\n",s);
	}
	else if (100 <= s && s <= 999){
		printf("这是一个3位数\n");
	}
	else if (1000 <= s && s <= 9999){
		printf("这是一个4位数\n");
	}
	else{
		printf("这是一个5位数\n");
	}
	return 0;
}

goto

goto语句为无条件转移语句,可以使程序立即跳转到函数内部任意一条可执行语句。goto关键字后面带一个标点符,该标点符是同一个函数中某条语句的符号。符号可以出现在任何可执行语句前面,并且以一个冒号“:”作为后缀。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

我们来看两个例子

1、goto从上到下

#include <stdio.h>
int main(){
goto end;
	printf("1\n");
	printf("2\n");
	printf("3\n");
	printf("4\n");
end:
	printf("5\n");
	printf("6\n");
	printf("7\n");

	return 0;
}

 2、goto从下往上  (会进入死循环)

#include <stdio.h>
int main(){             //这个代码会进入一个死循环
	printf("1\n");      //到了goto永远往上执行,不会停止
	printf("2\n");
	printf("3\n");
	printf("4\n");
end:  
	printf("5\n");
goto end;
	printf("6\n");
	printf("7\n");

	return 0;   
}

使用goto语句跳出循环。

#include <stdio.h>
int main(){
	int i = 0;
	int n = 0;
	for (i = 1; i < 10; i++){
		printf("The i is:%d\n", i);
		do{  //使用do...while进行循环
			printf("enter the number to select\n");
			printf("(0 is quit,99 for the next step)\n");
			scanf("%d", &n);  //用户选择输入
			if (n == 0){
				goto exit;  //执行goto跳转语句
			}
		} while (n != 99);  //判断用户输入
	}
exit:  //跳转语句执行位置
	printf("Exit the program!\n");
	return 0;
}

switch

case

default

因为上面三个关键字通常在一起使用,所以我们就不分开一一举例,我们直接三个一起联合说明。

switch语句是多分支选择语句。
if语句只有两个分支供选择,而在实际问题中常需要用到多分支选择。在c语言中可以用switch语句直接处理多分支选择情况,将程序的代码可读性提高。

switch后面括号中的表达式就是要进行判断的条件。在switch语句块中,使用case关键字表示检验条件符合的各种情况,其后的语句是相应的操作。其中还有一个default关键字,作用是如果没有符合条件的情况,那么执行default后面默认的情况语句。

#include <stdio.h>
int main(){
	int day;
	printf("请输入1-7:");
	scanf("%d", &day);
	switch (day)
	{
	case 1:
		printf("星期一\n");
		break;
	case 2:
		printf("星期二\n");
		break;
	case 3:
		printf("星期三\n");
		break;
	case 4:
		printf("星期四\n");
		break;
	case 5:
		printf("星期五\n");
		break;
	case 6:
		printf("星期六\n");
		break;
	case 7:
		printf("星期天\n");
		break;
	default:
		printf("你输入的有误!\n");
		break;
	}
	return 0;
}

注意:每个语句后面的break都不能省略了,不然就会出现一对多的情况。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

最后我们总结一下,switch语句的含义:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

return

return 0 代表程序正常退出,return 1代表程序异常退出。

使用return语句可以返回一个变量内的值或一个指针,也可用return0,表示返回为空。

return 代表调到函数外。

return 0代表函数正常终止。return 1代表函数非正常终止。

return 关键字的作用是返回程序流程的控制权。其副作用是返回一个值。

看一个例子:求阶乘

#include<stdio.h>
int Facl(int n){
	int i = 0;
	int ret = 1;
	for (i = 1; i <= n; i++){
		ret *= i;
	}
	return ret;
}
int main(){
	int n = 0;
	int ret = 0;
	printf("请输入一个要求阶乘的数:");
	scanf("%d", &n);
	ret = Facl(n);
	printf("%d\n", ret);
	return 0;
}

auto

auto:在缺省情况下,编译器默认所有的变量都是auto的,所以autu关键字可以省略。

auto关键字用于定义一个局部变量为自动的,这意味着每次执行到定义该变量时,都会产生一个新的变量,并且对其重新初始化。声明自动变量,一般不使用 。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

#include <stdio.h>
void AddOne(){
	auto int j = 1;      //定义auto变量
	j = j + 1;           //变量+1
	printf("%d\n", j);   //显示结果
}

int main(){
	printf("第一次调用:"); 
	AddOne();                //调用函数
	printf("第二次调用:");
	AddOne();                //调用函数
	return 0;
}

extern

extern变量称为外部存储变量。extern声明了程序中将要用到但尚未定义的外部变量。通常外部储存都用于声明在另一个转换单元中定义的变量。 
一个工程是由多个c文件组成的。这些源代码文件会分别进行编译,然后链接成一个可执行的模块。把这样的一个程序作为一个工程进行管理,并且生成一个工程文件来记录所有包含源代码文件。

下面我们通过一个实例来了解一下extern。
首先我们要建立两个c文件。

1、我们在第一个文件里面定义变量

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_15,color_FFFFFF,t_70,g_se,x_16

2、我们在第二个文件里面无法使用在第一个文件里面定义的变量

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_16,color_FFFFFF,t_70,g_se,x_16

3、这时我们可以使用extern关键字来解决这个问题

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 由上面的实验,我们没有在第二个文件里面进行定义变量,更没有对变量进行赋值,但是我们输出了变量的数值。所以extern可以调用在别的文件中定义的变量。

//kk.c
#include <stdio.h>
int jj = 1124;  //定义变量并且对变量进行赋值


//gg.c
#include <stdio.h>
int main(){
	extern jj;
	printf("%d\n",jj);  //1124
	//我们这里调用了第一个文件里面jj的值
	return 0;
}

register

register:这个关键字请求编译器尽可能地将变量存在CPU内部寄存器中,而不是通过内存寻址访问以提高效率。注意是尽可能,不是绝对。可以想象,一个CPU的寄存器数量有限,也就那么几个或几十个,如果用户定义了很多很多register变量,那么即便把CPU“累死”也不可能全部把这些变量放人寄存器,可能轮也轮不到你。

使用register关键字修饰符的注意点:

虽然寄存器的速度非常快,但是使用register修饰符也有些限制的: register变量必须是能被CPU寄存器所接受的类型。这意味着register变量必须是一个单个的值,并且其长度应小于或等于整型的长度﹐而且register变量可能不存放在内存中,所以不能用取址运算符“&”来获取register变量的地址。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

#include <stdio.h>
int main(){
	register int j;  //定义寄存器变量
	j = 1124;        //对j进行赋值
	printf("%d\n", j);  
	return 0;       //程序结束
}

static

static变量为静态变量,将函数的内部变量和外部变量声明成static的意义是不一样的。

static的两个重要作用:

1、修饰变量。变量又分为局部变量和全局变量,但它们都存在内存的静态区。

2、修饰函数。函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数是否会与其他文件中的函数同名。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

#include <stdio.h>
void AddOne(){
	static int j = 1;  //定义static变量
	j = j + 1;
	printf("%d\n", j);
}
int main(){
	printf("第一次调用:");
	AddOne();
	printf("第二次调用:");
	AddOne();
	return 0;
}

关于static定义的变量被其他文件访问

gg.c (第一个文件)
#include <stdio.h>
static int jj;
int gg; 

jj.c (第二个文件)
#include <stdio.h>
extern int gg;        //不报错
extern static int jj; //报错,不能定义多个储存类

int main(){
	gg = 11;          //不报错
	jj = 24;          //报错,类型不同
	printf("%d %d", gg, jj);
	return 0;
}

所以由上面的案例我们知道,在其他的文件中定义的变量,我们可以使用extern来声明此变量,供我们来使用,但是如果在其他文件中该变量被static定义了,我们就无法跨文件使用该变量了。

typedef

typedef关键字用以给数据类型取别名(但是该关键字被分到存储关键字分类中,虽然看起来没什么相关性)。

typedef其实就是一个含义:类型重命名

1. 对一般类型进行重命名 。

2. 对结构体类型进行重命名 。

3. 对指针进行重命名 。

4. 对复杂结构进行重命名。

下面我们来看一下实验案例:

1、对整型重命名

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 2、对数组的重命名

#include <stdio.h>

typedef int i_kg;

int main(){
	i_kg i;
	i_kg arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++){
		printf("%d ", arr[i]);
	}
	return 0;
}

下面我们来一点复杂的,大家尽力思考一下:

#include <stdio.h>

typedef int * ptr_t; 

int main(){
    ptr_t p1,p2; //问:p1,p2分别是什么类型
    return 0;
}


const

const是constant的缩写,是恒定不变的意思,也翻译为常量和常数等。很不幸,正是因为这一点,很多人都认为被const修饰的值是常量。这是不精确的,精确来说应该是只读的变量,其值在编译时不能被使用,因为编译器在编译时不知道其存储的内容。

关于const关键字的主要作用:

1. const修饰的只读变量。

2. const修饰一般变量。

3. const修饰数组。

4. const修饰指针。

5.  const修饰函数的参数。

6. const修饰函数参数的返回值。

7. 节省空间,避免不必要的空间分配,同时提高效率。

下面我们开始实验来进行观察const关键字的作用:

1、被const关键字修饰的变量不能直接被修改

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

2、被const修饰的变量可以使用指针来进行修改

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_19,color_FFFFFF,t_70,g_se,x_16

上面案例原码,大家可以自己实验一下

//code1
#include <stdio.h>
int main(){
	const int jj = 10;

	jj = 20;  //直接报错

	printf("%d\n", jj);
	return 0;
}


//code2
#include <stdio.h>
int main(){
	const int jj = 10;

	int *p = &jj;

	*p = 20;

	printf("%d\n", jj);
	return 0;
}

关于const重点细节讲解:!!!!!!!!!!!!!!!!!!!!!!!!!!!!

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

来一个例题吧,我们应该很了解了const 啦 :

请找出下面程序有哪些错误( )。

#include <stdio.h>
int main(){
	int i = 10;
	int j = 1;
	const int *p1;//(1)
	int const *p2 = &i; //(2)
	p2 = &j;//(3)
	int *const p3 = &i;//(4)
	*p3 = 20;//(5)
	*p2 = 30;//(6)
	p3 = &j;//(7)
	return 0;
}

答案:6 7
解析: (const修饰的哪个变量,它就不可以被改变。关键字不能修饰关键字,const不修饰int)
const在前,内容不能变;
const在后,指针不能变;
const* ,指针指向为常量;
*const ,指针本身为常量。

这里我们多提一下,关于指针的解引用:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

sizeof

sizeof被称为“最冤枉的关键字”,为什么呢??因为很多人都认为sizeof是一个函数。

siezof的主要作用就是计算数据类型长度。

下面我们就来看一下,基本数据类型的字节大小

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

 同时我们也可以使用sizeof来求数组的大小

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_20,color_FFFFFF,t_70,g_se,x_16

#include <stdio.h>
int main(){
	int jj[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	//int为4个字节
	//我们定义了10个数
	//所以10*4=40个字节
	printf("%d\n", sizeof(jj));//40
	
	//下面我们求的是数组的空间大小
	printf("%d\n", sizeof(jj)/sizeof(jj[0]));//10
	return 0;
}

volatile

volatile关键字和const一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其他线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

我们来看一个例子:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR5Lya5LiA55u05Zyo55qE,size_17,color_FFFFFF,t_70,g_se,x_16

此时编译器对代码进行优化,这是因为在①、2两条语句中,i没有被用作左值(没有被赋值)。这时候编译器认为i的值没有发生改变,所以在①语句时从内存中取出i的值赋给j之后,这个值并没有被丢掉,而是在②语句时继续用这个值给k赋值。编译器不会生成出汇编代码重新从内存里取i的值(不会编译生成装载内存的汇编指令,比如ARM的LDM 指令),这样提高了效率。但要注意:①、②语句之间确认i没有被用作左值才行。

  • 188
    点赞
  • 1090
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我会一直在的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值