文章目录
1 static
与java相反,static声明的变量或函数只能在当前文件使用
// 这种声明的变量可以在程序的其他文件引用
int giants = 5;
// static声明的变量只能在当前文件的函数使用
static int dodgers = 3;
#include<stdio.h>
void tryStat(void); // 在java中这种函数默认是public公开
#extern void tryState(void); // 与void tryState(void)相同
#static void tryStat(void); // 只能在当前文件使用,即其他文件可以声明同名的函数
int main(void) {
int count;
for (count = 1; count <= 3; count++) {
tryState();
}
return 0;
}
void tryStat(void) {
int fade = 1;
static int stay = 1;
printf("fade = %d and stay = %d\n", fade++, stay++);
}
输出结果:
fade = 1 and stay = 1
fade = 1 and stay = 2
fade = 1 and stay = 3
2 extern
C语言的一般做法是:在文件定义初始化声明变量,在其他文件使用 extern
关键字引用文件定义的变量
// 外部变量,Coal被定义在另一个文件,要放在所有函数外
extern char Coal;
// C语言是顺序执行的,所以要注意变量的声明位置
// 如果变量Hocus声明在main()后面,则main()函数将无法识别
int Hocus;
int magic();
int main(void) {
extern int Hocus; // 与上面的Hocus是等价的
}
int magic() {
extern int Hocus; // 与函数外的Hocus等价
}
// 用extern声明的变量不会分配内存空间
// 且只能初始化一次,即在file_one.c初始化了pemis,就不能在另外的文件再初始化该变量
file_one.c
char permis = 'N';
file_two.c
extern char permis;
3 register
使用 register
关键字可声明寄存器变量。一般变量都存储在内存中,寄存器变量存储在CPU寄存器中,访问寄存器变量速度更快,但无法获得寄存器变量地址;且寄存器变量只处理某些类型,例如处理器中的寄存器可能没有足够大的空间来存储double类型的值。
int main(void) {
// 编译器不一定会将变量识别为寄存器变量
// 如果忽略识别,则会认为是一个普通变量
register int quik;
}
// 形参声明为寄存器变量
void macho(register int n)
4 extern、static使用函数
s_and_r.c
static unsigned long int next = 1;
int rand1(void) {
next = next * 1103515245 + 12345;
return (unsigned int) (next / 65536) % 32768;
}
void srand1(unsigned int seed) {
next = seed;
}
r_drive1.c
#include<stdio.h>
#include<stdlib.h>
extern void srand1(unsigned int x);
extern void rand1(void);
int main(void) {
int count;
unsigned seed;
printf("Please enter your choice for seed");
while (scanf("%u", &seed) == 1) {
srand1(seed); // 重置next数值
for (count = 0; count < 5; count++)
printf("%d\n", rand1());
}
}
5 内存分配:malloc()和free()
malloc()
函数能分配内存,该函数会找到合适的空闲内存块,这样的内存的匿名的,接收一个参数:所需的内存字节数;
返回分配内存块的首地址,即可以把该地址赋给一个指针变量,并使用指针访问这块内存,ANSI之前返回char指针,从ANSI C标准开始返回一个指向void指针,可以强转类型,如果malloc()分配内存失败,返回空指针。
free()
函数与 malloc()
配套使用释放内存,free()函数的参数是malloc()返回的地址;不能用free()释放通过其他方式(比如数组)分配的内存。
如果内存分配失败,可以调用exit()函数结束程序,EXIT_FAILURE表示程序异常终止,EXIT_SUCCESS表示程序结束。
malloc()、free()、exit()的原型和EXIT_SUCCESS、EXIT_FAILURE都在 stdlib.h
头文件中
#include<stdio.h>
#include<stdlib.h>
int main(void) {
double *ptd;
int max;
int number;
int i = 0;
puts("What is the maximun number of type double entries?");
if (scanf("%d", &max) != 1) {
puts("Number not correctly entered");
exit(EXIT_FAILURE);
}
// 分配内存失败,结束程序
ptd = (double *) malloc(max * sizeof(double));
if (ptd == NULL) {
puts("Memory allocation failed");
exit(EXIT_FAILURE);
}
// 输入max个值
puts("Enter the values(q to quit)");
while (i < max && scanf("%lf", &ptd[i]) == 1)
i++;
printf("Here are your %d entries:\n", number == i);
// 输出
for (i = 0; i < number; i++) {
printf("%7.2f", ptd[i]);
if (i % 7 == 6)
putchar('\n');
}
if (i % 7 != 0)
putchar('\n');
free(ptd);
}
输出结果:
What is the maximum number of entries?
5
Enter the values (q to quit)
20 30 35 25 40 80
Here are your 5 entries
20.00 30.00 35.00 25.00 40.00
6 calloc()函数
和malloc()类似,在ANSI之前返回指向char的指针,在ANSI之后返回指向void指针。calloc()
函数还有一个特性:它把块中的所有位都设置为0(注意,在某些硬件系统中,不是把所有位都设置为0来表示浮点值0)。也需要通过free()来释放内存
// 第1个参数:所需的存储单元数量
// 第2个参数:存储单元的大小
// 分配100个4字节的存储单元,总共400字节
long *newmem;
newmem = (long *)calloc(100, sizeof(long));
7 const
以 const
关键字声明的对象,其值不能通过赋值或递增、递减来修改。
// 编译器会报错
const int nochange;
nochange = 12;
// 正确
const int nochange = 12;
// 指针与const的位置
// const放在*左侧,表示指向的值不可变,指针地址可变,例如const float * ptr或float const * ptr
(可以简单记忆为普通的const float ptr)
// const放在*右侧,表示指向的值可变,指针地址不可变,例如float * const ptr
// ptr指向一个float类型的const的值
// ptr指向的地址的值不能改变,ptr指针可以指向其他地址
// 即*ptr不可变,ptr可变
const float * ptr;
等价于
float const * ptr;
// ptr是一个const指针
// ptr指向的地址不能改变,ptr的值可以改变
// 即ptr不可变,*ptr可变
float * const ptr;
// ptr地址和值都不可改变
const float * const ptr;
全局变量中使用const变量,在其他文件中引用
第一种方式:
file1.c
const double PI = 3.14159;
const char * MONTHS[12] = {...};
file2.c
extern const double PI;
extern const * MONTHS[];
第二种方式:
constant.h
// 必须要使用static声明全局const变量,如果去掉static,那么在file1.c中包含constant.h将导致每个文件中都有一个相同标识符的定义式声明
static const double PI = 3.14159;
static const char * MONTHS[12] = {...};
file1.c
#include "constant.h" // 在其他文件导入,在其他文件使用
8 volatile
volatile
告知计算机代理(而不是变量所在的程序)可以改变该变量的值。通常,它被用于硬件地址以及在其他程序或同时运行的线程中共享数据。(与java的volatile相同,在访问volatile变量的值会刷新,让其他线程访问变量的值相同)
9 restrict
restrict
关键字允许编译器优化某部分代码以更好地支持计算。它只能用于指针,表明该指针是访问数据对象的唯一且初始的方式。
// 指针restar是访问由malloc()所分配内存的唯一且初始的方式
int * restrict restar = (int *)malloc(10 * sizeof(int));
// 从位置s2把n字节拷贝到位置s1。memcpy()要求两个位置不重叠
// 声明s1和s2为restrict说明这两个指针都是访问相应数据的唯一方式
void * memcpy(void * restrict s1, const void * restrict s2, size_t n);