c2
存储类,链接,内存管理
存储类
作用域
block scope: 代码块作用域
 c99允许在代码块中变量使用之前的任何位置声明变量;'for(int i=0;;)'
function prototype scope: 函数原型作用域
files cope: 文件作用域,全局变量
链接
 external linkage || internal linkage || no linkage
 block scope 和function prototype scope只有空链接;file scope默认外部链接,即可以被其他文件使用;若全局变量由static关键字声明则该变量是该文件私有变量,不能被其它文件使用。
存储时期
static storage duration, 静态存储时期
automatic storage duration, 动态存储时期
file scope: 静态存储时期;
block scope:动态存储时期,即程序进入定义这些变量的代码块时将为变量分配内存,退出代码块则内存释放;
存储类
| 存储类 | 时期 | 作用域 | 链接 | 声明 | 
|---|---|---|---|---|
| 自动 | 自动 | block | 空 | auto,可省略 | 
| 寄存器 | 自动 | block | 空 | register | 
| 外部链接静态 | 静态 | file | 外部 | —— | 
| 内部链接静态 | 静态 | file | 内部 | static | 
| 空连接静态 | 静态 | block | 空 | static | 
自动变量
- 相同变量名:内部定义覆盖外部定义
寄存器变量
- 获得较快的访问速度
- 不能再使用地址运算符
代码块作用域的静态变量
void trystat(void)
  {
    int fade=1;
    static int stay=1;
  printf("fade=%d and stay=%d",fade++,stay++);
  }
//循环运行后fade每次都会初始化,而stay只初始化一次。
//对于函数内部'static int stay=1'可以被当作不是在运行时执行的语句,只是告诉编译器它的作用域在这个函数块里。
外部链接的静态变量
- 
定义外部变量省略'extern' 
- 
若引用在其他文件定义的外部变量,则本文件中必须加关键字'extern' 
extern的存在标志着这是一个引用声明,而非定义变量
- 
若在main函数中不加关键字地声明一个与全局变量同名地变量,则该变量将覆盖全局变量 
- 
外部变量若不作初始化则被赋值为0 
- 
外部变量已用表达式初始化但只限于常量表达式,即表达式里没有变量 
函数存储类
static声明使函数私有,不能被外部访问
extern可省略
随机数函数和静态变量
//o-version rand
static unsigned long int next = 1;
int rand0(void) {
    next = next * 1103515245 + 12345;
    return (unsigned int)(next / 65536) % 32768;
}
//这解释了为什么每次运行结果都是一样的,因为next初始值是固定的
//解决的方案是产生“新种子”,这也是next声明为静态的原因
//1-version rand
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;
}
标准库
#include<stdlib.h>
#include<time.h>
int main(){
  srand((unsigned int)time(NULL));
  for (int i=0; i<10; i++)
  {
    printf("%d ", rand()%10);
  }
}
// 要取[a,b)之间的随机整数(包括a,但不包括b),使用:
     (rand() % (b - a)) + a
分配内存
 标准存储类自动决定作用域和存储时期。更灵活的指定内存管理规则则使用库函数:'malloc()''free()';
 malloc指定的内存是匿名的,返回指向void的指针,如此方便将返回值(首地址)赋值给一个相对应的指针变量进行内存管理。
#include<stdlib.h>
double *ptr;
ptr=(double *)malloc(10*sizeof(double));
//与数组名作为首地址指针由相似的功能
//指定可变数组
int n;
ptr=(double *)malloc(n*sizeof(double));//legal
free(ptr);
//对应一个malloc()调用,应该调用一次free();free参数是先前malloc返回的地址。一般在程序终止后,内存会自动释放,故调用此函数不是必须的。但建议。
if(ptr==NULL){
  exit(EXIT_FAILURE);
}
//若malloc无法返回所需数量内存则返回空指针
//EXIT_FAILURE指示程序异常终止
//EXIT_SUCCESS类似于0,指示正常终止。
long *newmen;
newmen=(long *)calloc(30,sizeof(double));
//calloc将全部位置0
以下的两种方法都可以建立动态的二维空间数组。
方法一:
int i,j;
int r,c;
int **a;  //创建二维指针来指向数组
scanf("%d%d",&r,&c);
a  = (int **) malloc(sizeof(int *) * r);//注意申请的指针格式
for (j=0;j<r;j++){
a[j] = (int *) malloc(sizeof(int) * c);
……
……
} 
释放为:
for (j=0;j<r;j++)
 free(a[j]);//先释放一维指针
 free(a);//最后释放我二维指针 
类型限定词
const
 变量声明中带有const,则不能改变变量的值。
