目录
1 常见关键字
C语言关键字:C语言定义的,具有特定含义、专门用于特殊用途的C语言标识符,也称为保留字
注:关键字是C语言自身定义的,关键字不能自己创建
关键字具有特殊含义,不能作为变量名
typedef是用来给类型取别名的关键字
define不是关键字,是编译器实现的,用来定义宏的预处理指令,不是C语言中的内容。
C语言内置了一些关键字,如常见关键字:
struct关键字是用户用来自定义的结构体类型,不属于C语言的内置类型(int char long short double等)
注:C语言关键字不能自己创建 和 关键字struct是用户用来自定义的结构体类型而不属于C语言的内置类型不矛盾
(一个不能自己创建,一个用户可以自定义)
因为:关键字是语言在设计的时候就给出来了,有特殊含义的, 除了用来表示类型的关键字外 ,还有其他关键字 , 但是C语言提供的表示类型的关键字并不能适应所有情况 有些复杂的数据比如:学生信息 这个内置类型就不能表达 所以才需要自定义类型, 自定义类型只是用户自己定义了一个新的类型 ,这个新的类型并不是关键字。
switch是用来进行多分支选择的语句,一般结构是:
switch(变量表达式)
{
case xx1:
// ...
break;
case xx2
// ...
break;
default:
// ...
}
当变量表达式的内容与某个case后的常量相等后,就执行该case下的语句,break表示该case以后的内容不会执行,如果没有跟break,会继续执行当前case之后的case分支。
当变量表达式的内容没有与那个case匹配,就会执行default下的内容。
switch中常用的关键字:case 、break、 default,当然case中语句比较复杂时,可能会用if进行判断。
continue是用来结束本次循环的,而switch不是循环。
注:EOF——是end of file文件的结束标志,不是字符,是#define定义的符号:#define EOF-1本质上是-1,是一种状态值和标记值,和字符没有关系
数据类型、关键字都不能做变量名
define不是关键字,define的用法:如#define MAX 100
#define中的define是预处理指令,不属于关键字
求两个整数中的较大者:
注:关键字不能自己创建
关键字不能是变量名
static——静态的
C语言中static可以修饰:
1、局部变量
2、全局变量
3、修饰函数
1、关键字static修饰局部变量例如:
#include<stdio.h>
void test()//不需要test这个函数返回值,所以写void,所以void在此表示不需要函数返回任何值
{
int a = 1;
a++;
printf("%d ", a);
}
int main()
{
int i = 0;
//while循环
while (i < 10)
{
test();//每进入循环就调用一次test函数一次,调用完(执行完)后i++
i++;//增1
}
//循环了10次(0—9)循环结束
return 0;//运行结果是:2 2 2 2 2 2 2 2 2 2
}
从进入main函数开始,i是0,进入while循环,遇到test(),则上去(main函数之前)去调用test函数,test函数有一个{}是一个代码块,进入这个函数范围时局部变量a开始创建,生命周期开始,创建a并赋值1,赋值后a++,自增1,a变成了2,打印a即打印2,这是一个2。a是一个局部变量,当printf完出这个test()函数后a是没有必要存在的,局部变量a的生命周期到了就会把它销毁,即把a的空间销毁还回操作系统,这个test()函数调用完后回到(while中)i++,(初始i=0)i变成1,i=1<10再循环进来,遇到test,再上去去执行test,第二次执行test()这个函数,重新调用这个函数,进入到这个函数,a又是局部变量,再次创建a,赋值为1,a++后变成2,再次打印a还是2,a打印完又出这个作用域,没有必要存在,a销毁,再回到(while中)i++,刚刚i是1,i++后变成2,后又进入循环,i=2<10,又遇到test,再上去调用test()函数,每一次调用这个函数时,因为a是局部变量,进入它的范围时它会被创建,创建并赋值a为1,a++后变成2,打印就是2,所以while循环中的test把上面的test()函数调用了10次,所以运行结果是10个2【这里涉及到了局部变量的生命周期】
(划横线的是相当于作为跳板来回跳)
//static修饰的局部变量:(把上述例子稍加改造)
#include<stdio.h>
void test()
{
//a本来是局部变量
//现在使用关键字static修饰a这个局部变量
static int a = 1;
a++;
printf("%d ", a);
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
}
return 0;
}//运行结果是:2 3 4 5 6 7 8 9 10 11
//说明static int a = 1;这一行没有起效果,因为a没有销毁和再创建
//根据结果推测出:每一次调用test函数使用的a都是上次函数调用留下的a,出它的范围也没有销毁
//所以static int a = 1;这一行代码没有意义,编译器执行到这一行并没有任何动作,即这一行不产生任何汇编代码,也不是跳过,是没法在这个地方使用。
//注:内存是一块比较大的存储空间,在使用内存时会划分出不同的功能区域,
//在学习编程语言时:有栈区,堆区,静态区
局部变量a被关键字static修饰之后,就变成了静态的局部变量,就属于静态变量
当是int a=0;没有被关键字static修饰时,a是局部变量,是在栈区里边创建的,而一旦被static修饰之后,a这个变量就不是原来的这个变量了,就不是在栈区里创建的了,而是在静态区里边创建的。
static修饰局部变量的时候,其实改变了变量的存储类型(栈区存储——>静态区存储)因为改变了存储类型,所以改变了使这个变量的属性,失去了局部变量的特性(本来局部变量进入它的范围它创建,出它的范围它销毁,但如果被static修饰之后它放在静态区里了,静态区里的变量即静态变量,出了它的局部范围它是不会销毁的,间接的使它的生命周期变长了)改变了它的存储类型从而使得静态的局部变量出了自己的作用域也不会销毁,其实相当于改变了局部变量的生命周期。
注:作用域是变量的属性,局部变量、全局变量都有自己的作用域。
全局变量的生命周期是整个程序的生命周期,从图中知:全局变量和静态变量放到一起,都在静态区。静态变量的生命周期和全局变量的生命周期是一样的,都是整个程序的生命周期。静态变量的作用域还是它原来范围的作用域,但是它的生命周期变长了,它不销毁,作用域不等于生命周期,两者不是一回事。上例的变量a的作用域总是test()函数内部而不能出这个范围外使用。
static修饰的局部变量改变了变量的生命周期,
让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。生命周期变长。
本质是static修饰局部变量的时候,改变了变量的存储类型,由栈区存储到静态区存储。
static修饰局部变量的特性,static修饰局部变量,该变量不会随函数的结束而消失,并且只在第一次调用时进行初始化,后序调用该函数时,使用的都是上次结束前该变量的值。
以上是关键字static修饰的局部变量。
//2、static修饰全局变量
//例子:
#include<stdio.h>
extern int g_val;
//声明一下;extern是一个关键字,是专门用来声明外部符号的
//声明的语法就是:extern+类型+变量名(即把外部文件创建的变量int g_val = 2021等号前面说清楚即可)
//extern声明:告诉你说我有一个变量,叫什么(变量名),它的类型(int)
//注:在使用之前声明
int main()
{
printf("%d\n", g_val);
return 0;
}
//注:如果想使用来自其他文件(外部文件)的全局变量,需要先声明一下(即告诉你我有什么什么东西)
//所以一个全局变量可以在其他源文件中使用。(创建的两个文件名不能一样)
//所以一个全局变量的作用域是很广的,是整个工程。整个工程的任意地方想使用都可以有办法使用得到。
//如果static修饰这个全局变量呢?
//运行不了,显示:error LNK2001: 无法解析的外部符号 _g_val
//本来这个全局变量在整个工程中都可以使用,但被关键字static修饰后就用不了了,报错误。
//一个全局变量在整个工程的其他文件内部能被使用,是因为全局变量具有外部链接属性,
//即是说一个全局变量本身是有外部链接属性的,其他源文件链接是可以直接使用的,
//当一个全局变量被关键字static修饰的时候,这个全局变量的外部链接属性就变成了内部链接属性,
// (即意思是只能自己看到,别人看不到)
//使得这个全局变量只能在自己所在的源文件内部使用,其他文件不能再使用。
//给我们的感觉是作用域变小了。(本来是能在整个工程中使用现在只能在自己源文件内部使用)
//(变量有一种属性叫外部链接属性和内部链接属性)
//全局变量本身是具有外部链接属性的——在这个源文件中定义的,其他源文件也可以使用。
//而一旦这个全局变量被关键字static修饰之后它就具有了内部链接属性,这是一种语法形式,只能自己看得到,
//其他源文件不能看得到。
//所以static改变的是链接属性,这个链接属性使得作用域变小
//static让全局变量失去了外部链接属性,变成了内部链接属性,因为这个链接属性的变化使得它作用域表小了,
//生命周期没有变,因为本来一个全局变量的生命周期和一个静态变量的生命周期是一样的。
//(全局变量和静态变量都放在了静态区)由原来的全局变量变成了静态变量其生命周期是没有变化的,
//存储位置也没有发生变化,还是在静态区放着。
//静态的全局变量也是一个静态变量。静态变量只能在自己所在的源文件内部使用,
//出了这个源文件其他地方不能使用。
//“生命周期还是整个工程”说法是错误的,生命周期不是工程,生命周期是程序的生命周期
//生命周期描述的是时间的长短作用域描述的才是范围,这个范围是源文件还是整个工程,
//生命周期和源文件不是一回事。
//static修饰的局部变量存放的位置换了。
//一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用。
//static修饰全局变量,让全局变量的外部链接属性变成了内部链接属性,从而使得它的作用域变小了,
// 改变的是它的链接属性。作用域变了(变小)生命周期不变
//全局变量是具有外部链接属性的,它本身没有内部链接属性,
//局部变量具有的是内部链接属性,局部变量只能在自己的源文件内部使用。
//而一个变量在a文件中定义的,在b文件中能够访问它,说明这个变量就具有外部链接属性。
//一个文件在a文件中定义的,在b文件中不能访问它,说明它具有内部链接属性。
//3、关键字static修饰函数
//关键字static修饰函数与修饰全局变量是一样的。
运行正常。
test.c源文件中:
#include<stdio.h>
int main()
{
int a = 10;
int b = 20;
int ret = Add(a, b);//a传过去,b传过去,完成参数的传入,算出的结果放到ret里。
printf("%d\n", ret);
return 0;
}
add.c源文件中:
//定义Add函数
int Add(int x, int y)
{
return x + y;//两个整数的相加得到的结果也是整数,所以Add前应该加int
}
//这个函数是在外部定义的加法函数,需要声明,声明外部函数需要extern
//声明函数:extern+返回类型(int)+函数名(Add)+参数(int x,int y)
//声明告诉的是:函数名叫Add,它有两个参数,一个是int,另外一个也是int,
//一个是整型,另外一个也是整型,它的返回类型也是整型
所以函数也是具有外部链接属性的
那么static修饰的函数呢?
即在add.c源文件中:int Add(int x, int y)前加static:
外部符号是来自外部符号的Add.
本来这个函数没有被static修饰时,在另一个文件中是可以使用的,结果被static修饰之后就不能被使用了。
static修饰函数的时候,函数本来也是具有外部链接属性的,被static修饰的时候就变成了内部链接属性,那么这个函数只能在自己所在的源文件内部使用,不能在其他文件内部使用,给我们的感觉是改变了作用域。
即关键字static修饰全局变量和函数时的作用效果是一样的。
注:只要要在其他外部源文件内使用,就要在任意使用的地方extern一下(声明)(如再添加的第三个文件就需要使用extern声明一下)
//一个全局变量本来是在这个源文件中定义,可以在这个源文件中使用,但是加上static之后,即使有extern来声明,在其他源文件内部依然不可以使用。原因是因为链接属性失效了,不能在其他源文件中被链接到了,找不到了,它只能在自己所在的源文件内使用。
注:函数声明不加extern有时候可以,但不是标准的写法,尽量加上。
extern是用来声明外部符号的,来自其他外部源文件的,在自己源文件中定义的使用时不用加extern。
static让局部变量和函数的外部链接属性失效了,感觉作用的范围更小了。
static使用的场景:
如:add.c源文件中定义了一个函数,想自己使用,不想让其他人使用,只要加上static就可以了。限制范围。方便管理。
注:局部变量不能在其他源文件中使用,局部变量只能在这个局部范围内使用,出了这个范围(代码块)就不能使用了,肯定不能跨文件使用。
一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。
#define定义常量和宏:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#define M 100//#define定义标识符常量,定义了一个M,是100。
#define STR "hehe"//#define定义了一个字符串
int main()
{
printf("%d\n", M);//可以直接打印
printf("%s\n", STR);//字符串用%s打印
return 0;
}//运行结果是:100和hehe,即是#define定义的符号,这个符号可以是整型,可以是字符串,其他的东西,
//像定义的M、STR这是名字,是一种符号而已,定义的这些名字后面是可以加参数的,叫#define定义宏。
//1、使用#define定义宏
(宏和函数是非常相似的)
#include<stdio.h>
int main()
{
int a = 10;
int b = 20;
//若写上一个宏来求a和b的(写上一个函数来求a和b的和)
int ret ADD = (a, b);//给ADD传a,b过去,希望ADD这个宏来帮助计算a和b的和,计算好之后放到一个变量ret里
//"ADD":宏、#define定义的符号名字习惯大写,(小写可以,但大写更好)
printf("%d\n", ret);
return 0;
}//这些和函数的感觉非常相似,接下来需要定义宏:
//#include<stdio.h>
//#define ADD(X,Y) ((X)+(Y))//定义宏,这个宏叫ADD,ADD需要完成两个数的相加,这个宏有两个参数一个是X一个是Y,因为要完成这两个参数的相加:X+Y
所以写上X+Y,因为X,Y是参数,所以需要分别单独括起来,表明X是一个整体:(X),Y是一个整体:(Y),代码算完之后又是一个整体,把整体也括起来,即((X)+(Y))
int main()
{
int a = 10;
int b = 20;
int ret = ADD(a, b);
printf("%d\n", ret);
return 0;
}//运行结果:30
//宏和参数相似,但写法不一样,没有像函数一样出现一个大括号。
//即宏的写法的一个例子:
#include<stdio.h>
#define ADD(X,Y)((X)+(Y))
int main()
{
int a = 10;
int b = 20;
int ret = ADD(a, b);
printf("%d\n", ret);
return 0;
}
//注:这里#define定义宏ADD时,ADD和其后参数(X,Y)之间不能有空格,否则报错。
//在不同的情况下有不同的写法。
//#define定义宏时:#define ADD(X,Y) ((X)+(Y))时没有像函数一样写它的(X、Y)的类型,也没有写宏的返回类型。
//ADD是随意起的,表明加法,但起名字时是有意义的,希望别人看到名字后可以知道其功能。
总结:
static的特性
1. static修饰变量
a. 函数中局部变量:
声明周期延长:该变量不随函数结束而结束
初始化:只在第一次调用该函数时进行初始化
记忆性:后序调用时,该变量使用前一次函数调用完成之后保存的值
存储位置:不会存储在栈上,放在数据段
b. 全局变量
改变该变量的链接属性,让该变量具有文件作用域,即只能在当前文件中使用
c. 修饰变量时,没有被初始化时会被自动初始化为0
2. static修饰函数
改变该函数的链接属性,让该函数具有文件作用域,即只能在当前文件中使用
说static修饰的变量不能改变是错误的,是const修饰的变量不能改变。