堆区空间申请

2020-04-13  本文已影响0人  晓晓桑

栈、堆、全局区、字符常量区、代码区
栈区:由操作系统申请,在变量生命周期结束后由操作系统释放。

堆区:由我们申请,由我们自己释放

malloc(size_t __size)

int main(void) {

    //申请4字节的空间,类型是int的地址,强制类型转换。
    //申请完的地址的首地址就是p
    int *p = (int *) malloc(4);
    return 0;
}
size_t: unaigned int
malloc传无符号,(int *) malloc(4)中4默认是int类型的,c语言会转换成无符号的,如果写成(int *) malloc(4u)就直接是无符号的。无符号就是全是整数,跟有符号的取值范围不一样哦。
malloc申请空间
malloc空间赋值
int main(void) {
    int *p = malloc(40);
    
    //申请的40个字节,能装10个int数据
    for (int i = 0; i < 10; ++i) {
        //给指针赋值
        p[i] = i;
    }
    //赋值后,读取
    for (int j = 0; j < 10; ++j) {
        printf("%d,", p[j]);//0,1,2,3,4,5,6,7,8,9,
    }
    return 0;
}

memset赋值

int main(void) {
    int *p = malloc(40);
    //内存赋值方法
    //第一个参数:起始地址,
    //第二个参数:给起始地址设置的值
    //第二个参数:一共设置多少个字节
    memset(p, 0, 40);
    //赋值后,读取
    for (int j = 0; j < 10; ++j) {
        printf("%d,", p[j]);//0,0,0,0,0,0,0,0,0,0,
    }
    return 0;
}
memset()是按字节赋值的

是把范围内的所有字节都设置成值1(下面的代码里的),而输出是int类型的,int类型占四个字节,所以输出四个值都是1的字节的值,即16843009

int main(void) {
    int *p = malloc(40);
    //内存赋值方法
    //第一个参数:起始地址,
    //第二个参数:给起始地址设置的值
    //第二个参数:一共设置多少个字节
    memset(p, 1, 40);
    //赋值后,读取
    for (int j = 0; j < 10; ++j) {
        printf("%d,", p[j]);//16843009,16843009,16843009,16843009,16843009,16843009,16843009,16843009,16843009,16843009,
    }
    return 0;
}

所以如果赋值成0,才能使用memse()

malloc()注意点

1.malloc申请的字节数一定要对应类型,比如申请int型,那么一定要大于4,double的话就要大于8,因为他们类型一次要操作这些个字节,少了不行,多了可以不用。
2.malloc申请内存之后,就不要再malloc了。但是如果malloc的地址记录一下,然后再指向新的地址,就不会丢失空间了。

int main(void) {
    int *p = malloc(40);

    //p重新指向另一块地址,那么原来的地址就不用了,这样会造成内存泄漏
    p = malloc(4);

    return 0;
}
int main(void) {
    int *p = malloc(40);
    int *p1 = p;
    //专业就不会丢失空间了.或者原来的空间不使用直接调用free(p)
    p = malloc(4);
    return 0;
}
free(p)释放指针
int main(void) {
    int *p = malloc(40);
    *p = 12;
    printf("%p,%d\n", p, *p);
    free(p);
    p = NULL;
    if (NULL == p) {
        //p是空指针 0==null=空
    }
    return 0;
}
malloc一维数组
int main(void) {
    //申请的连续的空间
    //申请出来的地址就是内存的头地址
    int *p = malloc(sizeof(int) * 5);//sizeof(int)*5=20
    int a[5];
    int *p2 = &a[0];//将指针的首地址指向数组的首地址
    return 0;
}
int main(void) {
    //申请的连续的空间
    int *p = malloc(sizeof(int) * 5);//sizeof(int)*5=20
    memset(p, 0, sizeof(int) * 5);//memset只能设置成0
    return 0;
}
int main(void) {
    unsigned int a;
    int *p;
    scanf("%u", &a);
    p = malloc(a);
    free(p);
    return 0;
}
malloc地址转化成一维数组指针/二维数组指针

malloc一维数组指针
(p+n)=*p[n]

int main(void) {
    int a[5];
    //栈区一维数组指针的写法
    int(*p1)[5] = &a;

    //对比上面的写法
    //malloc一维数组指针
    int  (*p)[5] = (int (*)[5]) malloc(sizeof(int) * 5);
    *(*p + 0) = 1;
    *(*p + 1) = 2;
    *(*p + 2) = 3;
    *(*p + 3) = 4;
    *(*p + 4) = 5;


    //遍历malloc的数组数组a的元素
    for (int i = 0; i < 5; ++i) {
        printf("%d,", (*p)[i]);//1,2,3,4,5,
    }
    
    free(p);
    return 0;
}

malloc二维数组指针

int main(void) {
    int a[2][3];
    //栈区二维数组指针的写法
    int(*p1)[2][3] = &a;// *p1 == a;

    //对比上面的写法
    //malloc二维数组指针:
    int  (*p)[2][3] = (int (*)[2][3]) malloc(sizeof(int) * 2 * 3);
    //二维指针数组p赋值
    (*p)[0][0] = 1;
    (*p)[0][1] = 2;
    (*p)[0][2] = 3;
    (*p)[1][0] = 5;
    (*p)[1][1] = 8;
    (*p)[1][2] = 10;
    //遍历malloc的数组数组a的元素
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j <3 ; ++j) {
            printf("%d,", (*p)[i][j]);//1,2,3,5,8,10,
        }
    }
    free(p);
    return 0;
}
calloc realloc
int main(void) {
    //1:数组元素个数,2:每个元素的字节数
    int *a = calloc(5, 4);//申请了一个 5个元素每个元素4个字节的空间

    for (int i = 0; i < 5; ++i) {
        printf("%d,", a[i]);//0,0,0,0,0,
        //calloc 申请出来地址他给初始化成0了,而malloc不给初始化,字节用memset()初始化。
    }

    free(a);
    return 0;
}

realloc:重新给malloc或者calloc分配空间

int main(void) {
    int *p = malloc(12);

    //1:分配空间的首地址,2:重新分配空间的大小
    int *p1 = realloc(p, 20);//正常情况p1 和p的地址是一样的,不正常的看下面的注意
    //如果重新分配的空间,系统分配不足,会返回null

    free(p);
    return 0;
}

注意:
如果malloc或者calloc原来的空间是10个字节,让realloc重新1000个字节:

calloc 和malloc的选择

*在C中的四种作用

上一篇 下一篇

猜你喜欢

热点阅读