【C语言数据结构】数组

简介: 【C语言数据结构】数组


【C语言数据结构】:数组

数组本质上只是编译器在内存空间上开辟的【一连串的内存】

而代表数组的【变量】其实只是这一连串内存空间的【第一个元素的内存地址】。

所以当你给编译器看一个数组时,他并不是像人一样能看到这个数组的全貌,他只能看到这个数组的第一个元素,并且知道这个元素的内存地址。

【看了这段话很蒙圈?问题不大!接着看下去就行了】


一、定义数组

数组的普通定义非常简单,你只需要这样

int numList[10];

就可以定义一个【含有10个空间大小的整型数组】,里面可以存放十个整型元素。

在刚定义并未初始化的时候,你可以理解为里面什么都没有,是空的,就像你拿了一个袋子,里面没有装东西一样。


1. 【延伸知识】数组的理解

毕竟数组你们在学C语言的时候也都学了,那么我们再学数据结构的时候,肯定还需要再深入一点点的

当然上面这个例子不是十分恰当,或许这个例子更好一点:

在你们学校开会的时候,【第一排的座位】规定只能由【领导】坐

这个【第一排座位】就可以理解为这个【数组】,有【10个座位】就是数组的【长度为10】,【领导】就是这个【int类型】。

如果这个你还不理解,那就…那就…去看视频理解吧 [手动狗头]


2. 【延伸知识】数组的初始元素

当然了,虽然可以理解为空的

但是其实不是空的,他是由数组长度个(上面的数组就是10个)自由内存地址组成,诶,你别不信,我们可以打印一下试试,看看我说的到底是真的还是假的。

#include <stdio.h>
int main()
{
    int a[10];
    for (int i=0;i<10;i++)
    {
        printf("%d\n", a[i]);
    }
}

看到这,可能有些Java选手受不了了,明明没有定义,你就打印,肯定会报错的!

pass:Java中需要定义,声明

但是会吗?很明显是不会的,它是有元素的

打印结果:

1997818734
0
1
44
7673468
6422376
4200059
4199952
0
44


二、数组的类型强制

——带着问题学知识——

  1. 下标取值是怎么做到的?
  2. 下标为什么从0开始?
  3. 为什么数组会强制类型?

————————————


【p1】下标取值是怎么做到的?

我们知道,数组其实是在内存空间中开辟的一串连续的内存地址,而在编译器中只有数组第一个元素的内存地址。

【下标】,其实是在操作数组第一个元素的内存地址,令其【加下标】,就能得到第【几个】元素。

我们假设第一个数组元素的内存地址为:00000001(不要当真),而这个数组变量为【a】(数组为整型),那么【a[0]】,其实就是令这个内存地址【+0】,得到第一个元素的内存地址,再得到这个内存地址所存储的值。

而因为这个数组是整型数组,而整型在内存中占用4个字节,所以,第二个元素应该这么表示:【a[1] =》(00000001+(1*4))】 得到第二个元素的内存地址,再得到第二个元素。


展示数组的地址与数组第一个元素的地址相同

#include <stdio.h>
int main(int argc, char const *argv[])
{
    int a[] = {1, 2, 3, 4};     // 一个数组
    printf("a的内存地址%p\na[0]的内存地址%p", &a, &a[0]);
    return 0;
}

运行结果:

a的内存地址0061FEC0
a[0]的内存地址0061FEC0


【p2】下标为什么从0开始?

想必看完上面的问题,你也对这个问题有了认知。

因为数组的内存实际上是第一个元素的内存,而通过下标进行计算是需要对内存地址进行相加操作的,所以就必须从0开始。


【p3】为什么数组需要强制类型?

看看刚刚的式子:【a[1] =》(00000001+(1*4))】 转成通用的式子就是:

数组第一个元素的内存地址+(下标*类型在内存中所占用的字节数)

所以数组要强制类型。

这个内存地址在C语言中,是可以通过【&】直接取到的,有兴趣的,可以通过这个符号去对数组进行一些操作。

比如:

#include <stdio.h>
int main()
{
    int a[10];
    for (int i=0;i<10;i++)
    {
        printf("%p\n", &(a[i]));
    }
}

自己打印一下看看数组的内存地址看看是不是相邻的,看看相邻是不是4

运行结果:

0061FEA4
0061FEA8
0061FEAC
0061FEB0
0061FEB4
0061FEB8
0061FEBC
0061FEC0
0061FEC4
0061FEC8


三、数组使用

增改查的操作。

增其实也是在未初始化的时候,,,而不是长度增加。

数组在使用的时候,切忌要记得数组的长度,不要超出数组长度,会报错的。


1. 增

遍历赋值的操作

#include <stdio.h>
int main()
{
    int a[10];
    for (int i=0;i<10;i++)
    {
        a[i] = i;
        printf("元素的内存地址:%p\n\n元素的值:%d\n", &(a[i]), a[i]);
    }
}

运行结果:将0-9的值放进数组中

元素的内存地址:0061FEA4
元素的值:0
元素的内存地址:0061FEA8
元素的值:1
元素的内存地址:0061FEAC
元素的值:2
元素的内存地址:0061FEB0
元素的值:3
元素的内存地址:0061FEB4
元素的值:4
元素的内存地址:0061FEB8
元素的值:5
元素的内存地址:0061FEBC
元素的值:6
元素的内存地址:0061FEC0
元素的值:7
元素的内存地址:0061FEC4
元素的值:8
元素的内存地址:0061FEC8
元素的值:9


2. 改

