@

存储类说明符

C中存储类说明符共有5个,为auto register static extern typeddef,最后一个关键字typedef与内存存储无关。

规定:不可以在一个声明中使用一个以上存储类说明符。

存储类说明符用来确定变量的存储类型。

存储类和函数

函数的存储类有两种:

  • 外部
  • 静态

在一个文件中定义的函数默认是外部的,也就是说其他文件可以调用它,只有使用static关键字修饰的函数才是函数定义所在文件所私有的函数,通常用来解决不同文件函数之间的命名冲突。

double a();//默认声明,函数a是外部的
extern int b();//此处显式声明b函数是在其他文件中定义的,可以省略。主要是为了让程序更清晰,除非函数声明使用了关键字`static`,否则默认其为`extern`的
static int c();//c函数只能在本文件中调用

动态分配内存

malloc与free函数原型存在于stdlib.h中。

malloc函数

在C中,一些数据的内存是由系统自动分配的,也允许程序主动要求分配。

int foo = 0;//系统自动分配内存空间用来存储一个int
char string[] = "I love you.";//系统自动为数组string分配正好装下字符串的内存空间
int bar[10];//要求分配10个用来存储int的内存空间

还可以手动分配内存。

extern void * malloc(unsigned int num_bytes)

函数malloc函数接受一个参数,该餐宿用于指定需要分配的内存字节数。malloc找到可用内存中一个区块,并返回该区块内存第一个字节的地址。它的void *返回值是一个通用指针,可以转换为其他指针类型。C中不要求强制转换,但C++中要求强制转换。如果malloc找不到符合要求的可用内存,它会返回空指针。例子:

double *p;
p = (double *)malloc(30 * sizeof(double));

例子中,分配了一块内存用于存储30个double类型数据,并将首字节地址赋值给了指针p。

free函数

void free(void *p)

对应每个malloc函数调用,应该有对应的free调用来进行内存释放。它的参数是之前malloc函数分配内存块第一个字节的地址。也就是说分配的内存可用时间是从malloc执行结束开始到free释放内存为止。

例子:

#include <stdio.h>
#include <stdlib.h> /*
* test.c 编译后产生可执行文件test.exe或test.out
*/ int main() { double *p;
int max;
int number;
int i = 0; puts("What's the number of \"double\" entries?");
while (scanf("%d",&max) != 1){
// setbuf(stdin,NULL);
scanf("%*s");
puts("Please input a integer:");
} printf("max = %d\n",max); p = (double *) malloc(max * sizeof(double));
if (p == NULL){
puts("Memory allocation has failed. Try to Restart this program.");
exit(EXIT_FAILURE);
} puts("Enter the values(q to quit): ");
while (i < max && scanf("%lf",&p[i]) == 1)
++i;
printf("Here are the number of entries: %d\n",number = i);
for (int j = 0; j < number; ++j) {
printf("%7.2f ",p[j]);
if (j % 7 == 6)
putchar('\n');
}
if (i % 7 !=0)
putchar('\n');
printf("i = %d\n",i);
puts("Done.");
free(p);
return 0;
}

calloc函数

与malloc类似,不同的是calloc可以指定要分配单元数目以及每个单元所需要的字节数。calloc会默认将内存块中的各个位置0。

calloc分配的内存同样需要用free函数来释放。

动态分配内存的缺点

动态分配内存给了程序一定的自由,但是若是忘记释放内存,那么就会造成资源的浪费(内存泄漏)。而且相对于自动变量栈式管理,动态分配内存不是紧凑的连续分配,而是在内存中找合适的区块,会造成内存碎片,拖慢速度。

C类型限定关键字

constant定义全局常量

constant定义常量之前已经做了笔记,看这里。这里我们来看它与全局常量的关系。

constant定义全局常量有两种方式:

第一种方法:

//file1.c
const double PI = 3.14; //file2.c
extern const double PI;

第二种:

//constant.h中定义常量,需要`static`关键字来修饰
static const double PI = 3.14; //file1.c只需include 头文件即可
#include "constant.h" //file2.c
#include "cobnstant.h"

第二种方法中,file1.c和file2.c文件都包含了constant.h头文件,那么这两个文件都会定义声明一个本文件私有的静态内部链接变量PI,其实是对constant.h中PI值的拷贝。为什么必须要使用static关键字呢?因为如果不使用的话同一个静态外部链接变量就要在两个文件中定义声明两次,而我们知道外部变量只允许定义声明一次,其余的都应该是引用声明,定义两次会造成标识符冲突,还不如直接加个static修饰,为每个文件分别拷贝一个PI值给他们用。

volatile关键字

volatile告诉编译器某个变量除了能被程序本身修改之外,还可以被超出程序之外的其他部分改变。假定,有一个变量的值记录的是时间,那么不管程序有没有在运行,运行的如何,这个变量的值肯定是要随着时间变化而变化的,那么这个变量就应该加volatile修饰来提醒编译器。再来个例子:

int x = 10;
int val1 = x;
int val2 = x;

编译器注意到x变量被使用了两次而没有进行别的操作,那么他可以将x的值临时存储在寄存器中,那么当val2和val1进行赋值操作时就会变快。但是,如果x的值可能被除了程序之外的部分改变,那么就应该这样:volatile int x = 10;来告诉编译器这个变量可能会如此,那么编译器就不会做出将x值存于寄存器这样的优化。一个变量既可以是constant,也可以是volatile的,因为不能被程序改变的量为常量,但可能被硬件改变,那么就是volatile的。这与Java中的volatile关键字可不一样。

restrict关键字

restrict关键字只能用来修饰指针,表示某个数据对象的唯一访问方式就是该指针,方便编译器优化。用法:

int * restrict foo = (int *) malloc(10 * sizeof(int))。这里表明foo这个指针是数组的唯一访问方式。

int array[4] = {};
int *p = array;

这里就不能给p加restrict限定词,因为array这个数组可以通过array和p两种方式进行访问。

