【C语言】基础语法5:数组和指针

news2024/9/19 10:41:51

上一篇:函数和递归
下一篇:字符串和字符处理

❤️‍🔥前情提要❤️‍🔥
  欢迎来到C语言基本语法教程
  在本专栏结束后会将所有内容整理成思维导图(结束换链接)并免费提供给大家学习,希望大家纠错指正。本专栏将以基础出发,在之后的教程中将会不断学习并详细讲解C语言的基本语法及其高级用法
  上一节讲了C语言基础中的函数和递归,接下来让我们来一起学习C语言中的数组和指针
请添加图片描述
  🍪本教程内容干货满满,跟上步伐吧~🍪


作者介绍

🎓 作者:某不知名编程爱好者📜
🗒️系列文章&专栏推荐: 🔗《华为机试题解析》 、🔗《C语言程序设计》、🔗 《MySQL数据库》
🕸️为大家推荐一款很好用的C语言刷题网站🔗点击跳转


🔖导航小助手🔖

  • 📑 数组和指针
  • 📑 1. 数组
    • 🏷️ 1.1 数组的定义
    • 🏷️ 1.2 数组的使用方法
    • 🏷️ 1.3 数组的初始化
    • 🏷️ 1.4 数组的遍历
    • 🏷️ 1.5 数组的常见问题
  • 📑 2. 指针
    • 🏷️ 2.1 指针的定义
    • 🏷️ 2.2 指针的使用方法
    • 🏷️ 2.3 指针的运算
    • 🏷️ 2.4 指针的关系操作
    • 🏷️ 2.5 指针地址的转换
    • 🏷️ 2.6 指针的应用场景
  • 📑 3. 数组指针
    • 🏷️ 3.1 数组指针的定义
    • 🏷️ 3.2 数组指针和指针数组
    • 🏷️ 3.3 数组指针的应用场景
  • 📑 4. 多维数组
    • 🏷️ 4.1 二维数组的定义
    • 🏷️ 4.2 二维数组的使用方法
    • 🏷️ 4.3 二维数组的初始化
    • 🏷️ 4.4 多维数组的定义和使用
  • 📑 5. 数组和指针在函数中的应用
    • 🏷️ 5.1 数组作为函数的参数
    • 🏷️ 5.2 指针作为函数的参数
    • 🏷️ 5.3 数组指针作为函数的参数
    • 🏷️ 5.4 函数返回指针
  • 📑 6. 数组和指针的高级应用
    • 🏷️ 6.1 动态内存分配
    • 🏷️ 6.2 指向函数的指针
    • 🏷️ 6.3 结构体和指针数组的结合使用
    • 🏷️ 6.4 指令和指针的安全使用
  • ⚠️ 注意事项
    • 🎀小结


📑 数组和指针

  • C语言中数组指针的使用是任何一个程序员必须掌握的基础知识。数组作为一种常用的数据结构,可以用于存储一系列同一类型的数据指针则是C语言中的重要概念之一,它指向一个内存地址,可以用于数据的传递和操作

📑 1. 数组


🏷️ 1.1 数组的定义

  • 在C语言中,数组可以定义为一组相同类型的数据元素的集合。数组中的每个元素都可以通过一个下标访问,下标从0开始计数。数组的定义方式如下:
数据类型 数组名[数组长度];

例如,定义一个长度为10的int类型数组:

int arr[10];

🏷️ 1.2 数组的使用方法

数组的元素可以通过下标来访问,例如:

arr[0] = 1;

上述语句将数组arr的第一个元素赋值为1。数组的元素也可以通过循环来遍历

for (int i = 0; i < 10; i++) {
    arr[i] = i;
}

上述语句将数组arr的元素依次赋值为0~9


🏷️ 1.3 数组的初始化

在定义数组时,可以直接初始化数组元素的值

int arr[5] = {1, 2, 3, 4, 5};

上述语句定义了一个长度为5的int类型数组,并将其元素依次初始化为1~5。


🏷️ 1.4 数组的遍历

数组的遍历可以使用for循环来实现:

for (int i = 0; i < 5; i++) {
    printf("%d ", arr[i]);
}

