iOS进阶之路

iOS:栈、堆、字符串常量区、全局区

2019-01-19  本文已影响128人  康小曹

C语言的数据在运行之前,编译器会提前预留一些内存(text 代码区,BSS、data等),这些数据不是说编译器就能生成,而是告诉程序在程序启动时先创建并分配内存,这部分数据就是全局区。程序运行之后也会生成堆区,堆区可以很大,用处也很多。其中一个作用就是作为栈使用。也就是遵循FIFO的内存,栈区内存由编译器控制,可以理解成编译器自动帮忙生成分配销毁内存的代码,栈区主要是用来存储局部变量和形参。堆区是程序员主动分配的内存。

一、常量区

常量区很多时候也被叫做:全局区/静态数据区/常量区等等。常量区分为两部分,已初始化的常量区和未初始化的常量区(也叫BSS,使用0初始化)存储的数据有

字符串常量的意义:
首先,字符串常量的意义就是在常量区存储一些已经使用了的,且没有指向的字符串常量。比如说一个char *p = "abcde";这个时候赋值给p的是"abcde"首个元素的地址。而char s[] = "abcde";是在内存中创建了"abcde"并赋值给了s[],也就是说s[]的内存中记录的就是"abcde",而p中内存记录的是地址,这也就导致了第二种情况下"abcde"无处安放,所以就存储在常量区。另外,排除编译器设置,按照C语言的原始设计思想,如果有char *p1 = "abc"; char *p2 = "abc";这种情况下,应该在常量区分配两块不同的内存,而有的编译器做了优化,所以会导致p1和p2指向的内存地址是一样的,也就是说"abc"=="abc" = YES;所以,不再需要纠结字符串常量到底存储在哪,只需要记住C语言中变量的赋值原则:非指针变量,拷贝内存中的表现形式(实际的值),指针变量,拷贝内存地址。
参考

例子1🌰:
代码:

char string1[] = "abcdef"; // string1在常量区/全局区

int main() {
    @autoreleasepool {
        char *p = "abcdef"; // abcdef在常量区/全局区
        printf("%p\n",&"abcdef");
        printf("%p\n",p); // 验证是否p指针指向是常量区"abcdef"
        printf("%p\n",string1); // 验证虽然同出常量区,但是string1并不是指向了"abcdef",而是复制或者说是重新生成

        char s[] = "abcdef";
        printf("%p\n",s); // s[]第一个元素的内存地址
        printf("%c\n",*s); // 获取s[]的第一个元素的值
        printf("%p\n",&(*s)); //验证s[]的值是否指向常量区的"abcdef",结果证明不是指向而是复制/重新生成
}

输出:

0x101f54b6d
0x101f54b6d
0x101f56188
0x7ffeedcae3e1
a
0x7ffeedcae3e1

最终结果:


image.png

例子2🌰:常量字符串不可改变
代码:

int main() {
    @autoreleasepool {
        char string2[] = "abc"; // abc存储在栈中
        char *p = "abc"; // "abc"存储在常量区
//        *p = '1'; //崩溃,常量区的值不可改变(那为什么全局变量的值可以改变?)
        char *p2 = string2;
        *p2 = '1'; //可以改变,因为string2是局部变量而不是字符串常量
//        string2 = '1'; // 编译报错(Array type 'char [4]' is not assignable),因为string2是一个地址,地址不能改变

        printf("%s",string2);
}

结果:

1bc

二、堆

堆区(heap):是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程,C/C++分别用malloc/New请求分配Heap,用free/delete销毁内存。由于从操作系统管理的内存分配所以在分配和销毁时都要占用时间,所以用堆的效率低的多!但是堆的好处是可以做的很大,C/C++对分配的Heap是不初始化的,存放的数据类型有:

三、栈

栈(Stack):也叫堆栈,是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有FIFO的特性,在编译的时候可以指定需要的Stack的大小,也只能指定大小,因为内存的分配是要等到程序执行之后才分配的。在编程中,例如C/C++中,所有的局部变量都是从栈中分配内存空间,实际上也不是什么分配,只是从栈顶向下用就行,在退出函数的时候,只是修改栈指针就可以把栈中的内容销毁,所以速度最快(堆是指程序运行时申请的动态内存,而栈只是指一种使用堆的方法)。栈中存储的数据类型是:

四、代码区

五、几个注意点

1.字符串常量不是字符,因为字符的本质还是数字(int)

  1. 虽然字符串常量和全局变量/静态变量在同一块内存区域,但是并不意味着值相等的字符串所处的内存地址是一样的。或者可以说:字符串常量没有对应的名称时才会存储到字符串常量区
    总结:


    C语言中的内存

参考:

C语言中内存分配

上一篇下一篇

猜你喜欢

热点阅读