C语言关键字

关键字

一、C语言的关键字一共有32个,除了常见的以外,现在列举几个不常见的关键字:auto、register、
volatile、extern、sizeof;
二、常用关键字的使用和注意事项:
1、auto:
声明自动变量,缺省是编译器一般默认为auto;
2、register:
最快的关键字,尽可能的将变量存在CPU的寄存器中,而不是通过内存寻址访问来提高效率;注意是尽量而不是绝对,因为寄存器的数量有限,也就最多十几个,CPU不同数量也不一样;
ps:寄存器是内存和CPU的中转站。使用时必须注意register变量是单个值,且其长度是小于或等于int的值,还有因为不是存在内存中,所以就不能使用&来访问register变量的地址;
3、static:
1)修饰变量(不管是全局变量还是局部变量,都存储在内存的静态区):

  • 修饰全局变量:使变量的作用范围就只能是当前文件,就算是使用extern关键字,也是无法访问的;其作用域就是从定义之处到文件的结尾,其定义之前的代码使用这个变量,要使用extern关键字,如果想要省去麻烦,就在文件的开头定义static变量。
  • 修饰局部变量:在函数里面定义,作用域就是当前这个函数,就算是同一文档的其他函数也不能访问这个变量;由于存储在内存的静态区,就算函数执行完毕,这个变量也不会随着函数的结束而被销毁,而是保存在静态区,其值也不会改变;这个函数再次调用时,也能使用这个变量,不会重新定义一遍,还是之前那个变量;

2)修饰函数:表示该函数的作用域是当前页面,而不是指存储方式;使用static的好处是:对于不同的人编写的程序,不用担心自己写的函数和其他人写的函数名重名的问题;
3)static修饰的全局变量都写在.cpp文件里面,而不会写在.h文件里面原因如下:
如果在头文件里面用static修饰变量:

//test.h
#ifndef TEST_H
#define TEST_H
static char ar[]="hello";
#endif


//test1.cpp
include"test.h"
int main()
{
   printf("%s",ar);
    return 0;
}


//test2.cpp
#include"test.h"
int main()
{
      printf("%s",ar);
      return 0;
}

这时有两个.cpp文件test1.cpp和test2.cpp引用这个头文件,编译器不会报错,且这两个文件的.obj文件中都有“hello”,编译器可以通过且不会报重定义是因为这两变量是具有相同的值,但有两个不同物理地址,就像两个不同的变量被赋予相同的值,作用于不同的编译文件。再深入一点会发现这两个ar具有相同的地址,这时就会让人误解用static修饰的变量可以在不同的文件中访问,这是因为编译优化的结果,编译器会优化代码,如果是相同的值,编译器只会拷贝一份内存,而不会两个,在链接的时候就只会有一份内存;
但如果这时修改ar的值的话,编译器就会强迫恢复原来物理内存的模样,开辟两块内存来存这个值,ar的地址也会不同;这时就是static将这一个变量分为两份,供两个文件使用。为了避免这种情况,就要记住不要在头文件里使用static来修饰变量;
4、基本数据类型:
float,double,long,int,short,char(六大基本数据类型)
C的数据类型分为:基本数据类型(整型、浮点型)、构造数据类型、指针类型、空类型(void)
构造数据类型分为:数组、结构体struct、共用体union、枚举enum
5、sizeof:
计算对象的内存空间是多少;在计算变量时可以省略括号,而在计算类型的时候就不能省略括号
6、

  • bool变量和“0”值进行比较:
    最好的比较书写:
    bool tag=false;
    if(!tag)

  • 指针变量和“0”比较:
    int *p;
    if(NULL==p)

因为这样可以防止少打一个零的情况:eg:如果写成if(p==NULL);当少打了一个等号的时候就变成了if(p=NULL);有时候这样照样可以通过,写成if(NULL=p)这样编译器就会给你提示报错

7、if语句:

  • if语句之后是不能加分号的:
    if(a>0);
    b=2;
    这里不过if中的语句是否成立,都会执行b=2;因为在C中;表示一句代码的结束,如果什么都没有写,则表示空语句
  • 使用if语句应该先处理正常的情况,在处理异常情况,因为如果先处理异常的情况,会大几率的执行一些没有必要的代码,浪费时间;

8、switch、case

  • switch处理的是多情况的时候的选择语句
  • 每个case后都必须加上break;除非是特殊的情况,且必须要有default表示其他情况,如果缺少了的话,会让人误解你没有考虑其他默认的情况
  • case 后只能是整型、字符型的常量或常量表达式

9、do、while、for
在C中有三的死循环:

  • for(;;)
  • while(1){}
  • do{}while(1)

10、break,continue的区别
break是表示终止本层循环,而continue是结束当前循环,执行下一次循环
11、void

  • 任何类型的指针可以赋值给无类型的指针,但这并不意味着无类型的指针可以赋值给有有类型的指针。因为无类型可以包含有类型,而有类型不能包容无类型。例如:我们可以说男人和女人都是人,但不能说人是男人或人是女人;
  • 在C语言中没有写返回类型的函数,默认是int而不是void;为了混淆这些定义,我们必须要给返回类型为空的函数的返回值置为void
  • 在C语言中可以给无参函数传递任意类型的参数,而在C++中是不能给无参函数传递任何类型的参数,所以无论是C语言还是C++如果函数不接受任何参数,一定要指明参数为void;

