C语言简单复习

最近打算开始学习STM32,发现关于C语言的一些知识已经忘得差不多了
这篇文章主要是对C语言的一些基础知识进行简单的复习

指针

* 用于声明指针变量或者获取指针变量所指向的变量。
& 用于获取变量的地址。
指针是一个变量,其值为另一个变量的地址。

一级指针

一级指针是最基本的指针类型,它存储的是变量的内存地址。在内存中,一级指针占用的空间大小固定,通常为4字节或8字节(取决于操作系统的位数,32位系统为4字节,64位系统为8字节)。

1
2
3
4
5
6
7
8
9
10
11
int a = 10;     //声明一个int类型的变量  
int *p; //声明一个指向int类型的指针
*p = &a; //将指针p指向变量a
*p = 20; //将变量a的值改为20

printf("%d\n", *p); //输出变量a的值
printf("%d\n", p); //输出变量a的地址

int *q = p + 1; //指针p加1,指向下一个int类型的变量
int *r = p - 1; //指针p减1,指向上一个int类型的变量
int n = q - p; //指针q和p相减,得到两个指针之间相差的int类型变量个数
  1. 动态内存分配
    使用malloc、calloc、realloc和free函数进行动态内存分配和释放。
    1
    2
    3
    4
    5
    6
    7
    int *p = (int *)malloc(sizeof(int) * 10);   // 动态分配10个int大小的内存空间
    if (p != NULL) {
    for (int i = 0; i < 10; i++) {
    p[i] = i; // 给动态分配的内存空间赋值
    }
    free(p); // 释放动态分配的内存空间
    }
  2. 函数参数传递
    使用指针作为函数参数,可以实现函数内部修改外部变量的值。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
    }

    int main() {
    int x = 10, y = 20;
    swap(&x, &y);
    printf("x = %d, y = %d\n", x, y); // 输出 x = 20, y = 10
    return 0;
    }

二级指针

二级指针是指向指针的指针,它存储的是一级指针的地址。在内存中,二级指针占用的空间大小固定,通常为4字节或8字节(取决于操作系统的位数,32位系统为4字节,64位系统为8字节)。

1
2
3
4
5
6
7
8
int a = 10;     //声明一个int类型的变量
int *p = &a; //声明一个指向int类型的指针p,并将指针p指向变量a
int **q = &p; //声明一个指向指针p的指针q

printf("%d\n", **q); //输出变量a的值
printf("%p\n", (void *)*q); //输出变量a的地址
printf("%p\n", (void *)q); //输出指针p的地址

  1. 二级指针的动态内存分配
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int **p = (int **)malloc(sizeof(int *) * 10);  // 动态分配10个int*大小的内存空间
    if (p != NULL) {
    for (int i = 0; i < 10; i++) {
    p[i] = (int *)malloc(sizeof(int) * 10); // 动态分配10个int大小的内存空间
    }
    for (int i = 0; i < 10; i++) {
    free(p[i]); // 释放动态分配的内存空间
    }
    free(p); // 释放动态分配的内存空间
    }

  2. 二级指针的函数参数传递
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void swap(int **a, int **b) {
    int *temp = *a;
    *a = *b;
    *b = temp;
    }

    int main() {
    int x = 10, y = 20;
    int *p = &x, *q = &y;
    swap(&p, &q);
    printf("x = %d, y = %d\n", *p, *q); // 输出 x = 20, y = 10
    return 0;
    }

指针数组

指针数组是一个数组,其元素是指针。在内存中,指针数组占用的空间大小取决于数组的大小和指针的大小。

1
2
3
4
5
6
7
8
9
10
11
int a = 10, b = 20, c = 30;  //声明三个int类型的变量
int *p[3]; //声明一个指针数组,其元素是指向int类型的指针

p[0] = &a; //将指针p[0]指向变量a
p[1] = &b; //将指针p[1]指向变量b
p[2] = &c; //将指针p[2]指向变量c

for(int i = 0; i < 3; i++) {
printf("%d\n", *p[i]); //输出变量a、b、c的值
printf("%p\n", (void *)p[i]); //输出变量a、b、c的地址
}

数组指针