//指针
const float *ptr;//ptr指向常量,数据不可变
float * const ptr;//常量指针,指向同一地址,但地址中数据可变
const float * const prt;//地址数据都不可变
float const *ptr;//==const float *ptr
//多用在函数参数中
void dispay(const int array[]);
void dispay(const int * array);//则数组指向的数据不可变
//全局数据使用const
//在一个文件中定义
const double PI=3.1415;
//另一个文件引用
extern const double PI;
//包含头文件的方法
//无需重复声明。但是每一个文件都对其进行了一次数据备份
volatile
该变量除了可被程序改变以外还可以被其他代理改变
多个关键字的顺序不重要
restrict
int *restrict ptr=(int *)malloc(10*sizeof(int));
//只能用于指针
//表示该指针是访问该数据的唯一入口,以方便编译器优化代码
//可以作为指针形函数参量的限定词,如此假定函数体内没有其它标识符修改指针指向的数据
文件读写
何为文件
文本视图/二进制视图
读写
FILE *ptr;
char ch;
ptr=fopen(,"r");//失败返回空指针NULL
fclose(ptr);//成功返回0,失败返回EOF
//写入文件
ch=getc(ptr);//
putc(ptw,ch);
if ((ptw = fopen(fileW, "w"))==NULL) {
        printf("fail to open %s", fileW);
        exit(3);
    }
while (ch=getc(ptr) != EOF) {
  putc(ch,ptw);
}
文件打开模式
| “r”,"w" | 只读/只写,不存在创建,存在删除原内容 | 
|---|---|
| “a” | 追加内容,不存在则创建 | 
| “r+” | 可读可写 | 
| “w+” | 可读可写,破环式 | 
| “a+” | 可读可写,最佳式,不存在创建,存在追加 | 
| “wb”,"rb","ab" | 二进制 | 
| "ab+"=="ab+" | 二进制 | 
fprintf/scanf/fgets/fputs
fprintf()/fscanf()
/*file.c    */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
    FILE * pta;
    char words[40];
  //create file
    if ((pta = fopen("addword.txt", "a+")) == NULL) {
        fprintf(stdout, "cna't open this file\n");
        exit(1);
    }
    //write
    puts("enter some words and a blank line to end:");
    while (gets(words) != NULL && words[0] != '\0') {
        fprintf(pta, "%s\n", words);//第一个参数
    }
    rewind(pta);//移动指针
    puts("file contents:");
    while (fscanf(pta,"%s", words) == 1) {
        printf("%s\n", words);//fscanf 第一个参数
    }
    //close
    if (fclose(pta) != 0) {
        puts("fail to close this file!");
    }
    return 0;
}
fgets()/fputs()
fgets(buf,Max,pta);//若有空余,则添加换行符
                    //遇结尾,返回eof
fputs(buf,pta);     //不添加换行符
while(fgets(line,Maxline,stdin)!=NULL && line[0]!='\n'){
  fputs(line,stdout);
}
随机存取
fseek()/ftell()
fseek(pta,0L,SEEK_END);//正常返回值0
fseek(pta,10L,SEEK_SET);//文件第10个字符
fseek(pta,2L,SEEK_CUR);//当前位置向前移动两个字节
fseek(pta,-10L,SEEK_END);//文件末尾回退10个字节
long last;
last=ftell(pta);//long 类型,返回据文件开始处字节
fgetpos()/fsetpos()
int fgetpos(FILE *restrict stream,fpos_t * restrict pos);
/*success->0; fail->not 0*/
int fsetpos(FILE *stream,const fpos_t *pos);
结构体
结构体
//声明,在main前
struct book {
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};  //struct definition end and 注意双引号
//definition
struct book sjtu,asee,*pta;//definition
struct book {
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
} sjtu; //在声明之后直接定义
//初始化
struct book sjtu={
  "love",
  "Charles",
  12.34
};
//指定初始化
struct book sjtu={
  .title="love"
}
结构数组
struct book sjtu[100];
sjtu[2].value;//访问成员
指向结构的指针
struct book *pta,sjtu,lib[10];
pta=&sjtu;  //与数组不同,结构体的名字不是该结构的地址
pta=&lib[0];
//pta+1:则pta指向lib[1]
//访问成员
pta->.title;  //is sjtu.title if pta =&sjtu
        //新的运算符
