存储划分
在C语言中,存储区大致分为5类
- 栈
- 堆
- 全局区(静态区)
- 常量区
- 代码区
栈
- 由编译器自动分配和释放
- 在函数体中定义的变量通常在栈上
- 栈中的变量先进后出
- 栈中的变量一般出了函数会被释放
堆
- 一般由程序员分配和释放,程序员不释放,程序结束时由操作系统释放。
- 使用
malloc
、calloc
、realloc
等分配内存的函数分配得到的就在堆上。 - 释放堆内存
free()
静态区/全局区
- 全局变量和静态变量的存储是放在一块的
- 初始化的全局变量和静态变量在一块区域
- 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域
- 程序结束操作系统统一释放
#include <stdio.h>
int *func()
{
int i = 1;
int *p = &i;
return p;
}
int main(int argc, const char *argv[])
{
int *fn = func();
printf("%d\n", *fn);// 1
printf("%d\n", *fn);// 868186003
printf("%d\n", *fn);// 868186003
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int *func()
{
static int i = 1;
int *p = &i;
//int i = 1;
//int *p = malloc(sizeof(4));
//p = &i;
return p;
}
int main(int argc, const char *argv[])
{
int *fn = func();
printf("%d\n", *fn);
printf("%d\n", *fn);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int g = 100;//全局变量存储在全局区,程序结束后被释放。
int *func()
{
static int i = 1;//静态变量存储在静态区,程序结束后被释放。
int *p = &i;
//int i = 1;
//int *p = malloc(sizeof(int));
//p = &i;
return p;
}
int main(int argc, const char *argv[])
{
int *fn = func();
printf("%d\n", *fn);
printf("%d\n", g);
return 0;
}
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char *str = malloc(sizeof(char)*10);// 堆内存
strcpy(str, "hello");
printf("%s\n", str);
free(str);//释放堆内存
return 0;
}
#include <stdio.h>
#include <string.h>
char *func()
{
char *str = malloc(sizeof(char)*10);
strcpy(str, "hello");
free(str);
return str;
}
int main(int argc, const char *argv[])
{
char *str = func();
printf("%s\n", str);
return 0;
}
常量区
- 专门存放常量的地方,例如1,3.14,'a','hello'...
- 程序结束后系统自动释放
程序代码区
- 存放二进制代码的区域
- 函数通常会被编译成二进制代码,存储在代码区。
- 函数被调用的时候,会从代码区取出,函数需要的参数以及函数体中的变量,会在栈里临时分配,函数结束时,变量会被释放。
动态内存分配
malloc
malloc()
函数向系统申请分配size
个连续的内存空间,返回值为void*
。void*
属于指针类型,不代表确切的指针类型,程序员根据需要转换成自己需要的类型。
void *malloc(unsigned int size)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char * argv[])
{
char *str = (char *)malloc(sizeof(char)*8);
strcpy(str, "hello");
printf("%s\n", str);//hello
free(str);//释放堆内存
str = NULL;//指向空指针
return 0;
}
数组分配空间
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char * argv[])
{
// 分配包含10个int元素的数组,本质上是分配了40个字节空间。
int *arr = (int *)malloc(sizeof(int)*10);
for(int i=0; i<10; i++){
arr[i] = i+1;
}
for(int i=0; i<10; i++){
printf("arr[%d] = %d\n", i,arr[i]);
}
free(arr);
arr = NULL;
// 分配2行3列的二维整型数组
int (*p)[3] = (int (*)[3])malloc(sizeof(int)*2*3);
for(int i=0; i<2; i++){
for(int j=0; j<3; j++){
p[i][j] = i+j;
}
}
for(int i=0; i<2; i++){
for(int j=0; j<3; j++){
printf("p[%d][%d] = %d\n", i, j, p[i][j]);
}
}
free(p);
p = NULL;
// 分配2行255列的二维字符串数组
char (*c)[255] = (char (*)[255])malloc(sizeof(char)*5*255);
free(c);
c = NULL;
return 0;
}
结构体指针
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct student{
char *name;
int age;
} Student;
int main(int argc, const char * argv[])
{
Student *p = (Student *)malloc(sizeof(Student));
p->name = (char *)malloc(sizeof(char)*10);
strcpy(p->name, "alice");
printf("%s\n", p->name);
free(p->name);
p->name = NULL;
free(p);
p = NULL;
return 0;
}
结构体数组
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct student{
char *name;
int age;
} Student;
int main(int argc, const char * argv[])
{
Student *p = (Student *)malloc(sizeof(Student)*3);
return 0;
}
其他内存分配函数
// 分配n个size大小的空间,需使用free释放内存。
// 与malloc不同的是calloc申请的内存空间会初始化成0
void * calloc(unsigned n, unsigned size)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char * argv[])
{
int n = 3;
int *arr = (int *)calloc(n, sizeof(int));
for(int i=0; i<n; i++){
printf("arr[%d] = %d\n", i, arr[i]);
}
free(arr);
arr = NULL;
return 0;
}
// 按新的长度重新分配内存,需使用free释放内存。
void * realloc(void *p, unsigned newsize);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char * argv[])
{
int n = 3;
int *arr = (int *)calloc(n, sizeof(int));
for(int i=0; i<n; i++){
printf("arr[%d] = %d\n", i, arr[i]);
}
printf("-------------------------\n");
int size = 5;
arr = (int *)realloc(arr, sizeof(int)*size);
for(int i=0; i<size; i++){
printf("arr[%d] = %d\n", i, arr[i]);
}
free(arr);
arr = NULL;
return 0;
}
内存操作函数
内存操作函数即可用于堆内存也可以用于栈内存中
// str开始长度为n的所有字节赋值为c
// 用于清除结构体或数组数据
void *memset(void *str, int c, size_t n)
// 从src拷贝n个字节到dst中
void *memcpy(void *dst, const void *src)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char * argv[])
{
int n = 5;
int *arr = (int *)calloc(n, sizeof(int));
for(int i=0; i<n; i++){
printf("arr[%d] = %d\n", i, arr[i]);
}
printf("-------------------------\n");
int size = 10;
arr = (int *)realloc(arr, sizeof(int)*size);
for(int i=0; i<size; i++){
printf("arr[%d] = %d\n", i, arr[i]);
}
printf("-------------------------\n");
// 按字节赋值
// memset(arr, 1, sizeof(int)*size);//00000001 00000001 00000001 00000001
// for(int i=0; i<size; i++){
// printf("arr[%d] = %d\n", i, arr[i]);
// }
// printf("-------------------------\n");
int a[size] = {1,1,1,1,1,1,1,1,1,1};
memcpy(arr, a, sizeof(int)*size);
for(int i=0; i<size; i++){
printf("arr[%d] = %d\n", i, arr[i]);
}
free(arr);
arr = NULL;
return 0;
}
// 内存比较,比较结果分大于0、小于0、等于0
int memcmp(const void *buf1, const void *buf2, unsigned int count)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char * argv[])
{
int size = 5;
int *arr = (int *)calloc(size, sizeof(int));
for(int i=0; i<size; i++){
printf("arr[%d] = %d\n", i, arr[i]);
}
printf("-------------------------\n");
int a[size] = {1,1,1,1,1,1,1,1,1,1};
int result = memcmp(arr, a, sizeof(int));
printf("result is %d\n", result);
free(arr);
arr = NULL;
return 0;
}