数组指针是一个指针,其指向一个数组。在内存中,数组指针占用的空间大小固定,通常为4字节或8字节(32位系统为4字节,64位系统为8字节)。

1
2
3
4
5
6
7
8
int a[3] = {10, 20, 30};  //声明一个int类型的数组

int (*p)[3] = &a; //声明一个指向int类型的数组的指针,并将指针p指向数组a

for(int i = 0; i < 3; i++) {
printf("%d\n", (*p)[i]); //输出数组a的元素
printf("%p\n", (void *)&(*p)[i]); //输出数组a的元素的地址
}

指针函数

指针函数是一个函数,其返回值是指针。

1
2
3
4
5
6
7
8
9
10
11
12
int a = 10;  //声明一个int类型的变量

int *func() {
return &a; //返回变量a的地址
}

int main() {
int *p = func(); //声明一个指向int类型的指针,并将指针p指向函数func的返回值
printf("%d\n", *p); //输出变量a的值
printf("%p\n", (void *)p); //输出变量a的地址
return 0;
}

函数指针

函数指针是一个指针,其指向一个函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int add(int a, int b) {
return a + b;
}

int sub(int a, int b) {
return a - b;
}

int main() {
int (*p)(int, int); //声明一个指向函数的指针
p = add; //将指针p指向函数add
printf("%d\n", p(10, 20)); //输出函数add的返回值
p = sub; //将指针p指向函数sub
printf("%d\n", p(10, 20)); //输出函数sub的返回值
return 0;
}

数组

数组是一种数据结构,它由相同类型的元素组成。在内存中,数组占用的空间大小取决于数组的大小和元素的大小。

一维数组

一维数组是将相同数据类型的元素按顺序存储在一起的数据结构,可以用一个下标来访问每个元素。

1
2
3
4
5
6
7
int a[3] = {10, 20, 30};  //声明一个int类型的数组

for(int i = 0; i < 3; i++) {
printf("%d\n", a[i]); //输出数组a的元素
}
// 输出结果:
// 10 20 30

二维数组

二维数组是将相同数据类型的元素按行和列组织在一起的数据结构,可以用两个下标来访问每个元素。

1
2
3
4
5
6
7
8
9
10
11
int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};  //声明一个int类型的二维数组

for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
printf("%d\n", a[i][j]); //输出二维数组a的元素
}
}
// 输出结果:
// 1 2 3
// 4 5 6
// 7 8 9

数组排序

数组排序是将数组中的元素按照一定的规则进行排列。常见的排序算法有
冒泡排序: 两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
选择排序: 每次从待排序的记录中选出关键字最小的记录,放在已排序记录的末尾。
插入排序: 将待排序的记录插入到已排序的记录中,直到所有记录都插入为止。
快速排序: 通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,然后分别对这两部分记录继续进行排序,以达到整个序列有序。
归并排序: 将两个或两个以上的有序表合并成一个新的有序表。
堆排序: 利用堆这种数据结构所设计的一种排序算法。
计数排序: 是统计每个输入元素的个数,然后依次输出。
桶排序: 将数组分到有限数量的桶里,然后对每个桶再进行排序。
基数排序: 将整数按位数切割成不同的数字,然后按每个位数分别比较。

字符串

C语言中,字符串实际上是使用空字符'\0'结尾的一维字符数组。因此,'\0'是用于标记字符串的结束。空字符(Null character)又称结束符,缩写NUL,是一个数值为0 的控制字符,'\0' 是转义字符,意思是告诉编译器,这不是字符0,而是空字符。

与C++不同,C语言中没有字符串类型,字符串是以字符数组的形式存储的

字符串的定义和初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char str1[] = "Hello"; // 字符串常量
char str2[10] = "World"; // 字符数组

// 初始化字符串
str1[0] = 'H';
str1[1] = 'e';
str1[2] = 'l';
str1[3] = 'l';
str1[4] = 'o';
str1[5] = '\0';

// 另一种初始化方式
char str3[] = {'H', 'e', 'l', 'l', 'o', '\0'};
char str4[10] = {'W', 'o', 'r', 'l', 'd', '\0'};

字符串操作