上述语句将数组arr的所有元素按顺序输出。


🏷️ 1.5 数组的常见问题

数组的下标越界是C语言中常见的问题,使用数组时一定要确保下标不超出数组的范围。另外,数组在作为函数参数传递时会自动转换为指针,这也是需要注意的地方。


📑 2. 指针


🏷️ 2.1 指针的定义

指针是一个存储变量地址的变量。指针的定义方式如下:

数据类型 *指针变量名;

例如,定义一个int类型的指针变量:

int *ptr;

🏷️ 2.2 指针的使用方法

指针可以用于访问修改变量的值,例如:

int a = 10;
int *ptr = &a;
*ptr = 20;

上述语句将变量a的值修改为20。指针也可以通过循环来遍历数组

int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
for (int i = 0; i < 5; i++) {
    printf("%d ", *(ptr+i));
}

上述语句将数组arr的所有元素按顺序输出。


🏷️ 2.3 指针的运算

指针也可以进行加减运算,例如:

int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
printf("%d\n", *(ptr+3));   //输出4

指针也可以自增自减,例如:

int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
ptr++;  //指向arr[1]

🏷️ 2.4 指针的关系操作

指针也可以进行关系运算,例如:

int a = 10;
int b = 20;
int *pa = &a;
int *pb = &b;
if (pa < pb) {
    printf("pa < pb\n");
}
else {
    printf("pa >= pb\n");
}

上述语句将输出"pa < pb",因为指针pa指向的变量a在内存中的地址小于指针pb指向的变量b在内存中的地址。(运行结果可能会不同)


🏷️ 2.5 指针地址的转换

指针地址可以通过强制类型转换变为不同数据类型的指针,例如:

int a = 10;
float *ptr = (float *)&a;
*ptr = 10.5;
printf("%.2f\n", (float)a);

上述语句将输出"10.50",因为将整型变量a的地址强制转换为float型指针后,可以将其看作一个浮点数变量。(运行结果可能会不同)


🏷️ 2.6 指针的应用场景

指针可以用于数据结构动态内存分配等场景中,例如链表等数据结构;以及malloc()free()函数进行动态内存分配等。


📑 3. 数组指针


🏷️ 3.1 数组指针的定义

数组指针指向数组的指针。数组指针的定义方式如下:

数据类型 (*数组指针变量名)[数组长度];

例如,定义一个指向int类型数组的指针:

int arr[5];
int (*ptr)[5] = &arr;

🏷️ 3.2 数组指针和指针数组

数组指针指针数组是两个不同的概念。指针数组是一个数组,其中每个元素都是一个指针。而数组指针一个指向数组的指针

例如,定义一个指针数组和一个数组指针:

int a = 1, b = 2, c = 3;
int *arr[] = {&a, &b, &c};   //指针数组
int arr1[3] = {1, 2, 3};
int (*ptr)[3] = &arr1;   //数组指针

🏷️ 3.3 数组指针的应用场景

数组指针可以用于多维数组访问传递,例如:

int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*ptr)[3] = arr;
for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 3; j++) {
        printf("%d ", *(*(ptr+i)+j));
    }
    printf("\n");
}

上述语句将多维数组arr的所有元素按顺序输出。


📑 4. 多维数组


🏷️ 4.1 二维数组的定义

在C语言中,可以定义多维数组。二维数组是最常见的多维数组。定义一个二维数组的方式如下:

数据类型 数组名[行数][列数];

例如,定义一个3行4列的int类型二维数组:

int arr[3][4];

🏷️ 4.2 二维数组的使用方法

二维数组的元素可以通过索引访问,例如:

int arr[3][4];
arr[0][1] = 1;

上述语句将二维数组arr的第一行第二列的元素赋值为1。


🏷️ 4.3 二维数组的初始化

在定义二维数组时,可以直接初始化数组元素的值

int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};

上述语句定义了一个3行4列的int类型二维数组,并将其元素依次初始化为1~12。


🏷️ 4.4 多维数组的定义和使用

类似地,C语言中还可以定义三维及以上的多维数组,例如:

int arr[2][3][4];
arr[0][1][2] = 1;

