全局变量
即定义在所有函数之外(一般都定义在main函数之前,#include头文件下边)的变量,这个是与局部变量(本地变量)所不同的,它可以在任何函数中使用
下面举个例子
例1:
# include <stdio.h>
int i;
int * p;
int main(void) {
printf("全局变量 i 的值为%d\n", i);
printf("全局变量 p 的值为%s\n", p);
return 0;
}
输出结果为:
没有初始化的全局变量会被赋予0这个值,如果是指针,会被赋予NULL,这点通过上面程序的结果即可发现;对全局变量进行初始化时,最好直接用编译时刻已知的值(即数字或常变量等),但最好只是用数字而不要使用其他方法
它的初始化发生在main函数之前
如果在函数内部有变量与全局变量名相同,则在该函数中,全局变量会被覆盖
例2:
# include <stdio.h>
int i;
//int * p;
void f();
int main(void) {
i = 9;
printf("在%s函数中 i 的值为%d\n", __func__, i);
// printf("全局变量 p 的值为%s\n", p);
f();
return 0;
}
void f() {
int i = 3;
printf("在%s函数中 i 的值为%d\n", __func__, i);
}
输出结果为:
由上结果可以证明
另外,通过上面的例子可以发现,在printf中放一个 %s ,而再输出的后面,对应的加一个__func__,则会输出该语句所在的函数的名字
上面的例子是在局部函数中定义相同变量名,覆盖了全局变量,下面举个全局变量的使用范围例子
例3:
# include <stdio.h>
int i;
//int * p;
void k();
void f();
int main(void) {
i = 9;
printf("在%s函数中 i 的值为%d\n", __func__, i);
// printf("全局变量 p 的值为%s\n", p);
f();
printf("在%s函数中 i 的值为%d\n", __func__, i);
return 0;
}
void f() {
// int i = 3;
printf("在%s函数中 i 的值为%d\n", __func__, i);
k();
printf("在%s函数中 i 的值为%d\n", __func__, i);
}
void k() {
i = 1000;
printf("在%s函数中 i 的值为%d\n", __func__, i);
}
输出结果为:
静态局部变量
就是在定义局部变量时在其类型前边加上static修饰符
当函数离开时,静态局部变量会继续存在(不会被释放内存)并保持其值
静态局部变量的初始化只会在第一次进入这个函数时做,以后进入此函数时会保持上次离开的值
举例说明
例4:
# include <stdio.h>
int i;
//int * p;
void f(int);
int main(void) {
i = 9;
printf("在%s函数中 i 的值为%d\n", __func__, i);
// printf("全局变量 p 的值为%s\n", p);
f(i);
i += 1;
printf("在%s函数中,改变后的 i 的值为%d\n", __func__, i);
f(i);
return 0;
}
void f(int t) {
static int s = t;
printf("在%s函数中 s 的值为%d\n", __func__, s);
}
输出结果为:
由上可以发现,第一次i的值为9时,将其传入f函数中,赋值给static int 变量s,输出s的值也为9,而当i的值改变为10时,再次传入f函数,将其值赋给s,但输出的s的值仍为9
下面再试一下,看静态变量、全局变量和局部变量分配的内存的地址在哪儿
例5:
# include <stdio.h>
int i;
//int * p;
void f(int);
int main(void) {
i = 9;
printf("在%s函数中 i 的值为%d\n", __func__, i);
// printf("全局变量 p 的值为%s\n", p);
f(i);
i += 1;
printf("在%s函数中,改变后的 i 的值为%d\n", __func__, i);
f(i);
return 0;
}
void f(int t) {
int j = 0;
static int s = t;
printf("全局变量i的地址为: &i = %p\n", &i);
printf("局部静态变量的s地址为: &s = %p\n", &s);
printf("局部变量j的地址为: &j = %p\n", &j);
printf("在%s函数中 s 的值为%d\n", __func__, s);
}
输出结果为:
由上面的结果可以发现,局部静态变量的地址有很大差距,而它反而和全局变量分配的内存的地址相近,说明静态局部变量实际上是特殊的全局变量,而且它们位于相同的内存区域,static在这里是局部作用域的意思,即其函数内部可访问
宏
以#开头的是编译预处理指令,它不是C语言的语句,但它是不可或缺的
#define是定义了一个宏,下面给出格式:
#define 名字 值
这三者之间只有两个空格,值的后边没有空格,不要加,不然很可能出错
注意,结尾是没有分号的,因为它不是语句,名字必须是单词或字母,值可以随意(数字表达式皆可)
它是在编译器进行编译之前被处理的
下面举个例子
例6:
# include <stdio.h>
# define N 5
int main(void) {
int a = 10;
printf("a*N=%d\n", a * N);
return 0;
}
输出结果为:
由上可知,N的值为5,宏就是这样,通过#define,让N与5等价,即在下面的程序中凡是出现N的地方,可以将它替换成5,这样做,是为了在写较大的程序时,使用一些数字,或许可能遗忘数字的含义,所以起一个名字替换该数字,而且,要是多次用到该数字,如果想改,需要在代码中一个个的找到,然后修改,使用宏以后,只需在程序最前边修改一次即可(注:宏定义一般是大写的字母或单词)
如果一个宏的值中有其它的宏,已久会被替换
如果一个宏的值超过一行,最后需要加\
宏后面出现的注释不会被替换
宏不单单可以定义数字,也可以定义表达式,但定义表达式时需要注意一点,首先举个例子
例7:
# include <stdio.h>
# define S "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
ssssssssssssssssssssss" //这是定义一个字符串,没什么用,只为举例 说明
# define M 3
# define N 2
# define Q M+N //这几个宏的值没什么用,只为举例说明
int main(void) {
int a = 10;
printf("Q=%d\n", Q);
printf("Q*Q=%d\n", Q*Q);
printf("S=%s\n", S);
return 0;
}
输出结果为:
请看下面的输出结果,Q*Q按说应该是5*5=25,但结果却是11?这是因为,它是这么算的Q=M+N,则Q*Q=M+N*M+N,即3+2*3+2,结果为11,要向达到预期效果,定义第三个宏时后面需要加括号
当然,这只是个简单的例子,实际上可以进一步的延伸,这里就不多说了
除了自己定义宏之外,还有一些预定义宏(不需要我们再定义了),如:__FILE__,__LINE__,__DATE__,__TIME__ (注意:它们的两边都是两个下划线 _ )
这些都是什么意思呢?
举个例子
例8:
# include <stdio.h>
int main(void) {
printf("__FILE__是:%s\n", __FILE__);
printf("__LINE__是:%d\n", __LINE__);
printf("__DATE__是:%s\n", __DATE__);
printf("__TIME__是:%s\n", __TIME__);
return 0;
}
输出结果为:
由结果可推测一下(其实第二个也未必能猜出),第一个是源程序文件的路径
第二个是该行代码所在的行号,第三个是输出日期,第四个是输出当前时间
其实,还可以定义带参数的宏,这个用起来也有点儿像函数
带参数的宏一定要加括号,整个值也要加括号,每个参数出现的地方都要加括号
例:9
# include <stdio.h>
# define max(a,b) (a>b?a:b) //后边是表达式的话,最好带着括号
int main(void) {
int i = 4, j = 7; //仅仅是举例
printf("较大的数为:%d\n", max(i,j));
return 0;
}
输出结果为:
这是个带参数的宏,它的后边是一个三目运算符,表示a和b两个值中的较大的数,看printf中的max(i,j),是不是像个函数调用?其实这里功能一样
【所有代码均在windows系统下dev c++下运行通过】
(如有错误,敬请指正)