C语言提供了许多用于操作字符串的函数,这些函数都包含在头文件string.h中。
- strcpy(dst, src): 将 src 字符串复制到 dst 字符串中。
- strcat(dst, src): 将 src 字符串连接到 dst 字符串的尾部。
- strlen(str): 返回字符串的长度。
- strcmp(str1, str2): 比较两个字符串大小, if < return -1, if > return 1, if = return 0
- strchr(str, c): 在字符串中查找字符 c,返回一个指针,指向 cstr 中第一次出现的位置。
- strstr(str1, str2): 在字符串中查找子字符串 str2,返回一个指针,指向 str2str1 中第一次出现的位置。

1
2
3
4
5
6
7
8
9
char str1[10] = "Hello";
char str2[10] = "World";

strcpy(str1, str2); // str1 = "World"
strcat(str1, str2); // str1 = "WorldWorld"
strlen(str1); // 10,因为字符串中包含了空字符
strcmp(str1, str2); // 0, str1 == str2
strchr(str1, 'o'); // str1中第一次出现字符'o'的位置指针,没有找到返回NULL
strstr(str1, "or"); // str1中第一次出现子字符串"or"的位置指针,没有找到返回NULL

其他字符串操作函数还有: - strncpy(dst, src, n): 将 src 字符串的前 n 个字符复制到 dst 字符串中。
- strncat(dst, src, n): 将 src 字符串的前 n 个字符连接到 dst 字符串的尾部。
- strncmp(str1, str2, n): 比较两个字符串的前 n 个字符大小。
- strrchr(str, c): 在字符串中查找字符 c,返回一个指针,指向 cstr 中最后一次出现的位置。
- atoi(str): 将字符串转换为整数。
- atof(str): 将字符串转换为浮点数。
- atol(str): 将字符串转换为长整数。
- itoa(n, str, base): 将整数 n 转换为字符串,base 为进制。
- gcvt(value, ndigit, buf): 将浮点数 value 转换为字符串,ndigit 为小数点后的位数。
- strtok(str, delim): 分解字符串为一组字符串,delim 为分隔符。
- strtoupper(str): 将字符串中的小写字母转换为大写字母。
- tolower(str): 将字符串中的大写字母转换为小写字母。

变量

变量概述

变量是C语言中用来存储数据的基本单位。它就像一个容器,可以存放各种类型的数据,例如数字、字符、字符串等。

变量的四要素:
- 变量名:变量的名称,用来标识变量。
- 数据类型:变量的类型,用来定义变量的数据类型。
- 存储地址:变量的存储地址,用来标识变量在内存中的位置。
- 数据值:变量的值,用来存储变量的数据值。

变量类型

C语言提供了多种数据类型,每种类型都有其特定的存储大小和取值范围。常见的数据类型包括:

  1. 基本数据类型:整型、浮点型、字符型。

    • 整数类型:int(4字节)、short(2字节)、long(4字节)、long long(8字节)。
    • 浮点类型:float(4字节)、double(8字节)、long double(8字节)。
    • 字符类型:char(1字节)。
    • 空类型:void
  2. 构造数据类型:

    • 数组类型:int a[10]
    • 指针类型:int *p
    • 结构体类型:struct {int a; float b;}
    • 枚举类型:enum {RED, GREEN, BLUE}

变量作用域

变量的作用域决定了变量在程序中可被访问的范围。C语言中主要有三种作用域:

  1. 局部变量:在函数内部定义的变量,只能在函数内部访问。函数结束后,局部变量会被销毁。
  2. 全局变量:在函数外部定义的变量,可以在整个程序中访问。
  3. 静态变量:具有静态存储类型的变量,在函数结束后仍然存在。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
int a = 10;  // 全局变量

void func() {
int b = 20; // 局部变量
static int c = 30; // 静态变量
c += 10
}

// 第一次调用func(),b = 20, c = 40
// 第二次调用func(),b = 20, c = 50
// 第三次调用func(),b = 20, c = 60

形参和实参

在函数调用时,形参是函数定义中声明的参数,实参是调用函数时传递给形参的实际值。

  • 形参:用于接收实参的值,类型和个数必须与实参一致。
  • 实参:实际传递给函数的参数,可以是变量、常量或表达式。