上述语句定义了一个2x3x4的int类型的三维数组,并将其第一块的第二行第三列的元素赋值为1。


📑 5. 数组和指针在函数中的应用


🏷️ 5.1 数组作为函数的参数

在函数中,数组可以作为参数传递。定义一个接受数组作为参数的函数的方式如下:

void func(int arr[], int len);

其中,arr是一个int类型的数组,len是数组的长度。


🏷️ 5.2 指针作为函数的参数

指针也可以作为参数传递

void func(int *ptr, int len);

其中,ptr是一个int类型的指针,len是数组的长度。


🏷️ 5.3 数组指针作为函数的参数

数组指针也可以作为参数传递

void func(int (*ptr)[5], int len);

其中,ptr是一个指向int类型数组的指针,len是数组的长度。


🏷️ 5.4 函数返回指针

函数也可以返回指针,例如:

int *func();

上述函数定义了一个返回int类型指针的函数。


📑 6. 数组和指针的高级应用


🏷️ 6.1 动态内存分配

动态内存分配可以通过malloc()函数实现:

int *ptr = malloc(10 * sizeof(int));

上述语句定义了一个长度为10的int类型的动态数组。


🏷️ 6.2 指向函数的指针

指向函数的指针可以通过以下方式定义:

int (*func)();

上述语句定义了一个指向返回int类型的函数的指针。


🏷️ 6.3 结构体和指针数组的结合使用

结构体指针数组可以结合使用来表示复杂的数据结构,并通过指针来进行操作,例如:

struct student {
    char name[20];
    int age;
};
struct student stu_arr[3] = {{"Tom", 18}, {"Jack", 19}, {"Lucy", 20}};
struct student *ptr_arr[3];
for (int i = 0; i < 3; i++) {
    ptr_arr[i] = &stu_arr[i];
}
for (int i = 0; i < 3; i++) {
    printf("%s %d\n", ptr_arr[i]->name, ptr_arr[i]->age);
}

上述语句定义了一个结构体数组,然后将每个元素的地址保存到一个指针数组中,并对每个结构体进行操作。


🏷️ 6.4 指令和指针的安全使用

为了防止指针访问非法内存地址,通过检查指针的值或使用NULL来进行指针的安全使用,例如:

int *ptr = NULL;
if (ptr != NULL) {
    *ptr = 1;
}

上述语句判断指针ptr是否为NULL,如果不是,则进行赋值操作。


⚠️ 注意事项

  • 使用数组时,一定要确保下标不超出数组的范围,否则会出现程序崩溃、数据错误等问题。

  • 使用指针时,一定要确保指针不是空指针,否则会出现程序崩溃的问题,可以使用空指针常量NULL进行判断。

  • 定义指针变量时,一定要对其进行初始化,否则可能指向非法地址,导致程序崩溃。

  • 指针使用完成后,应该及时将其置空,避免误用导致程序出现问题。

  • 数组在作为函数参数传递时会自动转换为指针,此时需要注意指针和数组的区别。

  • 使用malloc()等动态内存分配函数时,一定要释放已分配的内存,避免内存泄漏。

  • 指针类型转换时需要注意数据类型的匹配,否则会出现数据错误。

  • 处理多级指针时,需要注意指针的级别,如二级指针需要使用二级指针变量来存储和传递指针的地址。

对于数组指针的使用,需要掌握基本的概念和语法,同时需要注意数据类型的匹配数据访问的安全性,避免程序出现错误和安全问题。

上一篇:函数和递归
下一篇:字符串和字符处理


🎀小结

本文介绍了C语言中数组和指针的基本概念和用法,并讲解了数组指针多维数组的使用。同时,本文还介绍了数组和指针在函数中的应用,以及动态内存分配指向函数的指针结构体指针数组的结合使用等高级应用。通过本文的学习,读者可以更好地掌握C语言中数组和指针的使用,为后续的程序开发打下基础。

🔚以上就是C语言数组和指针的全部知识了~

🤗感谢大家的阅读~

📬后续还会继续更新💓,欢迎持续关注哟~📌

💫如果有错误❌,欢迎指正呀💫

