C语言06--数组进阶

news2024/11/25 18:25:10

数组名含义

  • 数组名有两个含义:
    • 第一含义是:整个数组
    • 第二含义是:首元素的地址
  • 当出现以下情形时,那么数组名就代表整个数组:
    • 在数组定义中
    • 在 sizeof 运算表达式中 ,因此sizeof 计算的就是整个数组的大小。sizeof(arr)
      • sizeof(arr)为数组元素类型大小和数组元素个数的乘积
    • 在取址符&中 , 因此取得的地址是整个数组的地址。
  • 其他任何情形下,那么数组名就代表首元素的地址。即:此时数组名就是一个指向首元素的指针。
  • 示例:
int a[3];                  // 此处,a 代表整个数组
printf("%d\n", sizeof(a)); // 此处,a 代表整个数组
printf("%p\n", &a);        // 此处,a 代表整个数组,此处为整个数组的地址

int *p = a;       // 此处,a 代表首元素 a[0] 的地址,等价于 &a[0]
p = a + 1;        // 此处,a 代表首元素 a[0] 的地址,等价于 &a[0]
function(a);      // 此处,a 代表首元素 a[0] 的地址,等价于 &a[0]
scanf("%d",  a ); // 此处,a 代表首元素 a[0] 的地址,等价于 &a[0]

C语言只有在第一含义的场合下表现为数组,其他大部分场合都表现为首元素的地址,当数组表现为首元素地址时,实际上就是一个指向其首元素的指针。数组运算实际上就是指针运算。

#include <stdio.h>
 
int main()
{
    int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    printf("%d\n", sizeof(arr)); // 数组的整个大小 10 * 4 = 40
    printf("%d\n", sizeof(&arr[0])); // 数组首元素的地址,一般看pc的位数,32位的为4,64位的为8

    printf("%d\n", sizeof(&arr)); // &arr表示数组的地址,一般看pc的位数,32位的为4,64位的为8
    printf("arr = %p\n", arr); // 表示数组的首元素地址
    printf("&arr[0] = %p\n", &arr[0]); // 表示数组的首元素地址
    printf("&arr = %p\n", &arr); // 表示整个数组的地址
 
    printf("arr + 1 = %p\n", arr + 1); // 表示数组的的首元素地址+1,数组元素为int类型,所以这里为数组首元素地址+4
    printf("&arr[0] + 1= %p\n", &arr[0] + 1); // 表示数组的首元素地址+1,数组元素为int类型,所以这里为数组首元素地址+4
    printf("&arr + 1= %p\n", &arr + 1); //&arr代表整个数组的地址,+1表示加一整个数组大小,一整个数组大小为40字节
    printf("arr + 9 = %p\n", arr + 10);//arr数组首元素地址,+10个数组首元素地址大小,+40个字节

    return 0;
}
//打印结果:
// 40
// 8
// 8
// arr = 0xffffcbd0
// &arr[0] = 0xffffcbd0
// &arr = 0xffffcbd0
// arr + 1 = 0xffffcbd4
// &arr[0] + 1= 0xffffcbd4
// &arr + 1= 0xffffcbf8
// arr + 9 = 0xffffcbf8

数组下标

  • 数组下标实际上是编译系统的一种简写,其等价形式是:
a[i] = 100;  等价于  *(a+i) = 100;
  • 根据加法交换律,以下的所有的语句均是等价的:
  a[i] = 100;
*(a+i) = 100;
*(i+a) = 100;
  i[a] = 100;
  • 数组运算,等价于指针运算。

字符串常量

  • 字符串常量在内存中的存储,实质是一个匿名数组
  • 匿名数组,同样满足数组两种涵义的规定
  • 示例:
printf("%d\n", sizeof("abcd")); // 此处 "abcd" 代表整个数组,打印5
printf("%p\n", &"abcd");        // 此处 "abcd" 代表整个数组,打印整个数组的地址

printf("%c\n", "abcd"[1]); // 此处 "abcd" 代表匿名数组的首元素地址,打印b
char *p1 = "abcd";         // 此处 "abcd" 代表匿名数组的首元素地址,P1指向数组的首元素
char *p2 = "abcd" + 1;     // 此处 "abcd" 代表匿名数组的首元素地址,P2指向数组第二个元素

注:字符串常量:

字符串常量是指在程序中直接使用双引号括起来的字符串。例如:"hello"、"world"等都是字符串常量。字符串常量在C语言中是不可变的,也就是说,一旦定义了字符串常量,就不能再修改它的值。字符串常量实际上是一个匿名数组,字符串即代表它的名字,如hello即代表"hello"的名字

