iOS开发学习之C语言---C09 动态内存分配

//

//  main.m

//  C09 动态内存分配

//

//  Created by 康亮亮 on 15/10/19.

//  Copyright (c) 2015 Darling.com. All rights reserved.

//


#import <Foundation/Foundation.h>

// 静态变量(全局变量)

// d的在整个工程中都有效

int d = 12;

// e的作用只在当前文件中

static int e = 23;



void testMemory(){

    printf("hello");

    

}






int main(int argc, const char * argv[]) {

    // 按地址从高到低

    // 栈内存中返回地址是不安全的,要避免!先进后出,局部变量丢在栈区

    // 堆区,手动分配,手动释放!

    // 静态存储区 全局变量(不属于任何一个函数)丢在静态存储区

    // 常量占用内存,只读状态,不可修改!

    // 代码区

    

    

#pragma mark 内存五大区

    /*

     1、内存地址按照从高到低可以分为五个区域,每个区域用来存放不同类型的数据

     2、五大区域按地址从高到低:栈区、堆区、静态区、常量区、代码区。

     */

    

    // 打印各个区的地址

    // 1、栈区的地址

    //    int a = 23;

    //    printf("栈区的地址是:%p\n",&a);

    //    // 2、堆区的地址

    //    int *p = malloc(4);

    //    printf("堆区的地址是:%p\n",p);

    //    // 3、静态区的地址

    //    static int b = 12;

    //    printf("静态区的地址是:%p\n",&b);

    //    // 4、常量区的地址

    //    char *p1 = "hello";

    //    printf("常量区的地址是:%p\n",p1);

    //    // 5、代码区的地址

    //    printf("代码区的地址是:%p\n",testMemory);

    

    

    

#pragma mark 栈区

    /*

     1、局部变量的存储空间,基本都是在栈区。局部变量在函数、循环、分支中定义。

     2、栈区的内存由系统负责分配和回收,按照从高到低分配内存空间。在存储数据时,从低到高存储数据。

     3、栈区里的内存,会在变量出了作用域后自动被系统回收。

     4、栈的数据结构:先进后出(FILO),最先入栈的数据,会保存在栈底。(例如:手枪的弹夹)

     5、栈区会存在数据稳定性的问题:在函数中返回栈的内存地址是不安全的,因为那块地址被系统回收了,随时会被其他数据占用。

     */

    

    

    

#pragma mark 静态区的特点

    /*

     1、全局变量,使用static修饰的变量(或局部变量)都存储在静态区

     2、静态区的存储空间由系统分配和回收。

     3、程序运行结束后,静态区的存储空间才会被回收。静态去变量的生命周期和程序的生命周期一样长。

     4、静态区的变量只能初始化一次,在编译期进行初始化,在程序运行期,可以修改静态区变量的值。

     5、静态变量如果没有设置初始值,默认设置为0

     6、如果变量是一个局部变量,使用static修饰之后,变量的作用域不会发生改变。 我们可以使用指针指向这块地址,这样在作用域之外就能正常访问它的值了。(因为静态区的变量,生命周期和程序运行的生命周期一样长)

     */

    //    int *p3 = NULL;

    //    for (int i = 0; i < 5; i++) {

    //        static int f = 34; // f从栈区挪到了静态区,在编译期,进行初始化,程序在运行时就不再执行这条代码

    //        f = 22; // 在运行期改值

    //        p3 = &f;

    //    }

    

    

    

    

#pragma mark 常量区(文字常量区)

    /*

     1、常量存储在常量区。如:常量字符串

     2、常量区的内存由系统分配和回收

     3、在程序执行结束后,常量区的内存空间才会被回收

     4、常量区的数据只能被读取,不能被修改,修改会造成程序崩溃

     */

    //    char *p4 = "nice";

    //    p4[0] = 'a'; // 程序运行到这一行会崩溃,因为修改了常量区的内容

    

    

    

    

#pragma mark 代码区

    /*

     1、内存由系统分配和回收

     2、程序运行结束后,由系统回收分配过的存储空间

     3、代码区只能读取,不能修改

     4、编程语言被翻译为机器指令后就存放在代码区

     */

    

    

    

    

    

#pragma mark 堆区

    /*

     1、由开发者负责分配和回收

     2、如果只开辟,不回收的话,会造成内存泄露

     3、堆区的内存如果程序员不回收的话,在程序执行结束后,系统会帮忙回收,但是如果程序员不能及时清理内存,那么程序运行期间可能会因为内存泄露造成堆内存被全部占用,程序无法继续运行。

     */

    

    

    // 内存分配函数malloc

    // void *malloc(size);

    // void *:表示的是无类型指针,这种指针可以转化为任何类型指针(返回值可以被任何类型的指针保存)

    // malloc:内存分配函数名

    // size:函数参数,是一个无符号整形数,表示要在堆区中开辟的字节个数

    // 这个函数的作用是:在堆区开辟指定size字节数的内存,并将内存首地址返回

    

    

    //    // 定义一个整形指针

    //    int *p = NULL;

    //    // 使用函数在堆区中开辟5int类型的字节数

    //    p = malloc( sizeof(int) * 5 );

    //    // 将前四个字节里放入23

    //    *p = 23;

    //    // 下一个数字是44

    //    *(p+1) = 44;

    //    // 打印存进去的两个数,及其地址

    //    printf("%d\n%p\n%d\n%p\n", *p, p, *(p+1), p+1);

    

    

    

    // 练习: 分配内存,用来存储float类型的数,12.34 并打印输出

    

    //    float *p = NULL;

    //    p = malloc( sizeof(float) );

    //

    //    *p = 12.34;

    //    printf("%f\n%p\n", *p, p);

    

    

    

    

    // 释放指针 ·

    //    int *p = malloc(sizeof(int));

    //    *p = 12;

    //    // 使用free函数,释放指针指向的内存空间

    //    free(p);

        printf("*p = %d\n", *p);

    //

    //    int *q = malloc(sizeof(int));

    //    *q = 45;

    //    printf("%p,%p\n", p, q);

    //    free(q);

    //    q = NULL; // 在指向的内存空间被释放后,应该将该指针指向0x0的位置,防止产生野指针的现象

        free(q); // 此时造成了过度释放:对一个已经释放的区域再次释放

    

    

    

    

    

    

    

    //

    //    int *p1 = NULL;

    //    p1 = malloc(sizeof(int) * 5); //sizeof(int) * 5 = 20

    //    for (int i = 0; i < 5; i++) {

    //        *p1 = i;

    //        p1++;

    //    }

    //

    //    // 如果程序在这里就结束,就产生了内存泄露

    //

    //    // 首先要将指针挪到这片地址空间起始地址

    //    for (int i = 0; i < 5; i++) {

    //        p1--;

    //    }

    //

    //    // 在这里释放内存空间,字节数就是当初分配给p1指针访问的字节数(在这里是20个字节)

    //    free(p1);

    //

    //    p1 = NULL;

    

    

    

    

    

    // 练习1: 有一字符串,其中包含数字,提取其中的数字.要求动态分配内存保存 提示: 先计算出有几个数字,然后根据数字的个数来开辟空间.

    //    char string[] = "hey1ha2wu9";

    //    // 1.查找字符串中数字字符的个数

    //    // 1.1定义一个计数器,记录字符串中数字的个数

    //    int count = 0;

    //    // 1.2 使用循环来遍历字符串,找到数字字符

    //    for (int i = 0; i < strlen(string); i++) {

    //        // 1.2.1 判断当前字符是否是0~9之间的字符

    //        if ('0' <= string[i] && string[i] <= '9') {

    //            count++;     // 符合判断条件,则让计数器加一

    //        }

    //    }

    //    // 打印验证

    //    printf("count = %d\n", count);

    //

    //    // 2.开辟堆内存的空间,并将数字字符转换为整形数,存进去

    //    // 2.1 开辟堆内存中的空间

    //    int *p8 = malloc(sizeof(int) * count);

    //    // 2.2 使用循环将数字存进堆内存

    //    int num = 0;  // 这个变量是给指针偏移使用的,在每找到一个数字后,就将(p+num)这个指针向后偏移的

    //    for (int i = 0; i < strlen(string); i++) {

    //        // 判断找出数字字符

    //        if ('0' <= string[i] && string[i] <= '9') {

    //            // 将数字字符转换为整形数

    //            int temp = string[i] - '0';

    //            printf("temp = %d\n", temp);

    //            // int类型的数字存进堆内存中

    //            *(p8 + num) = temp; //(p8 + num)

    //            num++;

    //

    //        }

    //    }

    //

    //    // 打印存进堆内存中的数据

    //    for (int i = 0; i < count; i++) {

    //        int a = *(p8 + i); // (p+i)是个新指针,不建议用(p++

    //        printf("%d\n",a);

    //    }

    //

    //    // 释放内存空间

    //    free(p8);

    

    

#pragma mark  callocrealloc

    /*

     calloc(<#size_t#>, <#size_t#>)

     1、前一个参数表示n个单位,后一个参数表示一单位是几个字节(size)。开辟的总长度就是n*size个字节数

     2、该函数会将开辟出来的内存空间清零

     3、效率问题:由于会自动清零,所以calloc函数的执行效率低于malloc

     */

    

    //    // 在堆区开辟10个字节的空间,使用calloc

    //    char *str = NULL;

    //    str = calloc(2, 5);

    //    // “Hello”写入堆内存中

    //    strcpy(str, "hello");

    //    printf("%s\n", str);

    //    printf("%d\n", *(str + 8));

    //    free(str);

    //    str = NULL;

    

    

    

    

    /*

     realloc(<#void *#>, <#size_t#>)

     1、第一个参数是指针,已有的内存空间的首地址(需要扩充内存字节数的空间的首地址)。第二个参数是:重新给这个指针指向的地址分配多少字节

     

     2、如果原空间足够大,则在原空间基础上重新分配;如果原空间不够大,就会重新寻找一块连续的存储空间(能够分配新的字节个数),重新分配,之前保存在内存中的数据会被原样拷贝到新空间里。

     */

    //    int *p7 = malloc(10);

    //    printf("p7 = %p\n", p7);

    //    int *q7 = malloc(4);

    //

    //    p7 = realloc(p7, 40);

    //    printf("p7 = %p\n", p7);

    //    free(p7);  // 虽然p7的指向发生改变,但是在改变之前,系统就代替程序员将它原来指向的区域释放掉,在这里,我们只需要释放新指向的区域即可。

    //    free(q7);

    

    

    

#pragma mark 内存操作函数

    /*

     memset(<#void *#>, <#int#>, <#size_t#>)

     三个参数,第一个是指针p,第二个是整型n,第三个长度size

     这个函数的作用是:从给定的地址开始一直向后size个字节数,这个范围的内存的值被设置为n

     */

    

    // 开辟5int类型的空间,使用memset函数将这五个字节的空间初始化为3

    //    int *p = malloc(5 * sizeof(int));

    //    // 使用初始化函数设置初始值

    //    memset(p, 3, 5);    // 最后一个参数表示的是初始化几个字节

    //    printf("*p = %d\n", *p);

    //    printf("*p = %d\n", p[0]);

    

    

    

    /*

     memcpy(<#void *#>, <#const void *#>, <#size_t#>)

     1、前两个参数是指针类型,最后一个参数是整型,表示范围size

     2、将第二个指针指向的地址开始,连续拷贝size个字节的内容到第一个指针指向的空间中

     3、第一个指针指向的空间字节必须大于等于size

     */

    //    char *p1 = malloc(3);

    //    p1 = "ab";

    //

    //    char *p2 = malloc(3);

    //    memcpy(p1, p2, 1);

    //    printf("%s\n", p1);

    

    

    

    /*

     * 我们可以使用memcpy函数来操作堆区的内存空间

     */

    //    char wrongName[] = "bj123";

    //    char rightName[] = "bj234";

    //    memcpy(wrongName, rightName, 3);  // rightName指向的地址开始连续3个字节的内容拷贝到wrongName中。(这里操作的是栈区的内存)

    //    printf("%s\n", wrongName);

    

    

    /*

     memcmp(<#const void *#>, <#const void *#>, <#size_t#>)

     字符串比较函数:参数是两个指针,从这两个指针指向的位置开始,一直比较size个字节,并将比较结果返回

     

     */

    

    //    int num1[3] = {1, 4, 3};

    //    int num2[3] = {1, 2, 3};

    //    int result = memcmp(num1, num2, 3); // 比较的是字节数,并不是元素的个数

    //    printf("result = %d\n", result);

    

    

    

    

    return 0;

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值