✨如果觉得收获满满,可以点点赞👍支持一下哟~✨


在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/449145.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#串口通信从入门到精通(4)——串口调试助手的使用

前言: 关于本文中使用到的串口助手工具,订阅专栏后,加入vip群,即可在群文件免费下载 1、认识串口助手 串口助手主要的功能有以下六个模块,功能介绍分别如下: 1.1 打开、关闭串口、清除接收区数据按钮区 这些按钮用于打开串口、关闭串口、清除接收数据区的数据 1.2 …

IIC协议——同步半双工串行通信方式

文章目录 前言一、简要介绍1、优点2、缺点 二、信号线和连接方式1、信号线2、连接方式2.1 单主设备&#xff0c;单从设备2.2 单主设备&#xff0c;多从设备2.3 多主设备&#xff0c;多从设备 三、数据传输格式1、数据传输过程 二、SPI配置1、传输模式2、地址位宽3、仲裁机制3.1…

【Linux】Linux基本指令(1)

一.前言 从这篇文章开始&#xff0c;博主就开启了Linux学习之路了&#xff0c;本篇文章也是博主的第一篇Linux的文章&#xff0c;今后也会持续不断更新的。 二.理解文件 1.文件 文件文件数据文件属性&#xff08;所以一个建好的文件就算没有数据&#xff0c;也占用存储空间&am…

[RoarCTF 2019]Easy Calc、攻防世界 ics07、[极客大挑战 2019]EasySQL

[RoarCTF 2019]Easy Calc 进入题目是一个计算器的功能 检查网页源码发现这样一个重要信息 这题有WAF计算功能是通过calc.php这里面的代码执行的&#xff0c;我们去访问一下得到源码 <?php error_reporting(0); if(!isset($_GET[num])){show_source(__FILE__); }else{$str…

传统机器学习(二)逻辑回归算法(二)

传统机器学习(二)逻辑回归算法(二) 之前在传统机器学习(二)逻辑回归算法(一)中介绍了逻辑回归的原理、公式推导、手动python实现及sklearn工具包的使用详解等内容。继续对逻辑回归的使用细节进行介绍。 一、如何得到逻辑回归模型系数 1.1、一个简单的逻辑回归例子 已采集15…

广州蓝景分享—6 个ES13 中非常实用的新 JavaScript 特性

首先作为前端最重要的编程语言JavaScript&#xff0c;每年都在不断发展&#xff0c;让该语言都会通过新功能变得更强大。今天由小蓝跟大家分享6 个ES13 中非常实用的新 JavaScript 特性。 接下来让我们开始&#xff1a; 1.at 当我们想要获取数组的第 N 个元素时&#xff0c;…

Redis底层设计与源码分析---学习笔记

一.Redis为什么快 高速的存储介质 机械硬盘—>固态硬盘—>内存&#xff0c;随机访问的延迟逐渐变小 优良的底层数据结构设计 底层设计用到了hashtable&#xff0c;时间复杂度低 高效的网络IO模型 epoll等&#xff0c;不同平台有不同的实现   高效的线程模型 二.Re…

【论文阅读笔记|ACL2022】Legal Judgment Prediction via Event Extraction with Constraints

论文题目&#xff1a;Legal Judgment Prediction via Event Extraction with Constraints 论文来源&#xff1a;ACL2022 论文链接&#xff1a;https://aclanthology.org/2022.acl-long.48.pdf 代码链接&#xff1a;GitHub - WAPAY/EPM 0 摘要 近年来&#xff0c;虽然法律判…

动态内存管理--->(经典入手版详解)

友友们有时候在开辟内存的时候&#xff0c;所需要的空间大小不太好确定&#xff0c;只有在程序运行的时候才能知道&#xff0c;这时候我们就要尝试一下动态内存开辟空间了&#xff0c;下面来和阿博一起了解并掌握它吧&#x1f917;&#x1f917;&#x1f917; 文章目录 1.为什么…

系统的部署

把报错的三个给删了&#xff0c;系统可以运行了我猜测它对应的是商品分类页面 我觉得它分页器有问题所以研究了下userdto和mtuser的区别 Failed to parse configuration class [com.fuint.fuintApplication]; nested exception is java.lang.IllegalArgumentException: Could…

