基础回顾之存储类、链接与内存管理
做技术,越做到后面越觉得基础、底层的才是越难得,也会越有技术含量的。最近做的项目有关音视频、图像处理,涉及到的都死c和c++相关的代码。遇到了问题才发现,c和c++才是通用大法。这两块没学好,那也只有玩一玩应用层、UI这些东西。抽空整理下。
作用域
四种:
- 多个文件共享的变量
- 特定文件每个函数共享的变量
- 某个函数特有的变量
- 某个函数一个代码块的变量
一个C变量的作用域可以是代码块作用域,函数作用域,文件作用域,基本概念就不说了。
需要注意的几点:
|
|
这里i
的作用域是整个for循环。
一个所有函数之外定义的变量就是文件作用域。整个文件可以访问该变量。也叫全局作用域
|
|
链接
- 外部链接:多个文件使用
- 内部链接:当前文件使用
- 空连接:函数代码块使用
|
|
存储时期(变量在内存中生存的时间)
- 静态存储:程序执行期间一直存储,文件作用域(内部和外部)的变量具有静态存储时期。文件作用域中特别注意用static表明链接类型而并非存储时期。一个使用了static生命的文件作用域变量表示这个变量具有内部作用域。
- 自动存储:代码块作用域的变量。
5种存储类:自动,寄存器,代码作用域静态,外部静态,内部静态。下面这种表总结了上面的多种情况。
重点说明一下寄存器变量:寄存处变量是存储在CPU的寄存器中,比一般的内存要快很多。但是有一个问题就是寄存器变量的地址是无法获取的。
把变量定义下所有函数之外,就创建了一个外部变量,为了使程序清晰,可以在使用使用外部变量的函数中通过extern来再次声明。如果变量在别的文件定义,使用extern来声明就是必须的。这里想一想OC中的写第三方库的时候,为了让其他模块能够访问某个变量就是通过这种方式来达到目的的。
比如YYWebImageSetter中。
.h
|
|
.m
|
|
函数也是具有存储类。函数默认是外部的,可以被其他文件中的函数调用,静态函数只可以在定义它的文件中使用(用static)
使用static可以防止名字的冲突,为文件定义一个私有的变量或者函数。想想平时我们在定义常量的时候,有时候会出现冲突,OC中用static解决的。应该有些同学有印象的。
分配内存
系统自动分配内存:
|
|
系统将会预留出存储float或字符串的足够内存空间。也可以指定预留多少内存空间:
|
|
声明了100个内存位置,每个位置可以存储一个int值。这里的plate和上面的x、hello变量可以理解为内存的标识符。所以我们可以用x、hello来标识、获取这些内存数据。
malloc&&free&&calloc
用于动态开辟内存。函数void* malloc( size_t size );
函数说明
|
|
传入所需要的内存字节数,然后malloc找到内存中一个大小适合的快,内存是匿名的,不像上面可以用定义float x;x用于标识。不过返回的是一个开辟内存的第一个字节的地址。虽然没有为它指定名字,但是我们可以通过指针来接受返回的值来访问那块内存。
因为char代表一个字节,所以经常将malloc定义为指向char的指针类型。但是后来又了新的类型——————通用型指针(void *
)。这样就可以返回其他类型的了。特别注意如果malloc找不到所需的空间,就会返回空指针。比如传入一个负数就会返回NULl
|
|
请求30个double类型值的空间,并把dbl指向该空间的所在的起始位置。然后就可以使用数组那样使用它。简单来讲可以dbl[0],dbl[1]访问
开辟了内存,必定要释放内存。用free释放内存。对应到OC就是那句内存管理的至理名言谁开辟、谁释放(alloc、release)
一次malloc,应该调用一次free。free的参数是malloc返回的地址,释放掉先前分配的内存。不能使用free来释放通过其他形式分配的内存,比如声明一个数组。
例子强调一下free的重要性
|
|
第一次调用testCopy,创建指针temp,并使用malloc开辟了2000 16,一个32000个字节。当函数终止,temp作为自动变量被销毁,*但是它指向的32000个字节的内存仍然存在,并且无法访问这些内存,因为地址不见了(temp销毁),由于没有调用free,那么就不可以再次使用这些内存。
第二次调用testCopy,又创建一个temp,但是第一次的32000字节的块已经不能再用了。所以malloc不得不再去开辟一块新的内存地址。当函数终止,这块内存同样没有调用free,创建的内存同样不能被访问。
循环1000次,就是32000000个字节。已经有3200万字节在内存中中不能使用。这就是在做iOS开发中MRC时代经常遇到的内存泄漏。
为了说明问题,这里我用xcode测试了一下,把循环次数改为了100000000。
没有加free之前。
加free之后。
对比上面很明显能看到两者的区别。
calloc与malloc最大的区别是calloc会把开辟的全部位置为0。使用方式和malloc类似,同样需要用free释放内存。
|
|
开辟了可以容乃100个long类型的内存空间。
常见的限定词
const
普通类型前,标识这个值不可变。而用在指针的时候情况就分多种了
因为指针存在,指针不可变还是指向的值不可变。
const float *pf
(等同于float const * pf
):表示pf指向一个常量浮点型数值。但是pf本身的值可以改变。比如它可以指向另一个const值float * const pt
:表示pt是一个常量指针,他总是指向同一个地址,但是地址里面的内容可以改变。const float * const pfc
:表示pfc是个常量指针,而且指向的地址内容也不能变。
记忆方式,const位于*
左边代表指向的值不可变,位于*
右边指针不可变