malloc
void malloc(size_t size);
size_t就是unsign int无符号正整数
#include <stdio.h> #include <stdlib.h> int main() { int* ptr = NULL; int num, i; printf("请输入待录入整数的个数:"); scanf_s("%d", &num); ptr = (int*)malloc(num * sizeof(int)); for (i = 0; i < num; i++) { printf("请录入第%d个整数:", i + 1); scanf_s("%d", &ptr[i]); } printf("The number you scanf is:"); for (i = 0; i < num; i++) { printf("%d ", ptr[i]); } putchar('\n'); free(ptr); return 0; }
#include <stdio.h> #include <stdlib.h> int main() { int* ptr; ptr = (int*)malloc(sizeof(int)); if (ptr == NULL) { printf("It's wrong!分配内存失败!\n"); exit(1); } printf("please input a number:"); scanf_s("%d", ptr); printf("The number is:%d\n", *ptr); free(ptr); //释放掉地址后变为非法空间,所以不会打印出任何东西。 printf("The number is:%d\n", *ptr); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int* ptr1 = NULL; int* ptr2 = NULL; //第一次申请的内存空间 ptr1 = (int*)malloc(10 * sizeof(int)); //第一次申请的内存空间不够用 //第二次申请内存空间 ptr2 = (int*)malloc(20 * sizeof(int)); //将ptr1的数据拷贝到ptr2中,memcpy是拷贝,在头文件string.h中 memcpy(ptr2, ptr1, 10); free(ptr1); //对ptr2申请的空间做了操作之后 free(ptr2); return 0; }
free
void free(void *ptr)
用来释放ptr参数指向的内存空间,必须是由malloc、calloc或relloc函数申请的。
如果ptr参数是NULL,则不执行任何操作
注意:该函数不会修改ptr参数的值,所以调用后它仍指向原来的地方(变为非法空间)
内存泄漏
1、隐式内存泄漏:用完内存块没有及时用free释放
2、丢失内存块地址
#include <stdio.h> #include <stdlib.h> int main(void) { //没有释放内存空间导致系统崩溃。(内存泄漏) while(1) { malloc(1024); } return 0; }
#include <stdio.h> #include <stdlib.h> int main() { int* ptr; int num = 123; ptr = (int*)malloc(sizeof(int)); if (ptr == NULL) { printf("It's wrong!分配内存失败!\n"); exit(1); } printf("please input a number:"); scanf_s("%d", ptr); printf("The number is:%d\n", *ptr); //这里把num的地址放到了ptr里面导致前面使用malloc申请的内存块丢失 ptr = # printf("The number is:%d\n", *ptr); //这里相当于直接对局部变量进行了位释放 free(ptr); return 0; }
calloc
void *calloc(size_t, size_t size);
calloc函数在内存中动态地申请nmemb个长度为size的连续内存空间(空间总尺寸为nmemb * size),而且全部初始化为0,相当于malloc加上memset。
而malloc函数不进行初始化操作,里面的数据是随机的
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 10 int main() { int* ptr = NULL; int i; /* int* ptr = (int*)calloc(8, sizeof(int)); == int* ptr = (int*)malloc(8 * sizeof(int)); memset(ptr, 0, 8 * sizeof(int)); */ ptr = (int*)malloc(N * sizeof(int)); if (ptr == NULL) { exit(1); } //memset 函数使用常量字节c填充s指向的前n个字节,在string头文件里面 //void* memset(void* s, int c, size_t n); //这里作用貌似就是用0填充一个用malloc创造出空间的ptr数组(数组内一共有十个全是0的元素) memset(ptr, 0, N * sizeof(int)); for (i = 0; i < N; i++) { printf("%d ", ptr[i]); } putchar('\n'); // 运行结果是0 0 0 0 0 0 0 0 0 0 free(ptr); return 0; }
realloc
void *realloc(void *ptr, size_t size);
realloc函数修改ptr指向的内存空间大小为size字节
如果新分配的内存空间比原来的打,则就内存块的数据不会发生改变;但是如果新的内存空间大小小于旧的内存空间,可能会导致数据丢失,慎用!
该函数将移动内存空间的数据并返回新的指针
#include <stdio.h> #include <stdlib.h> int main() { int i, num; int count = 0; int* ptr = NULL; // 注意这里必须初始化为NULL do { printf("please scanf a int(输入-1表示结束):"); scanf("%d", &num); count++; /* 如果ptr参数是NULL,调用该函数相当于调用malloc(size) 如果size参数为0,并且ptr参数不为NULL,那么调用该函数相当于调用free(ptr) 除非ptr参数为NULL,否则ptr的值必须由先前调用malloc、calloc、realloc函数返回 */ ptr = (int*)realloc(ptr, count * sizeof(int)); if (ptr == NULL) { exit(1); } ptr[count - 1] = num; } while (num != -1); printf("The number you input is :"); for (i = 0; i < count; i++) { printf("%d", ptr[i]); } putchar('\n'); free(ptr); return 0; }
C语言的内存布局
#include <stdio.h> #include <stdlib.h> int global_uninit_var; int global_init_var1 = 520; int global_init_var2 = 880; void func(void); void func(void) { ; } int main() { int local_var1; int local_var2; static int static_uninit_var; static int static_init_var = 456; char* str1 = "I love Fishc.com!"; char* str2 = "You are right!"; int* malloc_var = (int*)malloc(sizeof(int)); printf("addr of func -> %p\n", &func); printf("addr of str1 -> %p\n", &str1); printf("addr of str2 -> %p\n", &str2); printf("addr of global_init_var1 -> %p\n", &global_init_var1); printf("addr of global_init_var2 -> %p\n", &global_init_var2); printf("addr of static_init_var -> %p\n", &static_init_var); printf("addr of static_uninit_var -> %p\n", &static_uninit_var); printf("addr of global_uninit_var -> %p\n", &global_uninit_var); printf("addr of malloc_var -> %p\n", &malloc_var); printf("addr of local_var1 -> %p\n", &local_var1); printf("addr of local_var2 -> %p\n", &local_var2); /* addr of func -> 006313A7 addr of str1 -> 007DFB10 addr of str2 -> 007DFB04 addr of global_init_var1 -> 0063A034 addr of global_init_var2 -> 0063A038 addr of static_init_var -> 0063A03C addr of static_uninit_var -> 0063A13C addr of global_uninit_var -> 0063A46C addr of malloc_var -> 007DFAF8 addr of local_var1 -> 007DFB28 addr of local_var2 -> 007DFB1C */ return 0; }
C++
动态申请内存操作符new
new 类型名T(初始化参数列表)
- 功能:
在程序执行期间,申请用于存放T类型对象的内存空间,并依初值列表赋以初值。 - 结果值:
成功:T类型的指针,指向新分配的内存; 失败:抛出异常。
释放内存操作符delete
delete 指针p
- 功能:释放指针p所指向的内存。
p必须是new操作的返回值
#include <iostream> using namespace std; class Point { public: Point() :x(0), y(0) { cout << "Default Constructor called." << endl; } Point(int x, int y) :x(x), y(y) { cout << "Constructor called." << endl; } ~Point() { cout << "Destructor called." << endl; } int getX()const { return x; } int getY()const { return y; } void move(int newX, int newY) { x = newX; y = newY; } private: int x, y; }; int main() { cout << "Step one: " << endl; Point* ptr1 = new Point; // 调用默认构造函数 delete ptr1; // 删除对象,自动调用析构函数 cout << "Step two: " << endl; ptr1 = new Point(1, 2); delete ptr1; return 0; } /* Step one: Default Constructor called. Destructor called. Step two: Constructor called. Destructor called. */
分配和释放动态数组
- 分配:new类型名T{数组长度}
数组长度可以是任何整数类型表达式,在运行时计算 - 释放:delete[] 数组名p
释放指针p所指向的数组。
p必须是用new分配得到的数组首地址。
#include <iostream> using namespace std; class Point { public: Point() :x(0), y(0) { cout << "Default Constructor called." << endl; } Point(int x, int y) :x(x), y(y) { cout << "Constructor called." << endl; } ~Point() { cout << "Destructor called." << endl; } int getX()const { return x; } int getY()const { return y; } void move(int newX, int newY) { x = newX; y = newY; } private: int x, y; }; int main() { Point* ptr = new Point[2]; // 创建对象数组 ptr[0].move(5, 10); // 通过指针访问数组元素的成员 ptr[1].move(15, 20); // 通过指针访问数组元素的成员 cout << "Deleting..." << endl; delete[] ptr; // 删除整个对象数组(用两个方括号,用两个能释放两个内存空间,只用一个只释放一个内存空间,导致内存泄漏) return 0; } /* Default Constructor called. Default Constructor called. Deleting... Destructor called. Destructor called. */
动态创建多维数组
new 类型名T[第1维长度][第2维长度]...;
- 如果内存申请成功,new运算返回一个指向新分配内存首地址的指针。
- 例如:
char(*fp)[3]; fp = new char[2][3];
#include <iostream> using namespace std; int main() { // cp是指向数组(二维数组)的指针,多维数组去掉第一维的下标个数 int(*cp)[9][8] = new int[7][9][8]; for (int i = 0; i < 7; i++) for (int j = 0; j < 9; j++) for (int k = 0; k < 8; k++) *(*(*(cp + i) + j) + k) = (i * 100 + j * 10 + k); for (int i = 0; i < 7; i++) { for (int j = 0; j < 9; j++) { for (int k = 0; k < 8; k++) cout << cp[i][j][k] << " "; cout << endl; } cout << endl; } delete[]cp; return 0; }
#include <iostream> #include <cassert> using namespace std; class Point { public: Point() :x(0), y(0) { cout << "Default Constructor called." << endl; } Point(int x, int y) :x(x), y(y) { cout << "Constructor called." << endl; } ~Point() { cout << "Destructor called." << endl; } int getX()const { return x; } int getY()const { return y; } void move(int newX, int newY) { x = newX; y = newY; } private: int x, y; }; class ArrayOfPoints { // 动态数组类 public: ArrayOfPoints(int size) : size(size) { points = new Point[size]; } ~ArrayOfPoints() { cout << "Deleteing..." << endl; delete[] points; } Point& element(int index) { assert(index >= 0 && index < size); return points[index]; } private: Point* points; // 指向动态数组首地址 int size; // 数组大小 }; int main() { int count; cout << "Please enter the count of points: "; cin >> count; ArrayOfPoints points(count); // 创建数组对象 points.element(0).move(5, 0); // 访问数组元素的成员 points.element(1).move(15, 20); // 访问数组元素的成员 return 0; } /* Please enter the count of points: 2 Default Constructor called. Default Constructor called. Deleteing... Destructor called. Destructor called. */
vector
为什么需要vector?
- 封装任何类型的动态数组,自动创建和删除。
- 数组下标越界检查。
vector对象的定义vector<元素类型> 数组对象名(数组长度);
例:vector<int> arr(5) 建立大小为5的int数组
#include <iostream> #include <vector> using namespace std; double average(const vector <double>& arr) { double sum = 0; for (unsigned i = 0; i < arr.size(); i++) sum += arr[i]; return sum / arr.size(); } int main() { unsigned n; cout << "n = "; cin >> n; vector<double>arr(n); // 创建数组对象 cout << "Please input " << n << "real numbers: " << endl; for (unsigned int i = 0; i < n; i++) cin >> arr[i]; cout << "Average = " << average(arr) << endl; return 0; }
#include <iostream> #include <vector> using namespace std; int main() { std::vector<int>v = { 1, 2, 3 }; for (auto i = v.begin(); i != v.end; ++i) std::cout << *i << std::endl; for (auto e : v) std::cout << e << std::endl; return 0; }
浅层复制
- 实现对象间数据元素的一一对应复制。
不能复制指针(当这个指针指向的空间是用动态内存分配的空间)
深层复制
- 当被复制的对象数据成员是指针类型时,不是复制该指针成员本身,而是将指针所指对象进行复制。(需要开辟新的动态内存空间)
#include <iostream> #include <cassert> using namespace std; class Point { public: Point() :x(0), y(0) { cout << "Default Constructor called." << endl; } Point(int x, int y) :x(x), y(y) { cout << "Constructor called." << endl; } ~Point() { cout << "Destructor called." << endl; } int getX()const { return x; } int getY()const { return y; } void move(int newX, int newY) { x = newX; y = newY; } private: int x, y; }; class ArrayOfPoints { // 动态数组类 public: // 在这里创建一个复制构造函数,不适用默认的构造函数 ArrayOfPoints(const ArrayOfPoints& pointsArray); ArrayOfPoints(int size) : size(size) { points = new Point[size]; } ~ArrayOfPoints() { cout << "Deleteing..." << endl; delete[] points; } Point& element(int index) { assert(index >= 0 && index < size); return points[index]; } private: Point* points; // 指向动态数组首地址 int size; // 数组大小 }; ArrayOfPoints::ArrayOfPoints(const ArrayOfPoints& v) { size = v.size; // size的值可以直接复过来 points = new Point[size]; // 指针的不能直接,要开辟新的空间 for (int i = 0; i < size; i++) points[i] = v.points[i]; } int main() { int count; cout << "Please enter the count of points: "; cin >> count; ArrayOfPoints pointsArray1(count); // 创建对象数组 pointsArray1.element(0).move(5, 10); pointsArray1.element(1).move(15, 20); ArrayOfPoints pointsArray2(pointsArray1); // 创建副本,使用的是默认的复制构造函数,只能复制地址,所以在析构的时候使用了两次delete导致出错 cout << "Copy of pointArray1:" << endl; cout << "Point_0 of array2: " << pointsArray2.element(0).getX() << ", " << pointsArray2.element(0).getY() << endl; cout << "Point_1 of array2: " << pointsArray2.element(1).getX() << ", " << pointsArray2.element(1).getY() << endl; pointsArray1.element(0).move(25, 30); pointsArray2.element(1).move(35, 40); cout << "After the moving of pointsArray1:" << endl; cout << "Point_0 of array2: " << pointsArray2.element(0).getX() << ", " << pointsArray2.element(0).getY() << endl; cout << "Point_1 of array2: " << pointsArray2.element(1).getX() << ", " << pointsArray2.element(1).getY() << endl; return 0; } /* Please enter the count of points: 2 Default Constructor called. Default Constructor called. Default Constructor called. Default Constructor called. Copy of pointArray1: Point_0 of array2: 5, 10 Point_1 of array2: 15, 20 After the moving of pointsArray1: Point_0 of array2: 5, 10 Point_1 of array2: 35, 40 Deleteing... Destructor called. Destructor called. Deleteing... Destructor called. Destructor called. */