Mycat数据库中间件 mycat2 路由转发

1.非分片字段查询 Mycat中的路由结果是通过分片字段和分片方法来确定的。例如下图中的一个Mycat分库方案&#xff1a; 根据 tt_waybill 表的 id 字段来进行分片 分片方法为 id 值取 3 的模&#xff0c;根据模值确定在DB1&#xff0c;DB2&#xff0c;DB3中的某个分片 非分片字段…

ESP32设备驱动-LPS25H压阻式压力传感器驱动

LPS25H压阻式压力传感器驱动 文章目录 LPS25H压阻式压力传感器驱动1、LPS25H介绍2、硬件准备3、软件准备4、驱动实现1、LPS25H介绍 LPS25H 是一款超紧凑型绝对压阻式压力传感器。它包括一个单片传感元件和一个能够从传感元件获取信息并向外部世界提供数字信号的 I2C 接口。 传…

leetcode两数、三数、四数之和

如有错误&#xff0c;感谢不吝赐教、交流 文章目录 两数之和题目方法一&#xff1a;暴力两重循环&#xff08;不可取&#xff09;方法二&#xff1a;HashMap空间换时间 三数之和题目方法一&#xff1a;当然是暴力破解啦方法二&#xff1a;同两数之和的原理&#xff0c;借助Has…

工厂管理系统该如何选?5款主流的工厂管理软件全测评!

工厂管理系统该如何选&#xff1f;5款主流的工厂管理软件全测评&#xff01; 阅读本文您将了解&#xff1a;1.工厂管理系统软件是什么&#xff1b;2.五大主流工厂管理系统介绍&#xff1b;3.如何选择工厂管理系统。 一、工厂管理系统软件是什么&#xff1f; 工厂管理系统软件…

SpringBoot整合JUnit--MyBatis--MyBatis-Plus--Druid

文章转自黑马程序员SpringBoot学习笔记,学习网址:黑马程序员SpringBoot2教程 1.整合JUnit ​ SpringBoot技术的定位用于简化开发&#xff0c;再具体点是简化Spring程序的开发。所以在整合任意技术的时候&#xff0c;如果你想直观感触到简化的效果&#xff0c;你必须先知道使用…

SpringBoot项目创建和使用

Idea创建&#xff08;社区版&#xff09; 安装插件 首先找到设置&#xff0c;然后点击插件&#xff0c;在里面搜索 springboot helper 安装好后名字和图标会变为如下&#xff1a; 安装好后就可以开始创建项目了。 创建项目 第一步&#xff1a;打开创建项目面板 上面设置源…

2.2.1服务器百万并发实现

接上节课&#xff0c;上节课中&#xff0c;我们使用了epoll实现了同时监听多个文件描述符&#xff0c;是对IO的管理&#xff0c;也提到了reactor是对事件的管理&#xff0c;那具体来说是怎样的呢&#xff1f;reactor是事件驱动模型&#xff0c;也就是EPOLLIN/EPOLLOUT&#xff…

arm64 页表以及映射分析

arm64 页表映射分析 1 linux 6.10 xilinx内核的内存配置2 arm64不同粒度页的页表2.1 4KB页面粒度的页表配置2.2 16KB页面粒度的页表配置2.3 64KB页面粒度的页表配置 3 页表描述符3.1 无效页表描述符3.2 L0~L2页表描述符3.3 L3页表描述符 4 linux arm64 页表映射4.1 __create_pg…

Java 字符串类型的JSON数组转List<Object>

1.依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.21</version></dependency> 2.代码 import cn.hutool.json.JSONUtil; import java.util.List;/*** 字符串类型的JSON数组…

Java 把 Map 的值(Value)转换为 Array, List 或 Set

概述 在这篇短文中&#xff0c;我们将会展示如何把 Map 中的值取出来&#xff0c;转换为一个 Array,、List 或者一个 Set。 当然&#xff0c;你可以使用 Java JDK 来进行转换&#xff0c;你也可以使用 Guava 来进行转换。 首先&#xff0c;让我们来看看&#xff0c;如何使用原…