一个C语言程序的分析:运行速度和文件大小以及变量初始值

环境

  • Ubuntu 22.04
  • gcc 11.4.0
  • Window 11
  • Microsoft Visual Studio Community 2022 (64-bit) - Current Version 17.6.2

运行速度

一个C程序 test1.c 如下:

int array[30000][30000];int main() {for (int i = 0; i < 30000; i++)for (int j = 0; j < 30000; j++) {array[i][j] = 12345;}return 0;
}

编译:

gcc test1.c -o test1

运行并查看运行时间:

time ./test1
./test1  1.28s user 1.75s system 99% cpu 3.035 total

用时1.28秒。

修改一下代码,把循环里i和j的顺序交换一下:

int array[30000][30000];int main() {for (int j = 0; j < 30000; j++)for (int i = 0; i < 30000; i++) {array[i][j] = 12345;}return 0;
}

运行结果如下:

time ./test2        
./test2  15.92s user 1.59s system 99% cpu 17.533 total

可见,运行时间从原先的1.28秒暴涨到15.92秒。

其实,我们能猜到,引起性能下降的原因,一定与数组在内存中的存储方式有关。

以二维数组为例:在C语言中,是按“先列后行”来存储的,也就是按 arr[0][0]arr[0][1]arr[0][2] ,……,arr[1][0]arr[1][1]arr[1][2] ,……这样的顺序连续存储的。

写一个程序来检验如下:

#include <stdio.h>int arr[3][3];int main() {printf("size of int = %ld\n\n", sizeof(int));for (int i = 0; i < 3; i++)for (int j = 0; j < 3; j++) {printf("arr[%d][%d] address: %p\n", i, j, &arr[i][j]);}return 0;
}

运行结果如下:

size of int = 4arr[0][0] address: 0x5585c16fb040
arr[0][1] address: 0x5585c16fb044
arr[0][2] address: 0x5585c16fb048
arr[1][0] address: 0x5585c16fb04c
arr[1][1] address: 0x5585c16fb050
arr[1][2] address: 0x5585c16fb054
arr[2][0] address: 0x5585c16fb058
arr[2][1] address: 0x5585c16fb05c
arr[2][2] address: 0x5585c16fb060

可见,int 类型的size是4,而数组中每两个相邻元素,其地址编码相差也是4。

计算机访问连续内存地址的速度,要远远快于非连续地址。这也是数组要比链表访问速度更快的原因。

注:Java程序也类似。

文件大小

全局变量

再来看一下 test1.c

int array[30000][30000];int main() {for (int i = 0; i < 30000; i++)for (int j = 0; j < 30000; j++) {array[i][j] = 12345;}return 0;
}

经过编译后,生成的 test1 文件大小为16KB。

ll test1*
-rwxr-xr-x 1 root root 16K 11月 19 19:07 test1
-rw-r--r-- 1 root root 150 11月 19 18:51 test1.c

如果把数组大小改变,编译后的文件大小不变。

这是为什么呢?按理说,array是一个全局变量,是在编译期静态的生成的,应该会占据可执行文件的空间,但这里却似乎并没有影响。

我猜测是因为编译器做了一些优化。虽然声明了全局数组,但是没有赋初值,所以编译器并没有为数组分配空间。

如果有赋初值,则编译后的文件就会随着数组大小而显著变化。

创建文件 test11.c 如下:

int array[300][300] = {123};int main() {
}

编译后,生成的文件大小为368KB:

ll test11*
-rwxr-xr-x 1 root root 368K 11月 19 20:06 test11
-rw-r--r-- 1 root root   45 11月 19 20:06 test11.c

创建文件 test12.c 如下:

int array[3000][3000] = {123};int main() {
}

编译后,生成的文件大小为35MB:

ll test12*
-rwxr-xr-x 1 root root 35M 11月 19 20:08 test12
-rw-r--r-- 1 root root  47 11月 19 20:07 test12.c

可见,数组大小扩大100倍,文件大小也扩大了100倍。

局部变量

对于局部变量,是运行期(调用对应函数时)在栈上分配内存的,所以数组大小并不会影响文件大小:

int main() {int array[30000][30000] = {123};
}

这里不管数组大小如何变化,编译后生成的可执行文件都是16KB。

未初始化数组的内容

另一个好玩的问题是,如果定义了数组,但没有初始化,那么数组的内容是什么?

全局变量

对于全局变量,其内容会被自动初始化为0。

#include <stdio.h>int array[300][300];int main() {printf("%d\n", array[5][5]);
}

运行结果如下:

0

这应该是在load可执行文件时,将其内存初始化。

局部变量

#include <stdio.h>int main() {int array[300][300];printf("%d\n", array[5][5]);
}

运行结果如下:

0

可见,局部变量的内存也被初始化为0(在调用对应函数,在栈上分配内存时)。

但这不是100%确定的。在MicroSoft Visual Studio下,其运行结果为:

-858993460

在这里插入图片描述

总而言之,变量最好先初始化,再使用。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VMware Workstation 与 Device/Credential Guard 不兼容 解决办法

问题描述 问题描述&#xff1a; VMware 启动虚拟机会报错。无法运行。 错误信息&#xff1a;VMware Workstation 与 Device/Credential Guard 不兼容。在禁用 Device/Credential Guard 原因分析&#xff1a; 通常原因是 Window 系统开启了 内置的Hyper-V 虚拟机。 解决方案&…

sftp 从windows10向linux(centos7)传输文件

前言背景&#xff1a;该示例是需要从windows10向本地linux系统传输一个qt安装文件&#xff0c;不想或者无法安装xftp这些传输工具&#xff0c;直接通过命令传输&#xff1b; 首先保证windows10 ping通linux系统ip&#xff0c;linux ping 通windows10系统&#xff1b; 注意&am…

计算机网络的标准化工作及相关组织

一、国际化组织 计算机网络的标准化工作由一些主要的组织来进行管理和推动。以下是几个主要的计算机网络标准化的国际组织及其相关的标准&#xff1a; 1. 国际标准化组织&#xff08;ISO&#xff09;&#xff1a;国际标准化组织负责制定各种行业的标准&#xff0c;包括计算机…

【Java程序员面试专栏 专业技能篇】Java SE核心面试指引(一):基础知识考察

关于Java SE部分的核心知识进行一网打尽,包括四部分:基础知识考察、面向对象思想、核心机制策略、Java新特性,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 本篇Blog为第一部分:基础知识考察,子节点表示追问或同级提问 基本概念 …

⑩⑥ 【MySQL】详解 触发器TRIGGER,协助 确保数据的完整性,日志记录,数据校验等操作。

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 触发器 ⑩⑥ 【MySQL】触发器详解1. 什么是触发…

【智能家居】5、主流程设计以及外设框架编写与测试

目录 一、主流程设计 1、工厂模式结构体定义 &#xff08;1&#xff09;指令工厂 inputCmd.h &#xff08;2&#xff09;外设工厂 controlDevices.h 二、外设框架编写 1、创建外设工厂对象bathroomLight 2、编写相关函数框架 3、将浴室灯相关操作插入外设工厂链表等待被调…

设计模式-组合模式-笔记

“数据结构”模式 常常有一些组件在内部具有特定的数据结构&#xff0c;如果让客户程序依赖这些特定数据结构&#xff0c;将极大地破坏组件的复用。这时候&#xff0c;将这些特定数据结构封装在内部&#xff0c;在外部提供统一的接口&#xff0c;来实现与特定数据结构无关的访…

六大排序(插入排序、希尔排序、冒泡排序、选择排序、堆排序、快速排序)未完

文章目录 排序一、 排序的概念1.排序&#xff1a;2.稳定性&#xff1a;3.内部排序&#xff1a;4.外部排序&#xff1a; 二、插入排序1.直接插入排序2.希尔排序 三、选择排序1.直接选择排序方法一方法二直接插入排序和直接排序的区别 2.堆排序 四、交换排序1.冒泡排序2.快速排序…

Unity Meta Quest 一体机开发(七):配置玩家 Hand Grab 功能

文章目录 &#x1f4d5;教程说明&#x1f4d5;玩家物体配置 Hand Grab Interactor⭐添加 Hand Grab Interactor 物体⭐激活 Hand Grab Visual 和 Hand Grab Glow⭐更新 Best Hover Interactor Group &#x1f4d5;配置可抓取物体&#xff08;无抓取手势&#xff09;⭐刚体和碰撞…

计算机网络期末复习(知识点)

一、计算机网络体系结构 计算机网络&因特网&#xff1a; 计算机网络定义&#xff1a;将地理位置不同的具有独立功能的多台计算机及其外部设备&#xff0c;通过通信线路连接起来&#xff0c;在网络操作系统&#xff0c;网络关联软件及网络协议的管理和协调下&#xff0c;实…

WSL 2 更改默认安装的 Linux 发行版

目录 什么是 WSL 2&#xff1f;更改默认安装的 Linux 发行版更改发行版的 WSL 版本 什么是 WSL 2&#xff1f; WSL 2 是适用于 Linux 的 Windows 子系统体系结构的一个新版本&#xff0c;它支持适用于 Linux 的 Windows 子系统在 Windows 上运行 ELF64 Linux 二进制文件。 它的…

动态规划专项---最长上升子序列模型

文章目录 怪盗基德的滑翔翼登山合唱队形友好城市最大上升子序列和拦截导弹导弹防御系统最长公共上升子序列 一、怪盗基德的滑翔翼OJ链接 本题思路:本题是上升子序列模型中比较简单的模型&#xff0c;分别是从前往后和从后往前走一遍LIS即可。 #include <bits/stdc.h>co…