因为定义的时候,数组不是空的,也是有元素的,我们在进行我们的操作的时候,就将原来的值替换掉了,这个改也是同样的道理,其原理还是通过下标。


3. 查

通过下标查找某个元素

#include <stdio.h>
int main()
{
    int a[10];
    for (int i=0;i<10;i++)
    {
        a[i] = i;
        printf("元素的内存地址:%p\n元素的值:%d\n\n", &(a[i]), a[i]);
    }
}

再说别的就是数组的相关算法了,什么二分枚举,双指针,三分枚举…


四、练习题

学编程,最忌讳的就是光看不练,动起来,做点题


p1 数组串联

给你一个长度为 n 的整数数组 nums 。请你构建一个长度为 2n 的答案数组 ans ,数组下标 从 0 开始计数 ,对于所有 0 <= i < n 的 i ,满足下述所有要求:

ans[i] == nums[i]

ans[i + n] == nums[i]

具体而言,ans 由两个 nums 数组 串联 形成。

返回数组 ans 。

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/concatenation-of-array

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


p2 基于排列构建数组

给你一个 从 0 开始的排列 nums(下标也从 0 开始)。请你构建一个 同样长度 的数组 ans ,其中,对于每个  i(0 <= i < nums.length),都满足 ans[i] = nums[nums[i]] 。返回构建好的数组 ans 。

从 0 开始的排列 nums 是一个由 0 到 nums.length - 1(0 和 nums.length - 1 也包含在内)的不同整数组成的数组。

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/build-array-from-permutation

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


p3 执行操作后的变量值

存在一种仅支持 4 种操作和 1 个变量 X 的编程语言:

++X 和 X++ 使变量 X 的值 加 1

–X 和 X-- 使变量 X 的值 减 1

最初,X 的值是 0

给你一个字符串数组 operations ,这是由操作组成的一个列表,返回执行所有操作后, X 的 最终值 。

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/final-value-of-variable-after-performing-operations

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

关注下方公众号,领取更多福利
    - python基础教程
    - python知识脑图
    - python入门100例
    - C语言数据结构教程
    - C语言算法100题


目录
相关文章
|
20天前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
30 1
|
29天前
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
44 4
|
29天前
|
存储 机器学习/深度学习 搜索推荐
【趣学C语言和数据结构100例】86-90
本文介绍并用C语言实现了五种经典排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序。每种算法都有其特点和适用场景,如直接插入排序适合小规模或基本有序的数据,快速排序则适用于大规模数据集,具有较高的效率。通过学习这些算法,读者可以加深对数据结构和算法设计的理解,提升解决实际问题的能力。
43 4
|
29天前
|
存储 算法 数据处理
【趣学C语言和数据结构100例】81-85
本文介绍了五个经典算法问题及其C语言实现,涵盖图论与树结构的基础知识。包括使用BFS求解单源最短路径、统计有向图中入度或出度为0的点数、统计无向无权图各顶点的度、折半查找及二叉排序树的查找。这些算法不仅理论意义重大,且在实际应用中极为广泛,有助于提升编程能力和数据结构理解。
38 4
|
29天前
|
算法 数据可视化 数据建模
【趣学C语言和数据结构100例】76-80
本文介绍了五种图论算法的C语言实现,涵盖二叉树的层次遍历及广度优先搜索(BFS)和深度优先搜索(DFS)的邻接表与邻接矩阵实现。层次遍历使用队列按层访问二叉树节点;BFS利用队列从源节点逐层遍历图节点,适用于最短路径等问题;DFS通过递归或栈深入图的分支,适合拓扑排序等场景。这些算法是数据结构和算法学习的基础,对提升编程能力和解决实际问题至关重要。
45 4
|
29天前
|
存储 算法 vr&ar
【趣学C语言和数据结构100例】71-75
本文介绍了五个C语言数据结构问题及其实现,涵盖链表与二叉树操作,包括按奇偶分解链表、交换二叉树左右子树、查找节点的双亲节点、计算二叉树深度及求最大关键值。通过递归和遍历等方法,解决了理论与实际应用中的常见问题,有助于提升编程能力和数据结构理解。
36 4
|
29天前
|
存储 算法 C语言
【趣学C语言和数据结构100例】66-70
本书《趣学C语言和数据结构100例》精选了5个典型的数据结构问题及C语言实现,涵盖链表与数组操作,如有序集合的集合运算、有序序列表的合并、数组中两顺序表位置互换、三递增序列公共元素查找及奇偶数重排。通过详细解析与代码示例,帮助读者深入理解数据结构与算法设计的核心思想,提升编程技能。
32 4
|
29天前
|
存储 算法 C语言
【趣学C语言和数据结构100例】51-55
本文介绍了五个关于链表操作的C语言实现案例,包括删除单链表中的重复元素、从两个有序链表中查找公共元素、判断一个链表是否为另一链表的连续子序列、判断循环双链表是否对称及合并两个循环单链表。每个案例都详细解析了算法思路与实现方法,涵盖了链表操作的多种场景,旨在帮助读者深入理解链表数据结构的应用,提升算法设计与编程能力。
39 4
|
18天前
|
传感器 算法 安全
【C语言】两个数组比较详解
比较两个数组在C语言中有多种实现方法,选择合适的方法取决于具体的应用场景和性能要求。从逐元素比较到使用`memcmp`函数,再到指针优化,每种方法都有其优点和适用范围。在嵌入式系统中,考虑性能和资源限制尤为重要。通过合理选择和优化,可以有效提高程序的运行效率和可靠性。
62 6
|
21天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
43 5