关键字
1.extern:声明外部变量,变量在其他文件中定义,当然这个变量一定要是全局变量
test.c
#include <stdio.h>
int i = 1;
int main()
{
print();
return 0;
}
print.c
#include <stdio.h>
extern int i;
void print()
{
printf("%d\n",i);
}
2.static
用static修饰全局变量时,限定了作用域,无法通过extern进行外部调用;
用static修饰局部变量时,改变了其生命周期,由原来的函数内,改变为整个程序。
Tips:我们所提及的内存其实是虚拟内存,当运行程序时,操作系统会为其分配4个G的虚拟内存空间。如下图所示:
对于非静态的局部变量,生命周期为该变量所在函数内,但对于静态的局部变量,其生命周期为整个程序结束。因为,非静态的局部变量存放在栈中,栈又是由系统管理,而静态的局部变量存放在BSS段。
堆与栈的区别:
堆是由用户管理;栈由系统管理。
3.auto:最常用也最不常见
显式定义: auto int x, y;
隐式定义:int x, y;
4.register:对于使用频繁的变量,可以使用register声明为寄存器变量,其值存放在CPU中,加快了运行速度。
例如:register int x;
regster char ch;
注意:对于register关键字,不能使用&,因为存放在CPU中,与存放内存当中不同。
预处理
指在进行第一遍扫描(词法扫描和语法分析)之前所做的工作。
命令的种类:
#define
#include
#if 0 ....#endif
宏:
#define PI 3.1415926
#define OUT printf("hello world")
宏函数的安全性较差,但节约内存,仅仅是一种替换;
#define SQR(X) X*X
a = SQR(3);
printf("%d\n", a);
结果是:a = 3 * 3
= 9
#define SQR( X ) X*X
a = SQR(2 + 1);
printf("%d\n",a);
结果是:5
原因:宏仅仅是替换,对于此题SQR(2 + 1),我们要展开来开,2 + 1 * 2 + 1,因此此题是5,但将宏稍作修改
#define SQR(X) (X)*(X)
那么输出的结果就是9了
指针
1.指针是什么?
指针是变量的一种,占4个字节,里面是一个地址,通过这个地址可以找到要找到的内容。
例如 : int *p = &a;
实质:单元的地址就是指针的内容。
2.指针的运算
* : 定义时 ,指明为指针类型
使用时,取值
& : 取地址
例如:int *p, a;
p = &a;
*p = 3;
3.指针作函数参数
函数的参数不仅仅可以是整型、实型、字符型等,还可以是指针类型。
作用是:将变量的地址传送到一个函数中;
指针和变量
例如:
int x, *p, y;
x = 5;
p = &x;
y = *p + 3; // 5 + 3 = 8
y = ++*p; // *p自加1 ,y = 4
y = *p++; //y = 4, p的地址加1
思考:(*p)++ 与 *p++ 的区别?
(*p)++:对p指向的内容进行+1运算;
*p ++:先取p指向的内容,再p++,对地址进行+1操作;
注意:指针变量未赋值时,可以是任意值,是不能使用的,会造成意外错误,而指针变量被赋值为NULL值后,是可以使用的,只是不指向具体的内容。
指针和数组
1.数组元素的指针
数组的指针是指向数组的起始地址,数组元素的指针是指向数组元素的地址;
例如:
int a[10];
int *p;
p = &a[0]; //p是指向a[0]这个元素的地址
2.用指针引用数组元素
如果指针变量P已经指向数组中的一个元素,则p+1指向同一数组的下一元素;
例如: p = &a[0];
那么(p + i)和(a + i)都是a[i]的地址
*(p+i)和*(a+i)都是p+i和a+i所指向的数组元素,即a[i]。指向数组的指向变量也可以带下标,p[i]和*(p+i)是等价的。
3.引用一个数组
下标法:用a[i]来表示;
指针法:用*(a+i),*(p+i)来表示;