(*pta).title;//必须带圆括号,‘.’比‘*’运算级高
结构体作函数参数
int add(int ,int);
add(sjtu.num,situ.value);//函数不关心是否是结构体成员,只要参数类型符合
//结构地址
double sum(const struct funds *);
sum(&sjtu);
//结构作为返回值
struct book makeinfo(struct book sjtu);
字符指针和内存动态分配
struct name{
  char *fname;
  char *lname;
  int letters;
}
void getinfo(struct name *pst){
  char temp[8];
  puts("enter your first name:");
  gets(temp);
  pst->fname=(char *)malloc(strlen(temp)+1);
  strcpy(pst->fname,temp);
  /*
  两个字符串被保存在由malloc管理的内存中,结构体中只存放了地址
  */
  ...
}
//do not forget free them
void cleanup(struct name *pst){
  free(pst->fname);
  free(pst->lname);
}
复合文字和结构体
(struct book){"love","charles",2.33}
伸缩型数组成员
- 伸缩型数组成员必须是最后一个数组成员
- 结构中必须有一个其它成员
struct flex{
  int count;
  double average;
  double scores[];//vla
}
struct flex *pf1,*pf2;
//分配空间
pf1=malloc(sizeof(struct flex)+5*sizeof(double));
pf1=malloc(sizeof(struct flex)+9*sizeof(double));
free(pf1);
free(pf2);
结构内容保存到文件
fread(&sjtu[count], size, 1, pb)
fwrite(&sjtu[filecount], size, count - filecount, pb);//写入多个,是开始地址位
高级数据处理
联合
枚举
enmerated type
enum spextrum{red,orange,yellow,green,blue,violet};//definition
enum spectrum color;//create entity
//访问
int c;
color=blue;
if(color==blue){}
for(color=red;color<=violet;color++){}//枚举常量是int型
//enum常量默认按序列0,1,2……赋值
enum levels{low=1000,medium=2000,high=3000};
typedef
位操作
二进制
字节位
一个字节(byte)8位(bit)。从左到右字节为标识为7-0.其中位7为高位(high-order-bit),0位为低位(low-order-bit)。
补码(two's-complement)
正0负1,取反加1.
二进制小数
位运算符
逻辑运算符
~;  //取反
|;  //或
&;  //与 
^;  //异或
//赋值运算符
~=;
|=;
&=;
^=;
&   //掩码,打开通道
|   //打开位,其它位不变
&= ~//关闭位
^   //转置位
//查看
if((flag & mask)==mask)
移位运算符
(10001010) << 2//左移个数由右操作数决定,移入位由0补充
  stonk =stonk<<2;
stonk<<=2;//乘以2的n次幂
sweet>>3;//右移。除以2的n次幂
位字段
struct box{
  unsigned int opaque   :1;
  unsigned int  fill_color:3;
  unsigned int          :4;
  unsigned int show_border :1
};
预处理器
#define
符号常量
macro: 宏
Object-like macro: 类对象宏
macro expansion: 宏展开
预处理器发现程序中的宏后,用它的等价文本展开。若字符串中仍包括宏,则继续展开。例外情况是双引号中的宏。
语言符号,token.
使用参数
function-like macro
macro only replace text instead of calculating.
#define addnum(x) x*x
#define adddnum(x) (x)*(x)
//'#'创建字符串
#define psqr(x) printf("the square of "#x" is %d.\n",((x)*(x)))
//'##'粘合操作
#define XNAME(n) x ##n
//用圆括号括住每一恶搞参数,并括住宏的整体定义以保证正确分组
可变宏
#define PR(...) printf(__VA_ARGS__)
//省略号只能代替最后的宏参数
#include
格式
#include 
#include"hot.H" 当前工作目录搜索
更多指令
#undef LIMIT //delete macro
//conditional def
#ifdef MAVIS
    #include "horse.h"
#else
    #include"cow.h"
#endif
#ifndef SIZE   //是否为未定义的
#if
#elif
#else
#endif
预定义宏
| macro | mean | 
|---|---|
| __FILE__ | file name | 
| __DATE__\__TIME__ | date/time | 
inline function
inline double square(int a){
}
c库
math.h
stdlib.h
通用工具库
atexit();//以函数名,即函数指针作为参数,先进后出
exit();//0成功终止
链表
create linkeed list
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define TSIZE 45
struct film {
    char title[TSIZE];
    int rating;
    struct film *next;
};
int main() {
    struct film *head = NULL;
    struct film * prev, *current;
    char input[TSIZE];
    /*add list*/
    puts("enter first move title:");
    while (gets(input) != NULL && input[0] != '\0') {
        current = (struct film *) malloc(sizeof(struct film));
        if (head == NULL)
            head = current;
        else
            prev->next = current;
        current->next = NULL;
        strcpy(current->title, input);
        puts("enter the rating:<0-10>");
        scanf("%d", ¤t->rating);
        while (getchar() != '\n')
            continue;
        puts("enter next movie title:");
        prev = current;
    }
    /*display list*/
    if (head == NULL)
        printf("No data entered!");
    else
        printf("Here is the movie list:\n");
    current = head;
    while (current != NULL) {
        printf("Movie:%s Rating: %d\n", current->title, current->rating);
        current = current->next;
    }
    current = head;
    while (current != NULL) {
        head = current->next;
        free(current);
        //内存释放之后,结构信息也不存在,故先用head保存next属性值
        current = head;
    }
    printf("\nBye\n");
    return 0;
}
ADT
构造接口
二叉搜索树
binary search tree