形参和实参的关系:

  • 形参是形式上的参数,实参是实际的参数。
  • 形参在函数内部被赋值,实参在函数外部被赋值。
  • 函数调用时,实参会按顺序赋值给形参。

关键字

C语言中的关键字是一些具有特殊含义的单词,它们用于定义变量、函数、结构体等。C语言中的关键字有32个,可以分为以下几类:

  • 数据类型关键字:intfloatchardoublevoidshortlongsignedunsigned

  • 控制语句关键字:ifelseswitchcasedefaultwhiledoforbreakcontinuereturn

  • 存储类关键字:autoregisterstaticexternconstvolatile

  • 其他关键字:structunionenumtypedefsizeofgotoasm
    对于数据类型关键字和控制语句关键字就不多说了,structunionenum在结构中会详细介绍。

  • auto: 用于声明自动变量,存储类为auto的变量在函数内部定义,函数结束后自动销毁。

  • register: 用于声明寄存器变量,存储类为register的变量存储在CPU的寄存器中,访问速度快。

  • static: 用于声明静态变量,存储类为static的变量在程序运行期间一直存在。

  • extern: 用于声明外部变量,存储类为extern的变量在其他文件中定义。

  • const: 用于声明常量,常量的值不能被修改。

  • volatile: 用于声明易失变量,易失变量的值可能会被意外修改。

  • typedef: 用于定义类型别名,可以为已有的数据类型定义一个新的名字。

  • sizeof: 用于获取数据类型或变量的大小,返回值为字节数。

  • goto: 用于无条件跳转到指定的标签,不推荐使用。

  • asm: 用于嵌入汇编代码,可以在C语言中嵌入汇编代码。

结构

C语言提供了三种重要的结构化数据类型:结构体、联合体和枚举类型,它们可以用于表示更复杂的数据结构。

结构体

结构体是一种将不同类型的数据组合在一起的类型。它可以用来表示具有多个属性的复杂数据对象,例如学生、日期、书籍等。

结构体定义

结构体的定义使用关键字struct,其格式为:

1
2
3
4
5
struct student {
char name[20]; // 学生姓名
int age; // 学生年龄
int score; // 学生成绩
};

结构体使用

  1. 声名结构体变量
1
struct student stu; // 声明一个结构体变量stu
  1. 初始化结构体变量
1
2
3
4
5
struct student stu = {"Tom", 18, 90}; // 初始化结构体变量stu
// 或者
stu.name = "Tom";
stu.age = 18;
stu.score = 90;
  1. 访问结构体成员
1
2
3
printf("%s\n", stu.name); // 输出学生姓名
printf("%d\n", stu.age); // 输出学生年龄
printf("%d\n", stu.score); // 输出学生成绩

结构体特点

  • 结构体成员可以是不同类型的数据。
  • 结构体变量的大小等于所有成员变量的大小之和。
  • 结构体成员可以是其他结构体类型。
  • 结构体可以嵌套定义。
    例如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 以下代码定义了一个日期结构体和一个学生结构体,
    // 将日期结构体作为学生结构体的成员,可以用来表示学生的生日。
    struct date {
    int year;
    int month;
    int day;
    };

    struct student {
    char name[20];
    int age;
    struct date birthday;
    };

    struct student stu = {"Tom", 18, {2000, 1, 1}};

联合体

联合体与结构体类似,也是将不同类型的数据组合在一起的类型。但联合体的所有成员共享同一块内存空间,每次只能存储一个成员的值。

联合体定义

联合体的定义使用关键字union,其格式为:

1
2
3
4
5
6
union data {
int num; // 整型数据
float fnum; // 浮点型数据
char str[10]; // 字符串
};

联合体使用

1
2
3
4
5
6
7
8
9
10
11
union data data1; // 声明一个联合体变量data1

data1.num = 10;
printf("num = %d\n", data1.num); // 输出结果为10

data1.fnum = 3.14;
printf("fnum = %.2f\n", data1.fnum);// 输出结果为3.14

// 此时num的值被覆盖
printf("num = %d\n", data1.num); // 输出结果为0

联合体特点

  • 联合体的大小等于所有成员变量中最大的大小。
  • 联合体的成员共享同一块内存空间,每次只能存储一个成员的值。
  • 联合体常用于节省内存空间。

