Storage
存储类别,链接,内存管理
存储类别
作用域
块作用域:其实就是花括号(在 C99 之前确实就是这样)
for 循环,while 循环,do while 循环,if 语句所用值得代码,及时没有花括号,也算作用域的一部分
#include<stdio.h>
int main()
{
for(int i=0; i<1;i++)
printf("%d",i);
}只有在变长数组中,形参名才有用:
void use_a_VLA(int n, int m, ar[n][m]);在 main 外边的变量,作用域是这个文件
链接
#include <stdio.h>
int giants = 5; // 文件作用域,外部链接
static int dodgers = 3; // 文件作用域,内部链接
int main()
{
return 0;
}存储期
静态存储期:程序执行是一直存在——文件作用域
线程存储期:以__Thread_local声明一个独享,每个线程都获得改变量的私有备份
自动存储期:块作用域
动态分配存储期:malloc
自动
自动
块
无
块内
寄存器
自动
块
无
块内, 使用关键字 register
静态外部链接
静态
文件
外部
所有函数外
静态内部链接
静态
文件
内部
所有函数外, 使用关键字 static
静态无链接
静态
块
无
块内, 使用关键字 static
自动变量
可以显示的写:auto。(最好不要用 auto,因为和 C++不统一)。
我们可以实现 rust 中的“遮蔽”,C 里边叫“隐藏”
寄存器变量
可以显示的写:register。(程序会尝试把内容存在寄存器,但不保证一定能存到,可能会被降级成普通)
register int quick;
块作用域的静态变量
可以显示的写:static。(证明了本文件可访问的全局变量)而且只被初始化一次。
外部链接的静态变量
使用外部的变量:extern。
如果用本文件内的全局变量,可以选择的写 extern
如果用别的文件的全局变量,必须要写 extern
不要用 extern 来创建新的变量,他是用来引用别的变量的
注意,初始化不可以用变量
#include<stdio.h>
int x = 10; // 可以
int x2 = 2*x; // 不可以
int x3 = 2*10; // 可以
int main(){return 0;}内部链接的静态变量
略
多文件
略
存储类别说明符
总结一下以上内容,一共六个关键字:
auto
register
static
extern
_Thread_local
typedef
只有 _Thread_local可以和 static 火化 extern 一起使用,其他的都只能单独使用。
存储类别和函数
函数也有存储类别
double gamma(double);
// 外部函数:本文件可调用,别的文件不能调用它
static double beta(int, int);
// 内部函数:本文件可以调用,别的文件不能调用它
extern double delta(double, int);
// 调用别的文件的函数,要这样先声明一下存储类别的选择
外部存储类别方便但不安全,请不要什么都用外部存储类别。
随机数函数和静态变量
种子“next”是具有内部链接的静态变量,rand0 函数是具有外部链接的函数,可以被别的文件调用
/* rand0.c –– produces random numbers */
/* uses ANSI C portable algorithm */
static unsigned long int next = 1; /* the seed */
unsigned int rand0(void)
{
/* magic formula to generate pseudorandom number */
next = next * 1103515245 + 12345;
return (unsigned int) (next/65536) % 32768;
}/* r_drive0.c -- test the rand0() function */
/* compile with rand0.c */
#include <stdio.h>
extern unsigned int rand0(void);
int main(void)
{
int count;
for (count = 0; count < 5; count++)
printf("%d\n", rand0());
return 0;
}
// (base) kimshan@MacBook-Pro Ch12 % gcc rand0.c r_drive0.c -o a
// (base) kimshan@MacBook-Pro Ch12 % ./a
// 16838
// 5758
// 10113
// 17515
// 31051我们可以发现,种子是固定的,每次都是从16838这里开始,我们进一步写一个更新 seed 的函数
/* s_and_r.c -- file for rand1() and srand1() */
/* uses ANSI C portable algorithm */
static unsigned long int next = 1; /* the seed */
int rand1(void)
{
/* magic formula to generate pseudorandom number */
next = next * 1103515245 + 12345;
return (unsigned int) (next/65536) % 32768;
}
void srand1(unsigned int seed)
{
next = seed;
}
/* r_drive1.c -- test rand1() and srand1() */
/* compile with s_and_r.c */
#include <stdio.h>
#include <stdlib.h>
extern void srand1(unsigned int x);
extern int rand1(void);
int main(void)
{
int count;
unsigned seed;
printf("Please enter your choice for seed.\n");
while (scanf("%u", &seed) == 1)
{
srand1(seed); /* reset seed */
for (count = 0; count < 5; count++)
printf("%d\n", rand1());
printf("Please enter next seed (q to quit):\n");
}
printf("Done\n");
return 0;
}
// (base) kimshan@MacBook-Pro Ch12 % gcc s_and_r.c r_drive1.c -o b
// (base) kimshan@MacBook-Pro Ch12 % ./b
// Please enter your choice for seed.
// 100
// 12662
// 23392
// 22561
// 20718
// 6314
// Please enter next seed (q to quit):
// 200
// 25325
// 25316
// 2367
// 19320
// 9131
// Please enter next seed (q to quit):
// q
// Done
```malloc 和 free
double *p = (double *)malloc(30*sizeof(double));注意是 double *,它要指向 double,而不是指向 30 个大小的 double!
if(p==NULL)
{
puts("Memory out!");
exit(EXIT_FAILURE);
}记得要 free
free(p);也可以用 calloc
double *q = (double *)malloc(30, sizeof(double)); // 就一点区别ANSI C 类型限定符
const
幂等性
const const const int n=6;等同于
const int n=6;所以我们可以这么写
typedef const int zip;
const zip q=8;指针与 const
#include <stdio.h>
int main()
{
{ // const 在 * 左边
double d1 = 100.0;
double d2 = 100.0;
const double *p1 = &d1; // 限定的是double 是 const
// double const *p1 = &d1; // 一样
p1 = &d2; // 可以,指针可变
// *p1 = d2; // 不行, 值不能变
}
{ // const 在 * 右边
double d1 = 100.0;
double d2 = 100.0;
double *const p1 = &d1; // 限定的是double 是 const
// p1 = &d2; // 不行,指针不能变
*p1 = d2; // 可以, 值可以变
}
return 0;
}全局变量很危险,所以使用 const 限制它会很好!
volatile
volatile 和 const 语法一样,volatile 用于给编译器优化用。比如一个地址存的是当前的时钟时间,需要不停的改变。
restrict (C99)
_Atomic (C11)
并发中的原子性。一个进程访问他时,别的进程不能访问。
最后更新于
这有帮助吗?