【C语言】数组

本文详细介绍了数组的概念、定义、元素访问与查找方法,包括线性查找与二分查找,以及二维数组和数组指针、指针数组的区别。同时涵盖了如何在函数中传递数组和指针作为参数,以及注意事项。
摘要由CSDN通过智能技术生成

目录

1、概念

2、数组定义

3、读取元素

4、查找元素

5、二维数组

 6、数组指针与指针数组

7、函数传参


1、概念

        数组是一种数据结构,用于存储相同类型的元素序列。它是一组连续的内存空间,每个元素都有一个唯一的索引(下标),可以通过索引来访问或操作数组中的元素。

数组的特点包括:

  1. 相同类型的元素: 数组中的所有元素必须是相同的数据类型,例如整数数组、浮点数数组、字符数组等。
  2. 连续的内存空间: 数组中的元素在内存中是连续存储的,这也是数组高效访问的原因之一。
  3. 固定大小: 数组一旦定义大小,在程序运行时其大小通常不会改变。C语言中的数组大小必须是一个常量表达式。
  4. 索引访问: 数组中的元素通过索引(下标)来访问,索引从0开始递增。例如,第一个元素的索引为0,第二个元素的索引为1,依此类推。

        需要注意的是,数组在定义时需要指定其大小,因此在使用时要确保不超出数组范围,否则可能导致内存访问错误。

2、数组定义

定义数组的语法如下:

type arrayName[arraySize];

(1)type:表示数组元素的数据类型,可以是整数类型(如 intlong)、浮点数类型(如 floatdouble)、字符类型(如 char)等。

(2)arrayname:数组的名称。 

(3)arraySize:数组的大小,即数组可以容纳的元素数量,必须是一个整数常量表达式。

        如果不指定初始值,则数组中的元素会被默认初始化。例如,整型数组中的元素会被初始化为0,字符数组中的元素会被初始化为空字符(\0)。

        数组的大小必须是一个常量表达式,这意味着在定义数组时不能使用变量来指定数组大小,例如 int size = 5; int numbers[size]; 是错误的写法。

3、读取元素

        在计算机中,内存可以看成是一些已经排列好的格子,每个格子对应一个内存地址。一般情况下,数据会分散地存储在不同的格子中。

        而对于数组,计算机会在内存中为其申请一段连续的空间,并且会记下索引为0处的内存地址。以数组{"C","S","D","N"}为例,它的各元素对应的索引及内存地址如下图所示:

假如,我们想要访问索引为2处的元素"D"时,计算机会进行以下计算:

  1.  找到该数组的索引0的内存地址:2008;
  2. 将内存地址加上索引值,作为目标元素的地址,即2008 + 2 = 2010,对应的元素为"D",这时便找到了目标元素。

        计算内存地址这个过程是很快的,而我们一旦知道了内存地址就可以立即访问到该元素,因此它的时间复杂度是常数级别,为O(1)

【常数级别的时间复杂度表示算法的执行时间不随输入规模的增加而增加,这意味着算法中的基本操作次数是固定的,与输入规模无关。】

4、查找元素

        假如我们对数组中包含哪些元素并不了解,只是想知道其中是否包含元素"D",数组会如何查找该元素呢?

        由于我们只保存了索引为0处的内存地址,因此在查找元素时,只需从数组开头逐步向后查就可以了。如果数组中的某个元素为目标元素,则停止查找;否则继续搜索直到到达数组的末尾。

        如上方法属于线性查找(顺序查找),最坏的情况是查找整个数组,此时时间复杂度为O(n),其中 n 是数组的大小。

        如果是利用二分查找方法,则时间复杂度为O(log n)。这种算法适用于有序数组,通过每次将查找范围缩小一半来进行查找,因此在大规模数据中具有较高的效率。

        简单讲一下二分查找方法:

基本步骤:

  1. 首先,确定查找范围的左右边界,通常初始时为数组的第一个元素和最后一个元素。
  2. 然后,计算中间元素的索引,并将中间元素与目标元素进行比较。
  3. 如果中间元素等于目标元素,则查找成功,返回中间元素的索引。
  4. 如果中间元素大于目标元素,则目标元素可能在左半部分,更新右边界为中间元素的前一个位置。
  5. 如果中间元素小于目标元素,则目标元素可能在右半部分,更新左边界为中间元素的后一个位置。
  6. 重复上述步骤,直到找到目标元素或左右边界重合(查找失败)。

时间复杂度分析:

  1. 每次比较后,查找范围缩小一半,因此二分查找的时间复杂度为 O(log n),其中 n 是数组的大小。
  2. 每次比较的过程可以看作是一次对数运算,因此时间复杂度是对数级别的增长。

        数组的插入元素和删除元素频繁使用会造成时间的浪费。我们通常使用链表进行这些操作,在这里就不细讲了。

5、二维数组

        二维数组是一种结构较为特殊的数组,只是将数组中的每个元素都变成了一维数组。

 所以二维数组的本质上仍然是一个一维数组,内部的一维数组仍然从索引0开始,我们可以将它看作是一个矩阵。

 6、数组指针与指针数组

数组指针

        数组指针是指向数组的指针,它指向整个数组而不是数组中的单个元素。数组指针的声明通常如下所示:

type (*ptrName)[arraySize];

(1)ptrName:指针变量的名称。

(2)type:数组元素的类型。

(3)arraySize:数组的大小。

指针数组

        指针数组是一个数组,其中的每个元素都是指针。这些指针可以指向不同的变量或对象。指针数组的声明通常如下所示:

type *ptrArray[arraySize];

(1)ptrArray:数组的名称。

(2)type:指针所指向的变量的类型。

(3)arraySize:数组的大小。

区别

数组指针:是指向整个数组的指针,它指向数组的首地址,可以通过指针来访问整个数组。

指针数组:一个包含指针的数组,每个指针可以指向不同的变量或对象。

7、函数传参

传递数组名

        在函数声明中,可以直接将数组名作为参数,此时实际上传递的是数组的地址,即数组的第一个元素的地址。函数内部可以通过指针访问整个数组。示例代码如下:

#include <stdio.h>

// 函数声明:使用数组名作为参数
void print_array(int arr[], int size) 
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() 
{
    int numbers[] = {1, 2, 3, 4, 5};
    int size = sizeof(numbers) / sizeof(numbers[0]);

    print_array(numbers, size); // 调用函数并传递数组名和大小作为参数
    return 0;
}

传递指针作为参数

        除了直接传递数组名之外,还可以将指向数组的指针作为函数参数传递。这种方式也非常常见,需要注意的是,在函数内部需要使用指针的方式来访问数组元素。示例代码如下:

#include <stdio.h>

// 函数声明:使用指针作为参数
void print_array(int *arr, int size) 
{
    for (int i = 0; i < size; i++) 
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return ;
}

int main()
{
    int numbers[] = {1, 2, 3, 4, 5};
    int size = sizeof(numbers) / sizeof(numbers[0]);

    print_array(numbers, size); // 调用函数并传递数组的指针和大小作为参数
    return 0;
}

注意:

  1. 无论是使用数组名还是指针作为函数参数,都需要传递数组的大小,因为在函数内部无法直接获取数组的大小。
  2. 在函数内部可以通过下标或指针来访问数组元素,并对数组进行操作。
  3. 在函数声明中,使用数组名作为参数时,可以省略数组的大小,但使用指针作为参数时,需要明确指定指针的类型。
  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力学代码的小信

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值