C Primer Plus--C存储类、链接和内存管理之动态分配内存及类型限定词的更多相关文章

  1. C Primer Plus之存储类、链接和内存管理

    存储时期即生存周期——变量在内存中保留的时间 变量的作用域和链接一起表明程序的哪些部分可以通过变量名来使用该变量. 注意:生存期和作用域是两个不同的概念. 作用域    作用域描述了程序中可以访问一个 ...

  2. 《C prime plus (第五版)》 ---第12章 存储类.链接和内存管理

    12-1:存储类: 1.作用域: 代码块作用域,函数原型作用域和文件作用域. 2.链接:分为外部链接,内部链接和空链接.代码块作用域和函数原型作用域都是空连接,意味着是私有的.而文件作用域的变量可能是 ...

  3. C Primer Plus--C存储类、链接和内存管理之存储类(storage class)

    目录 存储类 作用域 链接 存储时期 自动变量 寄存器变量 具有代码块作用域的静态变量 具有外部链接的静态变量 extern关键字 具有内部链接的静态变量 多文件 存储类 C为变量提供了5种不同的存储 ...

  4. 【C语言学习】《C Primer Plus》第12章 存储类、链接和内存管理

    学习总结 1.作用域可分为代码块作用域.函数原型作用域或者文件作用域. 代码块作用域例子: { for(int i=0;i<10;i++){  //C99允许 …  //i的作用域 } ... ...

  5. 【C语言学习笔记】存储类、链接和内存管理

    因为对内存管理部分一直没有很清楚的思路,所以一直在找资料想系统看一下这部分的内容.在C primer plus里看到了这一章,虽然大多都是心知肚明的东西,但是还是很多概念性系统性的东西让我眼前一亮,把 ...

  6. C中存储类、链接和内存管理

    在C语言中,有5种不同的存储类型,即存储类.在介绍存储类之前,需要首先简单介绍几个术语.如下: 作用域:描述程序中可以访问一个标识符的一个或多个区域.一个C变量的作用域可以是代码块作用域.函数原型作用 ...

  7. 【足迹C++primer】46、动态存储类

    动态存储类 StrVec Class Design StrVec Class Definition class StrVec { public: //构造函数 StrVec():elements(nu ...

  8. 存储类&作用域&生命周期&链接属性

    链接属性 (1)大家知道程序从源代码到最终可执行程序,经历的过程:编译.链接. (2)编译阶段就是把源代码搞成.o目标文件,目标文件里面有很多符号和代码段.数据段.bss段等分段.符号就是编程中的变量 ...

  9. 7、存储类 & 作用域 & 生命周期 & 链接属性

    概念解析 存储类 存储类就是存储类型,也就是描述C语言变量在何种地方存储. 内存有多种管理方法:栈.堆.数据段.bss段..text段······一个变量的存储类属性就是描述这个变量存储在何种内存段中 ...

随机推荐

  1. MY SQL 两种安装方式

    MySQL基础知识-安装MySQL   前导: 昨天去参加了一个面试,公司不太大,是一家日资企业,在国内有几家分公司,面试官问到了MySQL的基本操作和性能优化,说了一大堆,倒是比较轻松的过了,但是面 ...

  2. 分享-SpringCloud微服务架构图

    1: 为大家分享一张SpringCloud微服务通用架构图 ​标题 此图仅供参考: 需要原图的同学请移步 >>>>>>>>> 这里 如有不合理的地 ...

  3. metasploit、msfvenom生成木马入侵电脑及手机

    简介 msfvenom msfvenom a Metasploit standalone payload generator,Also a replacement for msfpayload and ...

  4. JS函数的三种方式

    函数,一段能够自动完成某些功能的代码块,函数的出现,既解决了重复使用重一功能的需求,又可以避免代码的臃肿性. 使用函数有两个要求:必须调用后才可以执行;函数名不要和关键字以及系统函数相同; 函数主要有 ...

  5. 记支付宝接口对接,涉及到提取证书SN号的解决方案

    支付宝针对.NET SDK并未封装有提取证书SN序列号的方法,仅针对Java平台才有对应的方法(赤裸裸的歧视啊~~) 要想在提取这个SN序列号有两种方案: 1. 直接用Java SDK包来提取SN 2 ...

  6. 修正DejalActivityView在iOS8之前系统上存在的Bug

    DejalActivityView是国外的第三方库,可自定义文本内容和文本长度的菊花转加载指示器效果.该第三方库与其它hud存在不同,能够遮盖键盘:可以自定义遮盖NavigationBar或不遮盖Na ...

  7. p4.BTC-实现

    比特币是基于 transaction-based ledger.(隐私保护性很好,但是在转账中需要说明币的来源,比较麻烦) 比特币的全节点需要维护一个UTXO的数据结构(unspent transac ...

  8. Linux 曝出严重安全漏洞,受限用户亦可提权至 Root 身份运行任意命令!(内附解决方案)

    本文首发于:微信公众号「运维之美」,公众号 ID:Hi-Linux. 「运维之美」是一个有情怀.有态度,专注于 Linux 运维相关技术文章分享的公众号.公众号致力于为广大运维工作者分享各类技术文章和 ...

  9. 2013.5.8 - KDD第二十天

    下午去上刘杨老师的机器学习课,今天讲的"朴素被噎死",他本想当场举个例子,结果读了好半天才吧关系都拼凑上,他说明天给我们带来个精彩的,回去之后夜里把朴素贝叶斯自己又脑补了一下,发现贝叶斯原理(后验)就 ...

  10. docker安装之mariadb

    https://hub.docker.com/_/mariadb?tab=description Supported tags and respective Dockerfile links 10.4 ...