在C语言中,你可以使用双引号括起来的任何字符序列来定义字符串常量。

在C语言中,字符串和字符串常量之间有一些重要的区别,我们可以通过以下几点来区分它们:

  1. 字符串常量是在双引号内的字符序列,例如"Hello"。字符串常量是在程序编译时就确定并存储在只读内存段中的。
  2. 字符串是字符数组,可以存储在堆内存或栈内存中。我们可以通过数组名或者指针来引用字符串。

字符串常量的本质表现是代表它的第一个字符的地址,这是因为在C语言中,字符串常量被存储为字符数组,并以空字符 '\0' 结尾。因此,当你声明一个字符串常量时,实际上是在内存中创建一个字符数组,并将该字符串中每个字符的地址存储在数组中。

在C语言中,字符串常量是不可变的,因此任何尝试修改字符串常量的操作都是不允许的。这也是为什么在前面的例子中,尝试使用指向字符串常量的指针来进行修改会导致崩溃的原因。

char *s = ”hello",不能通过s改变”hello“,而数组能够表示字符串并对字符串进行操作是通过申请一段字符存储空间,并复制字符串常量来表示字符串,而操作数组表示的字符串实际上是操作数组,所以char s[ ] = "hello"可以通过s来改变“hello” 

数组表示字符串是把字符串常量直接复制一份过来,可访问可修改

指针是指向字符串的地址,因为是字符串常量,所以只可访问不可修改

当你写下 char str[] = "helloworld"; 时,实际上发生了两件事情:

  1. 在数据段中分配内存来存储字符串常量"hello"
  2. 创建了一个字符数组 str,并分配了足够的内存来存储字符串 "hello world"。 
  3. 将字符串 "hello world" 中的每个字符复制到了字符数组 str 中,并在末尾添加了一个空

字符 '\0' 来表示字符串的结束。

  1. 编译器会自动在字符数组的末尾添加一个空字符 '\0' 来表示字符串的结束。这个过程是自动进行的,你不需要手动添加空字符

因此,你可以对字符数组 str 进行任意操作,因为它是可变的。这包括修改、反转、拼接等操作。但是,如果你通过指针直接对字符串常量"hello world" 进行操作,就会导致编译错误或者运行时错误

零长数组

  • 概念:长度为0的数组,比如 int data[0];
    • 数组是唯一一个允许合法越界操作的。
  • 用途:放在结构体的末尾,作为可变长度数据的入口(通过数组进行越界访问【合法】)
  • 示例:
struct node
{
    /* 结构体的其他成员 */
    // 成员1
    // 成员2
    // ... ...
    
    int   len;
    char data[0];
};

// 给结构体额外分配 10 个字节的内存。
struct node *p = malloc(sizeof(struct node) + 10);
p->len = 10;    //结构体指针指向node,为node的len赋值为10

// 额外分配的内存可以通过 data 来使用
p->data[0] ~ p->data[9]

变长数组 (长度是一个变量)

  • 概念:定义时,使用变量作为元素个数的数组。
  • 要点:变长数组仅仅指元素个数在定义时是变量,而绝非指数组的长度可长可短。实际上,不管是普通数组还是所谓的变长数组,数组一旦定义完毕,其长度则不可改变。
  • 在实际编程中,有时数组的长度不能提前确定,如果这个变化范围小,那么使用常量表达式定义一个足够大的数组就可以,如果这个变化范围很大,就可能会浪费内存,这时就可以使用变长数组
  • 变量的值在编译期间并不能确定,只有等到程序运行后,根据计算结果才能知道它的值到底是什么,所以数组长度中一旦包含了变量,那么数组长度在编译期间就不能确定了,也就不能为数组分配内存了,只有等到程序运行后,得到了变量的值,确定了具体的长度,才能给数组分配内存,我们将这样的数组称为变长数组(VLA, Variable Length Array)。
  • 普通数组(固定长度的数组)是在编译期间分配内存的,而变长数组是在运行期间分配内存的
int len = 5;
int a[len];  // 数组元素个数 len 是变量,因此数组 a 是变长数组

// 当数组被成功定义出来后,len的值发生任何改变都不影响数组的大小
len = 10 ;

int x = 2;
int y = 3;
int b[x][y]; // 数组元素个数 x、y 是变量,因此数组 b 是变长数组
int b[2][y]; // 数组元素个数 y 是变量,因此数组 b 是变长数组
int b[x][3]; // 数组元素个数 x 是变量,因此数组 b 是变长数组
  • 语法:变长数组不可初始化,即以下代码是错误的:
int len = 5;
int a[len] = {1,2,3,4,5}; // 数组 a 不可初始化

先定义一个变量 n 和一个数组 arr,然后用 scanf() 读入 n 的值。有些初学者认为,scanf() 输入结束后,n 的值就确认下来了,数组 arr 的长度也随即确定了。这种想法看似合理,其实是蛮不讲理,毫无根据。

从你定义数组的那一刻起(也就是第二行代码),数组的长度就确定下来了,以后再也不会改变了;改变 n 的值并不会影响数组长度,它们之间没有任何“联动”关系。用 scanf() 读入 n 的值,影响的也仅仅是 n 本身,不会影响数组。

那么,上面代码中数组的长度究竟是什么呢?鬼知道!n 是未初始化的局部变量,它的值是未知的。

修改上面的代码,将数组的定义放到最后就没问题了:

在定义数组之前就输入 n 的值,这样输入的值才有用武之地。

结语

        通过本篇博客,我们深入探讨了C语言中的数组,涵盖了其基本概念、初始化方式、访问和修改元素的方法,以及如何有效地使用数组进行高级编程。数组不仅是C语言中常用的数据结构,更是许多算法和程序实现的基础。

        理解数组的运作机制及其在内存中的存储方式,不仅能够提升我们的编程技巧,还能帮助我们优化代码性能及资源管理,让我们的应用程序更为高效。无论是在处理数据集合,还是在实现复杂的算法时,掌握数组的各种进阶用法无疑会极大地拓宽我们的编程视野。

        希望这篇文章能对您在学习和使用C语言数组方面有所帮助。数组的世界浩瀚无边,掌握了它们,您将能够驾驭更复杂的数据结构与算法。继续探索和练习吧,编程之旅才刚刚开始!

        感谢您的阅读,如果您有任何疑问或想法,欢迎在评论区与我们分享。

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

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

相关文章

《黑神话:悟空》风灵月影V1.0-35项修改器全面解析

《黑神话&#xff1a;悟空》作为一款备受瞩目的魂系动作角色扮演游戏&#xff0c;以其细腻的画面、流畅的操作和深厚的剧情吸引了众多玩家的关注。然而&#xff0c;对于不少玩家来说&#xff0c;游戏的高难度设置也带来了不小的挑战。为此&#xff0c;风灵月影工作室特别推出了…

[Spring] Spring原理(SpringBoot完结)

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

【15】Java字节码

Java方法栈帧的组成&#xff1a;操作数栈局部变量表 操作数栈 Java字节码是Java虚拟机所使用的的指令集。它与JVM基于栈的计算模型是分不开的。 在解释执行过程中&#xff0c;每当为 Java 方法分配栈桢时&#xff0c;Java 虚拟机往往需要开辟一块额外的空间作为操作数栈&…

JavaEE 第16节 线程安全的集合类

目录 前言 顺序表 队列 哈希表 1、Hashtable 2、ConcurrentHashMap&#xff08;重点&#xff09; 前言 本文章主要介绍在多线程环境下&#xff0c;如何线程安全的使用一些常用的集合类&#xff08;顺序表和哈希表&#xff09;。 顺序表 1、自己使用同步锁机制&#xff…

模拟笔试:卡码网2023年快手笔试真题

1.158同余方程 思路 纯数学的思路&#xff0c;想不出来的话很难做。 欧几里得算法视频讲解 代码 #include <iostream> using namespace std;// 扩展欧几里得&#xff1a;计算 ax by gcd(a, b) 的解 long long extended_gcd(long long a, long long b, long long &a…

Java语言程序设计——篇十五(5)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…

【STM32嵌入式系统设计与开发拓展】——16_FreeRTOS操作系统

参考&#xff1a;链接: 正点原子 一、认识裸机和RTOS 裸机是无操作系统支持&#xff0c;程序直接运行在硬件上&#xff0c;开发者要自行处理硬件细节。早期单片机常采用&#xff0c;优点是性能和资源利用率高&#xff0c;缺点是开发难、可移植性差。RTOS 是实时操作系统&…

vscode导入的包裹代码名称没有颜色

问题描述:代码其他染色正常,但是例如import torchtorch没有颜色,虽然能够识别(ctrl左键能够点进去看到torch代码) 解决: 下载extention pylancefile->preferences->settings, 搜索Python: Language Server, 从default改成pylance

JAVA—IO流

存储数据的方案File和文件数据的操作IO流&#xff0c;学习字节流和字符流&#xff0c;了解框架和IO框架Commons IO 目录 1.File &#xff08;1&#xff09;创建对象 &#xff08;2&#xff09;常用方法 【1】判断类型&#xff0c;获取信息 【2】创建文件&#xff0c;删除…

