1.数组的概念
数组(Array):是多个相同类型数据,按照一定顺序排列的集合,并使用一个名字命名,并通过编号方式对这些数据进行统一管理。
- 数组是 C 语言中的一种数据结构,用于存储一组具有相同数据类型的数据。
- 数组中的每个元素可以通过一个索引(下标)来访问,索引从 0 开始,最大值为数组长度减 1。
- 数组是若干个相同类型的变量在内存中有序存储的集合。
2.数组的特点
- 数组中的元素在内存中是依次紧密排列的,有序的。
- 创建数组对象会在内存中开辟一整块连续的空间。占据的空间大小,取决于数组的长度和数组中元素的类型
- 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。
- 数组,一旦初始化完成,其长度就是确定的。数组的长度一旦确定,就不能修改。
- 数组名中引用的是这块连续空间的首地址
3.一维数组的定义
定义数组的语法格式:
类型 数组名[元素个数];
int arr[10];// 数组 arr ,里面包含10个成员,每个成员都是int 类型
或者 #define NUM 10
int arr1[NUM];
- 数组名不能与其他变量名相同,同一作用域内是唯一的
- 其下标从0开始,因此5个元素分别为arr[0] arr[1] arr[2] arr[3] arr[4]
注意:数组角标越界:
假设数组有n个元素,如果使用的数组的下标小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间访问。
C语言不做数组下标越界的检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确。
4.数组内存分析
数组名,记录数组的首地址,即a[0]的地址
数组的各个元素是连续分布的,假如a[0] 地址是0x1122, 则 a[1]的地址=a[0]的地址+int字节数a[1]=0x1126,后面依次类推
注意事项:
c语言规则,数组变量一旦声明,数组名指向的地址就不可更改。因为声明数组时,编译器会自动为数组分配内存地址,这个地址与数组名是绑定的,不可更改。
因此,当数组定义后,再用大括号重新赋值,是不允许的。下面的代码会报错。
5.变长数组
变长数组的根本特征是数组长度只有运行时才能确定 。它的好处是程序员不必在开发时,随意为数组指定一个估计的长度,程序员可以运行时为数组分配精确的长度。
以前的方法是一但定义后就不能改变,要想根据需要处理更多的数据。可以使用以下的方法
动态内存分配:使用malloc、calloc或realloc等函数来动态地分配和重新分配内存。
这允许你在运行时改变内存块(可以看作是一个动态数组)的大小
C库函数<stdlib.h>
size_t是 stdlib.h 中定义的变量类型:
这是无符号整数类型,它是 sizeof 关键字的结果。
void *malloc(size_t size)
分配所需的内存空间,并返回一个指向它的指针。
描述
C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。
声明
下面是 malloc() 函数的声明。
void *malloc(size_t size)
参数
-
size -- 内存块的大小,以字节为单位。
返回值
该函数返回一个指针 ,指向已分配大小的内存。如果请求失败,则返回 NULL。
void *calloc(size_t nitems, size_t size)
描述
C 库函数 void *calloc(size_t nitems, size_t size) 分配所需的内存空间,并返回一个指向它的指针。malloc 和 calloc 之间的不同点是,malloc 不会设置内存为零,而 calloc 会设置分配的内存为零。
注意:calloc() 函数将分配的内存全部初始化为零。如果不需要初始化,可以使用 malloc() 函数代替。另外,使用 calloc() 函数时需要注意,如果分配的内存块过大,可能会导致内存不足的问题。
声明
下面是 calloc() 函数的声明。
void *calloc(size_t nitems, size_t size)
参数
- nitems -- 要被分配的元素个数。
- size -- 元素的大小。
返回值
该函数返回一个指针,指向已分配的内存。如果请求失败,则返回 NULL
realloc()
是 C 标准库中的一个函数,用于重新分配内存空间。它在动态内存管理中非常重要,尤其是在需要调整已分配内存大小的情况下。
C 库函数 void *realloc(void *ptr, size_t size) 尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。
声明
下面是 realloc() 函数的声明:
void *realloc(void *ptr, size_t size)
参数
- ptr -- 指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。
- size -- 内存块的新的大小,以字节为单位。如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。
返回值
- 如果成功,
realloc()
返回指向新内存块的指针。 - 如果失败,返回
NULL
,并且原来的内存块仍然保持不变(并没有释放)。
使用说明
realloc()
可能会将内存块移动到新的位置(如果在原位置没有足够的空间容纳新的大小)。如果移动成功,ptr
会指向新位置。需要特别注意,旧的ptr
指针需要被更新为realloc()
返回的新地址。- 如果内存分配失败,
realloc()
返回NULL
,而原始的内存块不会被释放。为避免内存泄漏,应该使用一个临时指针来接收realloc()
的返回值,并检查是否为NULL
。
free()
描述
在 C 语言中,free()
函数是标准库函数,用于释放由 malloc()
, calloc()
, realloc()
等动态分配函数分配的内存。当动态分配的内存不再需要时,调用 free()
函数可以避免内存泄漏,确保程序有效地管理内存。
声明
下面是 free() 函数的声明。
void free(void *ptr)
参数
- ptr -- 指针指向一个要释放内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果传递的参数是一个空指针,则不会执行任何动作。
返回值
该函数不返回任何值。
6.数组的复制
int a[3]={10,20,30};
int *b;
b=a;
不是将数组a复制给数组b,而是让a和b指向同一个数组
数组的复制只能使用
循环的方法
用memcpy函数
void *memcpy(void *str1, const void *str2, size_t n)
描述
C 库函数(string.h) void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。
声明
下面是 memcpy() 函数的声明。
void *memcpy(void *str1, const void *str2, size_t n)
参数
- str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
- str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
- n -- 要被复制的字节数。
返回值
该函数返回一个指向目标存储区 str1 的指针。
两种方式对比:
1. 循环复制:
优点: 简单直观,容易理解和实现。不需要引入额外的头文件。
缺点:需要编写循环代码来遍历数组并逐个赋值,相对而言可能稍显繁琐。不适用于复制大型数组或复杂数据结构。
2.memery函数复制:
优点:使用标准库提供的函数,可以实现快速且高效的内存复制。适用于大型数组或复杂的数据结构的复制。可以直接复制字节数,不需要遍历数组。
缺点:需要包含头文 件,对于简单的数组复制,可能有些过于繁重。