枚举类型

枚举类型是一种用于定义一组常量的类型。它可以提高代码的可读性和可维护性。

枚举类型定义

枚举类型的定义使用关键字enum,其格式为:

1
2
3
4
5
enum color {
RED, // 红色
GREEN, // 绿色
BLUE // 蓝色
};

枚举类型使用

1
2
3
4
5
6
7
8
9
10
11
12
13
enum color c = RED; // 声明一个枚举变量c,并初始化为RED

switch (c) {
case RED:
printf("红色\n");
break;
case GREEN:
printf("绿色\n");
break;
case BLUE:
printf("蓝色\n");
break;
}

枚举类型特点

  • 枚举类型可以定义一组相关联的常量。
  • 枚举类型的值默认从0开始,依次递增。比如上面的枚举类型RED的值为0,GREEN的值为1,BLUE的值为2。
  • 枚举类型可以提高代码的可读性和可维护性。
  • 枚举类型可以用于节省内存空间。

运算符

C语言提供了多种运算符,用于对变量和常量进行运算。常见的运算符包括:

  • 算术运算符:+-*/%
  • 关系运算符:==!=><>=<=
  • 逻辑运算符:&&||!
  • 位运算符:&|^~<<>>
  • 赋值运算符:=+=-=*=/=%=&=|=^=<<=>>=
  • 条件运算符:? :
  • 逗号运算符:,
  • 自增自减运算符:++--
  • 指针运算符:&*
  • sizeof运算符:sizeof
  • 类型转换运算符:(type)

位运算符

位运算符是对二进制数进行操作的运算符,包括按位与、按位或、按位异或、按位取反、左移和右移。

  • 按位与:&,两个位都为1时,结果为1,否则为0。
  • 按位或:|,两个位都为0时,结果为0,否则为1。
  • 按位异或:^,两个位相同时,结果为0,否则为1。
  • 按位取反:~,对每个位取反。
  • 左移:<<,将二进制数向左移动指定的位数。
  • 右移:>>,将二进制数向右移动指定的位数。
1
2
3
4
5
6
7
8
9
int a = 5; // 二进制数为0101
int b = 3; // 二进制数为0011

printf("%d\n", a & b); // 输出结果为1,二进制数为0001
printf("%d\n", a | b); // 输出结果为7,二进制数为0111
printf("%d\n", a ^ b); // 输出结果为6,二进制数为0110
printf("%d\n", ~a); // 输出结果为-6,二进制数为11111111111111111111111111111010
printf("%d\n", a << 1); // 输出结果为10,二进制数为1010
printf("%d\n", a >> 1); // 输出结果为2,二进制数为0010

类型转换运算符

类型转换运算符用于将一个数据类型转换为另一个数据类型。C语言提供了两种类型转换运算符:强制类型转换和隐式类型转换。

  • 强制类型转换:使用(type)将一个数据类型转换为另一个数据类型。
1
2
int a = 10;
float b = (float)a; // 将整数a转换为浮点数b
  • 隐式类型转换:在表达式中,不同类型的数据会自动转换为相同的类型。
1
2
3
int a = 10;
float b = 3.14;
float c = a + b; // 整数a会自动转换为浮点数c

函数

常用的库函数有: ## 输入输出函数

  • printf:格式化输出函数,用于将数据输出到控制台。printf("格式化字符串", 参数列表);
  • scanf:格式化输入函数,用于从控制台读取数据。scanf("格式化字符串", 参数列表);
  • getchar:从控制台读取一个字符。 char c = getchar();
  • putchar:将一个字符输出到控制台。putchar('c');
  • gets:从控制台读取一个字符串。 char str[10]; gets(str);
  • puts:将一个字符串输出到控制台。 puts("Hello");

数学函数

  • abs:求整数的绝对值。 int a = abs(-10);
  • fabs:求浮点数的绝对值。 float b = fabs(-3.14);
  • sqrt:求平方根。 float c = sqrt(16);
  • cbrt:求立方根。 float d = cbrt(8);
  • pow:求幂。 float e = pow(2, 3);
  • exp:求指数。 float f = exp(1);
  • log:求自然对数。 float g = log(2.718);
  • log10:求常用对数。 float h = log10(100);
  • sin:求正弦。 float i = sin(3.14);
  • cos:求余弦。 float j = cos(3.14);
  • tan:求正切。 float k = tan(3.14);

