C语言之关键字

关键字修饰变量
局部变量未赋初值初始化为垃圾值
全局变量和静态变量未赋初值初始化为0

  1. 闪电飞刀:register
    register是局部变量,不能取地址,因为register变量存储在寄存器中,不是在内存,一般循环变量(大量频繁操作)定义成register变量(数量尽量较少)来提高效率,另外变量长度应该小于等于寄存器长度

  2. 隐形刺客:auto
    局部变量默认为auto变量,存储在栈空间

  3. 外来的和尚会念经:extern
    想在其他 .c 文件调用本文件 .c 中定义的变量,用extern声明, 声明外部变量,告诉编译器变量在其他文件定义,也可以声明函数(因为函数相当于全局变量)
    extern int num √
    extern int num = 100 ×
    注意:声明不分配内存,定义分配内存

  4. 政权旗帜:static

(1)修饰全局变量,改变全局变量的作用域,使变量只能在本文件中调用,不能再其他文件中调用

(2)修饰函数(相当于修饰全局变量)

(3)修饰局部变量改变局部变量的生命周期:不加static变量存放在栈空间内,函数运行完被释放;加static变量存放在数据段(静态存储区),直到程序运行结束才释放
C语言之关键字_第1张图片
运行结果:1 1 1

C语言之关键字_第2张图片
运行结果: 1 2 3

面试题:

  1. 如何引用一个已经定义过的全局变量?
    答 、可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。

  2. 全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
    答 、可以,在不同的C文件中以static形式来声明同名全局变量
    可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错。

  3. 铁布衫const
    const意味着常数 ×
    const意味着只读 √
    const不仅可以修饰基本类型,还可以修饰构造类型
    怎么判断谁的值不变记住两个要点:
    (1)将类型去掉
    (2)看const修饰谁,谁就有了铁布衫,谁的值就是不能修改的
    C语言之关键字_第3张图片
    1.去掉类型int,const a = 10,a的值不变
    2.去掉类型int,const a = 10,a的值不变
    3.去掉类型int,const a[10],数组的值不变
    4.去掉类型int ,const *p,指针p指向的空间的值不能变
    5.去掉类型int *,const p,指针p的地址不能变,指向空间的值可以变
    6.去掉类型struct devices,const dev[5],数组的值不变
    7.去掉类型struct devices,const *dev[5],数组指针指向空间的值不能改变

const的作用:
1). 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。
2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。

  1. 专一王子:volatile

顾名思义,volatile表面意思是易挥发,易变化,它修饰的变量的值很容易因为外部因素而发生改变,因此要求编译器每次对变量进行访问时老老实实去内存里面读取,先来看一个例子:
int a = 10;
int b = a;
int c = a;
因为cpu访问内存速度较慢,编译器为了提高效率,图“省事”,直接将a的值给了b,单从这段代码来看是没有问题的,但是如果有以下几种情况就很容易出错:
(1)并行设备的硬件寄存器(如:状态寄存器
(2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
(3)多线程应用中被几个任务共享的变量

面试题:
(1)一个参数既可以是const还可以是volatile吗?解释为什么。
(2)一个指针可以是volatile 吗?解释为什么。
(3)下面的函数有什么错误:
int square(volatile int ptr)
{
return ptr * ptr;
}
答案:
(1) 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
(2)是的。尽管这并不很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的指针时。
(3)这段代码的目的是用来返指针
ptr指向值的
平方,但是,由于
ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = ptr;
return a * b;
}
由于
ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}

  1. typedef详解
    作用:为一种数据结构起一个新的名字(通常与结构体连用)
    面试题一:找出下题错误并改正
    C语言之关键字_第4张图片
    本题错误:新类型本身还没有建立完成,这时候新类型名字还不存在,也就是编译器不认识p_node
    正确写法;
    C语言之关键字_第5张图片
    面试题二:
    以下两种情况的意图都是要定义p_str 。哪种方法更好呢?为什么?
    #define p_str char *
    typedef char * p_str
    答案:
    通长讲,typedef要比#define好,特别是在有指针的场合。请看例子:
    typedef char * p_str1;
    define p_str2 char *;
    p_str1 s1, s2;
    p_str2 s3, s4;
    在上述变量定义中,s1,s2,s3都被定义成char * ,但是s4被定义成char,不是我们所预期的指针变量,根本原因就是#define知识简单的文本替换而typedef则是为一个类型起一个新名字

  2. sizeof(求数据类型长度)
    面试题:以下代码中的两个sizeof用法有问题吗?
    void UpperCase( char str[] ) // 将 str 中的小写字母转换成大写字母
    {
    for( size_t i=0; i if( ‘a’<=str[i] && str[i]<=‘z’ )
    str[i] -= (‘a’-‘A’ );
    }
    char str[] = “aBcDe”;
    cout << "str字符长度为: " << sizeof(str)/sizeof(str[0]) << endl;
    UpperCase( str );
    cout << str << endl;
    答:函数内的sizeof有问题。根据语法,sizeof如用于数组,只能测出静态数组的大小,无法检测动态分配的或外****部数组大小。函数外的str是一个静态定义的数组,因此其大小为6,函数内的str实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因此sizeof作用于上只将其当指针看,一个指针为4个字节,因此返回4。(数组在函数调用里面退化成对应类型的指针)

你可能感兴趣的:(C语言篇)