变量
全局变量与静态变量
相同点
总的来说,它们的相同点是都保留在静态存储区,生命期与程序生命期相同。
不同点
-
总的来说,它们的不同点是,全局变量具有全局作用域,静态变量具有文件作用域。 -
静态局部变量具有局部作用域,只被初始化一次,自从第一次被初始化,直到程序运行结束都一直存在。它和全局变量的区别在于,全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见 -
静态全局变量也具有全局作用域,它与全局变量的区别在于,如果程序包含多个文件,它作用于定义它的文件里,不能作用到其他文件里,即被static关键字修饰过的变量具有文件作用于这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量 -
把局部变量改变为静态变量后是改变了它的存储方式,即改变了它的生存期;把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围
局部变量与全局变量
局部变量可以与全局变量重名,但是局部变量会屏蔽全局变量。要使用全局变量,需要使用操作符::
对于有些编译器,在同一个函数体内可以定义多个同名的局部变量。例如,在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内
全局变量与局部变量的区别:
-
全局变量的作用域为程序块,而局部变量的作用域为当前函数 -
内存存储方式不同,全局变量分配在全局数据区,后者分配在栈区 -
生命周期不同。全局变量随主程序创建而创建,随主程序销毁而销毁,局部变量在局部函数内部,甚至局部循环体等内部存在,退出就不存在了 -
使用方式不同。通过声明为全局变量,程序的各个部分都可以用到,而局部变量只能在局部使用
但是,局部变量不可以赋值为同名的全局变量,例如:
#include <stdio.h>
int i = 1;
int main()
{
int i = i;
printf("%d\n", i);
return 0;
}
程序的输出结果为:
-858993460
上述代码合法,有的编译器编译也能通过,但是不合理。int i = i ,i 变量从声明那一刻开始就是可见的,main() 函数里的i不是i ,因为它和main() 函数外的i无关,而是一个未定义的值,所以输出就是一个随机值了
一些复杂的变量声明
-
一个有10个指针的数组,数组中指针指向一个整型数。int *a[10]; -
一个指向有10个整型数数组的指针。int (*a)[10]; -
一个指向函数的指针,该函数有一个整型参数并返回一个整数。int (*a)(int); -
一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数。int (*a[10])(int);
在C语言中,每个变量声明都由两个部分组成:一个类型和一组具有特定格式的,期望用来对该类型求值的表达式。例如,float *g(), (*h)() ,该语句表示*g() 和(*h)() 都是float 表达式。由于() 比* 优先级更高,绑定的更紧密,所以*g() 与*(g()) 表示的意义相同,即g 是一个返回float 指针的函数,而h是一个指向返回float 的函数的指针
还有一些更复杂的声明方式:
-
(*(void(*)())0)() 该声明表示硬件会调用地址为0处的子程序,但如果写成是(*0)() 并不符合要求,因为* 运算要求必须有一个指针作为它的操作数,而不能是数字。而且,这个操作数必须是一个指向函数的指针,以保证* 的结果可以被调用,所以此时需要将0转换为一个可以描述“指向一个返回void 的函数的指针”的类型,即(void(*)())0 -
void *(*(*fp1)(int))[10]; 可以分解为如下两个表达式: 1)p = (*fp1)(int) 2)void *(*p)[10] 第一个表达式中,fp1 是一个函数的指针,这个函数的参数为int ,函数的返回值为p ;第二个表达式中,p 是一个指向有10个元素的数组的指针,这个数组中元素的类型为void* (指向void 指针)。综上,fp1 是一个函数的指针,它指向的函数有一个int 参数,这个函数的返回值是一个指针,这个指针指向一个有10个元素的数组,而且数组中每个元素都是void* -
float (*(*fp2)(int, int, int))(int); 可以分解为如下两个表达式: 1)p = (*fp2)(int, int, int) 2)float (*p)(int) 第一个表达式中,fp2 是一个指针,这个指针指向一个函数,这个函数有3个int 类型的参数,这个函数的返回值为p ;第二个表达式中,p 也是一个指针,指向一个函数,并且这个函数的参数为int ,返回值为float 。综上,fp2 是一个指向函数的指针,函数有3个int 类型的参数,函数的返回值是一个函数的指针(这个函数的参数为int ,返回值为float )
C语言中各种变量默认初始值
全局变量放在内存的全局数据区,由编译器建立,如果在定义的时候不做初始化,则系统将自动为其初始化,数值型为0,字符型为NULL ,指针变量也被赋值为NULL 。静态变量的情况与全局变量类似。而非静态局部变量如果不显式初始化,那么其内容是不可预料的,将是随机数,会很危险,对系统造成非常大的安全隐患
类型转换
在C/C++中,常用的数据类型有char 、uchar 、short 、ushort 、int 、uint 、long 、ulong 、float 和double 。这些数据类型所能表示的范围也是不同的。那么当这些不同的数据类型参与运算的时候,就带来了类型转换问题。
算术运算过程中的类型转换
当参与运算的表达式中有不同的数据类型时,在运算的时候会进行类型隐式转化,遵循以下规则:
-
整数提升。如果参与运算的表达式中没有比int更高的类型,那么,运算的表达式都会隐式转换为int,然后进行运算 -
类型对齐。把所有参与运算的表达式隐式转换为占用空间最大的数据类型 -
当无符号数与有符号数类型进行混合运算时,有符号数会隐式转换为无符号数
综上,类型隐式转换的规则如下:
(char, uchar, short, ushort)-->int->uint-->long-->ulong-->float-->double
赋值运算过程中的类型转换
-
普通的两个变量赋值,以左值为准 -
函数参数的传递,其实也就是把实参的值赋给形参,以形参的类型为准 -
赋值运算,其实就是将函数运算的结果赋值给返回值,以返回值类型为准
|