C入门系列:第五章 数据存储类别和内存管理

    xiaoxiao2023-12-02  148

    C入门系列:第一章 基本类型

    C入门系列:第二章 字符串

    C入门系列:第三章 函数

    C入门系列:第四章 数组和指针

    C入门系列:第五章 数据存储类别和内存管理

    C入门系列:第六章 文件输入/输出

    C入门系列:第七章 结构和其他数据形式

    C入门系列:第八章 C预处理器和C库

    文章目录

    1 static2 extern3 register4 extern、static使用函数5 内存分配:malloc()和free()6 calloc()函数7 const8 volatile9 restrict

    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);
    最新回复(0)