动态分配内存
头文件:stdlib.h
void *malloc(int size);
:在堆区分配一块指定大小的内存空间,这块内存空间在函数执行完成后不会被初始化,它们的值是未知的void *calloc(int len, int size);
:在堆区分配一块len*size大小的内存空间,并且每个字节都初始化为0void *realloc(void *ptr, int newsize);
:重新分配内存,把内存扩展到newsizevoid free(void *ptr);
:释放指针ptr所指向的内存块
对于void *realloc(void *ptr, int newsize);
:
- 指针ptr必须是在动态内存空间分配成功的指针
- 如果ptr为NULL,效果同malloc()
- 如果newsize为0,效果同free()
成功分配内存后ptr将被系统回收,一定不可再对ptr指针做任何操作,包括free
- 如果是扩大内存操作会把ptr指向的内存中的数据复制到新地址(新地址也可能会和原地址相同,但依旧不能对原指针进行任何操作)
- 如果是缩小内存操作,原始据会被复制并截取新长度
- 分配成功返回新的内存地址,可能与ptr相同,也可能不同;失败则返回NULL
- 如果分配失败,ptr指向的内存不会被释放,它的内容也不会改变,依然可以正常使用
在定义数组的时候,我们必须事先定好数组的长度,并且不能再改变长度
而使用动态内存分配,可以做到所谓的动态数组,在运行时确定数组长度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int *arr = (int *)malloc(sizeof(int) * (argc-1));
for(int i=1; i<argc; i++){
int value = atoi(argv[i]);
arr[i-1] = value;
}
for(int i=0; i<argc-1; i++){
printf("arr[%d] = %d\n", i, arr[i]);
}
free(arr);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
$ gcc a.c
$ ./a.out 1 2 3 4 5 6 7 8 9 10
arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
arr[4] = 5
arr[5] = 6
arr[6] = 7
arr[7] = 8
arr[8] = 9
arr[9] = 10
memset()、memcpy()、memmove()、strcpy()
头文件:string.h
void *memset(void *buffer, int c, int len);
把buffer所指内存区域的前len个字节设置成字符c
经常用来初始化基本数据类型、结构体等,因为比用for循环快多了
void *memcpy(void *dest, void *src, int len);
由src所指内存区域复制len个字节到dest所指内存区域
src和dest所指内存区域不能重叠,函数返回指向dest的指针,可以拿它拷贝任何数据类型的对象
void *memmove(void *dest, void *src, int len);
它与memcpy的功能相似,都是将src所指的len个字节复制到dest所指的内存地址的起始位置
不同的是它处理了src和dest有重叠的情况,当目标区域与源区域没有重叠则和memcpy函数功能相同
char *strcpy(char *dest, char *src);
把src所指由NULL结束的字符串复制到dest所指的数组中
src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,返回指向dest的指针
字符串赋值
定义一个字符串可以用一个字符数组:如字符串”Google”可以表示为char str[7] = {'G', 'o', 'o', 'g', 'l', 'e'};
但是这样也太麻烦了,所以c语言允许这样简写:char str[] = {"Google"};
或者char str[] = "Google";
但是只有在初始化的时候才能这么干,如果在赋值的时候,只能一个一个字符赋值!
因为在赋值的时候,对于str = "Google";
,”Google”实际是一个char *
类型的字符串常量,存储在代码区,而str则是char [7]
类型的变量,所以编译报错
而对于一个字符指针,有这么几种赋值方式:
char *str = "www.zfl9.com";
对于”www.zfl9.com”,这是一个字符串常量,存储在代码区,因为是常量,所以不能通过指针修改它的值!
char *str = (char *)malloc(sizeof(char) * 50);
strcpy(str, "www.zfl9.com");
第一个语句,申请了50个字节长的堆空间,第二个语句,将存储在代码区的”www.zfl9.com”字符串常量拷贝到刚才申请到的堆内存中,也就是内存的复制
char *str = (char *)malloc(sizeof(char) * 50);
str = "www.zfl9.com";
第一个语句,申请了50个字节长的堆空间,第二个语句,改变这个指针的指向,指向存储在代码区的”www.zfl9.com”
这种方式,会直接把刚才申请的堆内存的地址给弄丢了!搞得不好就会内存溢出,因为那50个字节的内存找不回了!