YeeKal

c2

YeeKal
"#"

存储类,链接,内存管理

存储类

作用域

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'可以被当作不是在运行时执行的语句,只是告诉编译器它的作用域在这个函数块里。

外部链接的静态变量

  1. 定义外部变量省略'extern'

  2. 若引用在其他文件定义的外部变量,则本文件中必须加关键字'extern'

extern的存在标志着这是一个引用声明,而非定义变量

  1. 若在main函数中不加关键字地声明一个与全局变量同名地变量,则该变量将覆盖全局变量

  2. 外部变量若不作初始化则被赋值为0

  3. 外部变量已用表达式初始化但只限于常量表达式,即表达式里没有变量

函数存储类

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 *ptasjtu,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", &current->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

?null与0的区别