LNMP学习

一、LNMP—web 1. 概述 LNMP/LAMP linux/windows/unix apache/nginx mysql/pgsql php/jsp 2. nginx部署及其平滑升级 实操 3. nginx七层负载均衡及算法 算法参考文档&#xff1a;https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/ 实操 4…

flv格式转换mp4怎么转换?5个软件帮助你自己快速进行格式转换

flv格式转换mp4怎么转换&#xff1f;5个软件让你从此快速转换格式不求别人 将FLV格式的视频转换为MP4格式可以通过使用以下五款软件来轻松实现。这些工具操作简便&#xff0c;能够快速高效地完成视频格式的转换&#xff0c;让你轻松应对各种视频格式需求。 口袋视频转换器 这…

网安新声 | 网易云音乐崩了:网络安全如何守护在线体验

网安加社区【网安新声】栏目&#xff0c;汇聚网络安全领域的权威专家与资深学者&#xff0c;紧跟当下热点安全事件、剖析前沿技术动态及政策导向&#xff0c;以专业视野和前瞻洞察&#xff0c;引领行业共同探讨并应对新挑战的策略与可行路径。 8月19日&#xff0c;#网易云音乐崩…

“休闲化“趋势增强,IAA手游出海如何抓住增长机遇?

进入存量时代&#xff0c;全球手游市场正面临严峻的挑战。数据显示&#xff0c;2023年 App Store 和 Google Play 的全球双端下载量同比下降10%&#xff0c;IAP 收入也同比减少2%。而作为大盘的支柱品类&#xff0c;中重度手游首当其冲。以 RPG 和 SLG 品类为例&#xff0c;虽然…

Halo个人博客Docker部署结合内网穿透为本地站点配置公网地址远程访问

文章目录 前言1. Docker部署Halo1.1 检查Docker版本如果未安装Docker可参考已安装Docker步骤&#xff1a;1.2 在Docker中部署Halo 2. Linux安装Cpolar2.1 打开服务器防火墙2.2 安装cpolar内网穿透 3. 配置Halo个人博客公网地址4. 固定Halo公网地址 前言 本文主要介绍如何在Cen…

常见计算机网络协议汇总(非常详细)从零基础入门到精通,看完这一篇就够了

文章目录 前言计算机网络五层模型回顾应用层协议 DNS协议&#xff1a;HTTP协议HTTPS协议 传输层协议 UDP协议TCP 网络层 IP协议ICMP协议 数据链路层 ARP协议 物理层整体的网络传输流程 1️⃣网络安全零基础入门 ① 学习路线② 路线对应学习视频 2️⃣视频配套资料&国内外网…

二分+前缀和+思维,CF 1902D - Robot Queries

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1902D - Robot Queries 二、解题报告 1、思路分析 不管怎么反转: 起点终…

【新品实测】C1001毫米波人体检测传感器来了!跌倒检测、睡眠监测更准确!

我们最近推出了一款全新的60G毫米波产品&#xff1a;C1001毫米波人体检测传感器。在这篇文章中&#xff0c;我们将深入测评这款产品的性能&#xff0c;并详细解析C1001毫米波人体检测传感器的功能和特性。 产品链接&#xff1a;C1001 60GHz毫米波人体检测传感器 原文链接&…

QML ScrollView 实现自动滚动到底部

先看效果,每当有新的日志,会自动添加到Text中,主要实现了ScrollView自动滑动到底部,显示最新的日志 目录 1.思路2.position分析 1.思路 在官网中scrollview并没有关于scrollview位置的设置 但是我们可以控制右边滑动条scrollbar的位置 注意position并不是一个高度数据,你可以…

Adobe Dreamweaver(DW)网页代码编辑器win/mac软件安装下载

一、Adobe DW软件概览 1.1 DW软件简介 Adobe Dreamweaver&#xff08;简称DW&#xff09;是一款功能强大的网页代码编辑器&#xff0c;由Adobe公司开发并维护。其全称为“Adobe Dreamweaver”&#xff0c;中文译为“梦想编织者”。DW集网页制作和管理网站于一身&#xff0c;支…

Allegro PCB位号重排反标原理图步骤

第一步&#xff1a;也是最重要的一步&#xff0c;备份整个工程文件夹。 防止操作过程中误操作导致工程文件出问题&#xff0c;万一出问题&#xff0c;没有备份&#xff0c;调整代价比较大 第二步&#xff1a;确认当前PCB和原理图的网表统一。 稳妥做法&#xff1a; 2a:原理图…