字符串函数

  • strlen:求字符串的长度。
  • strcpy:复制字符串。
  • strcat:连接字符串。
  • strcmp:比较字符串。
  • strchr:查找字符。
  • strstr:查找子字符串。

内存函数

  • malloc:分配内存空间。
  • calloc:分配并初始化内存空间。
  • realloc:重新分配内存空间。
  • free:释放内存空间。

其他函数

  • rand:生成随机数,返回一个0到RAND_MAX之间的随机数,也可以使用rand() % n生成[1, n)之间的随机数。
  • srand:设置随机数种子,随机数种子相同,生成的随机数也相同。
  • time:获取当前时间。
  • clock:获取程序运行时间。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
srand(1); // 设置随机数种子
int n = rand() % 300 + 1; // 生成1到300之间的随机数
time_t t = time(NULL); // 获取当前时间
clock_t c = clock(); // 获取程序运行时间
printf("%d\n", n);
printf("%ld\n", t);
printf("%ld\n", c);
return 0;
}

内存

C语言中的内存分为栈内存、堆内存和全局内存。

栈内存

栈内存是程序运行时由编译器自动分配和释放的一块内存区域。它主要用于存储函数的局部变量、函数参数和返回值等。

栈内存的特点:

  • 由编译器自动管理,程序员无需手动操作。
  • 先进后出,即后压入的栈帧先弹出。
  • 空间大小有限,由编译器决定。

示例:

1
2
3
4
5
6
7
8
9
10
11
void func(int a, int b) {
int c = a + b;
// ...
}

int main() {
int x = 1;
int y = 2;
func(x, y);
// ...
}
在这个例子中,func()函数的局部变量 abc存储在栈内存中。当 func()函数结束时,栈内存中的这些变量会被自动释放。

堆内存

堆内存是程序运行时由程序员显式分配和释放的一块内存区域。它主要用于存储动态分配的内存空间,例如使用malloc()calloc() 函数分配的内存。

堆内存的特点:

  • 由程序员手动管理,需要显式分配和释放。
  • 先分配后释放,程序员需要手动释放堆内存,否则会导致内存泄漏。
  • 空间大小可变,由程序员决定。

示例:

1
2
3
4
5
int main() {
int *p = malloc(10 * sizeof(int));
// ...
free(p);
}
在这个例子中,p指针指向了一块由 malloc() 函数分配的堆内存空间。当不再使用 p 指针指向的内存空间时,需要使用 free() 函数释放它,以避免内存泄漏。

全局内存

全局内存是程序运行时由编译器分配,在程序结束时释放的一块内存区域。它主要用于存储全局变量和静态变量等。

全局内存的特点:

  • 由编译器自动管理,程序员无需手动操作。
  • 程序运行期间一直存在。

示例:

1
2
3
4
5
int global_var = 1;

int main() {
// ...
}
在这个例子中,global_var 变量存储在全局内存中,从程序开始到结束,一直存在。

内存分配和释放

C语言提供了多种内存分配和释放函数,包括malloccallocreallocfree

  • malloc:分配指定大小的内存空间,并返回指向该内存空间的指针。
  • calloc:分配指定大小的内存空间,并将其初始化为0,返回一个指向分配内存的指针。
  • realloc:用于重新分配内存空间,返回一个指向分配内存的指针。
  • free:用于释放动态分配的内存空间。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int *p = (int *)malloc(sizeof(int) * 10); // 分配10个int大小的内存空间
//或者
//int *p = (int *)calloc(10, sizeof(int)); // 分配10个int大小的内存空间,并初始化为0
if (p != NULL) {
for (int i = 0; i < 10; i++) {
p[i] = i; // 给动态分配的内存空间赋值
}
free(p); // 释放动态分配的内存空间
}
//重新分配内存空间
int *p = (int *)realloc(p, sizeof(int) * 20); // 重新分配20个int大小的内存空间
if (p != NULL) {
free(p); // 释放动态分配的内存空间
}