12、return
return 不能返回一个栈内存的指针,因为在函数结束时,该内存会被自动销毁;
13、const

  • const 修饰的变量在C语言中不是常量的意思,实质上还是变量,只是加上了只读的属性;且在声明的时候必须初始化,因为如果没有初始化,之后的赋值由于是常量的属性而不能够修改,所以必须在定义的时候进行初始化。

  • const和#define的区别:

    1)编译器不会为const的只读变量分配内存空间,而是将他们放在符号表中,是他们成为编译时期的值,没有存储和读内存的操作,在第一次使用常变量时才为它们分配内存空间,之后再次使用也不会再分配其他的内存空间,在整个程序中只有一份拷贝(因为它是全局只读变量,放在静态区);而#define定义的宏变量在内存中有多个拷贝。
    2)从汇编的角度来说,const定义的变量只是给出了对应的内存地址,而不是像#define给出了一个立即数,只是在预编译的时候进行替换;const是在编译的时候才给它的确切地值。
    3)#define 没有类型,而const具有特定的类型。

  • const修饰指针:
    const int*p; //p指向的对象不可变,p可变
    int const *p;//p指向的对象不可变,p可变
    int *const p;//p指向的对象可变,p不可变
    const int*const p;//p指向的对象和p都不可变
    记忆原则:去掉类型,const离谁最近,就修饰谁,谁就是不可变

14、volatile
用它修饰的变量表示可以被某些编译器的未知因素而改变,比如操作系统、线程或者硬件设备等,编译器如果遇到这种变量就不再对其优化,优化器没次使用这个关键字修饰的变量的时候都是从内存中访问,而不是从寄存器中。

int i=1;
int j=i;//(1)
int k=i;//(2)

在这里在进行(1)的赋值语句的时候,编译器会在内存中访问i的值,然后赋值给j;然而在执行(2)的时候,之前从内存中访问i的时候得到的值并没有被销毁,这时候会将这个值再赋值给k;而不是从内存中在次访问i的值,这样就提高了效率;因为在(1)和(2)这两个语句中i并没有作为左值进行被赋值,这时候编译器就认为i的值没有被改变,而将第一次使用i的值保存下来为下一次使用。如果i被重新赋值,编译器将再次从内存中取i的值。

volatile i=1;
int j=i;
int k=i;

这里使用volatile修饰i,这是编译器会认为i的值是不断变化的,所以,每次使用i的时候都会从内存中读取i的值。

15、extern
extern 可以置于函数和变量之前以表示变量或者函数的定义在别的文件中,下面的代码用到的这些变量或函数是外来的,不是本文件定义的,提示编译器遇到此变量和函数时在其他模块中寻找 其定义。

16、struct
结构体的大小是其成员内存之和,空的结构体的大小是1字节(byte),因为编译器认为任何类型都有其大小,用它来给每一个变量分配确定的内存大小,所以认为空的结构体是有大小的,而非空的结构体的大小是1字节,也就是只有char类型的以一个变量,所以编译器会为每一个结构体至少预留一字节的空间,所以空的结构体的大小是1字节。
17、柔性数组
在一各个结构体的最后一个数组可以是未知大小的,但它之前必须要有其他成员,用sizeof计算结构体的大小时,不包含该数组的大小,也就是说这个结构体不包含这个数组,但在使用该数组的时候必须要用结构体变量来使用,只有使用该数组的时候结构体才承认这个数组是它的成员。该数组是由malloc动态分配大小,其实柔性数组和结构体是没有什么关系的,C89不支持,但C99却把它当成一个特例来使用。
18、union
union维护足够的空间来放置多个数据,但所有的数据都共用一片内存,也就是说,他们是共享内存的,以节省空间。用在不需要同时使用它们中任意两个或两个以上的成员的时候使用。内存的大小是所有成员中所占内存最大的决定,所存储的内容是最后使用该内存的成员的数据。
可以用union来判断该电脑的存储模式:

union
{
   int i;
   char ch;
}c;
c.i=1;
return (c.ch==1);

如果返回值是0,则表示当前系统是大端模式,如果返回值是1,则表示当前系统是小端模式。
19、enum
枚举的成员在使用的时候都是常量,在定义的时候可以给他们赋值,之后的变量没有赋值的话会依次加一,如果所有的变量都没有赋值的话,第一个成员是从0开始,之后再依次加1。
和#define 的区别:
1)#define是宏常量,在预编译阶段就进行简单的替换,而枚举常量是在编译的时候才确定其值。
2)枚举常量是可以调试的,而不能调试宏常量。
3)枚举可以一次定义大量的相关常量,而#define宏只能一次定义一个。

符号

1、连接符和转义符

1)\作为连接符时后面不能有空格,表示这一行和下一行是连接在一起的。
char
a
=\
10;

和char a=10;是相同的意思。
2)\还可以作为转义符的开始的标志。广义上讲,C语言字符集中的任何一个字符都可以用转义字符表示。

2、++、–操作符

1)++
int i=3;
int x=(++i,++i,i+10);
在逗号表达式中,i在遇到每一个逗号后,认为此次计算结束,这时候i自加,所以这里是i自加两次然后在和10相加,得到x=15;此时i的值为5;
在C语言中有一个规则:每一个符号应该包含尽可能多的字符,也就是说编译器将程序分解成符号的方法是,从左到有右一个一个字符的读入,如果该字符可能组成一个符号,那么在下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号
所以:int i=0;++i+++i+++i;此时i的值为++i i++ + i++ + i

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值