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

news2024/9/24 11:30:49

环境

  • 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 = 4

arr[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.coloradmin.cn/o/1228209.html

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

相关文章

ChatGPT最强?文心一言与ChatGPT对比

对于同一个问题我们分别对文心一言3.5和ChatGPT3.5输出回答&#xff0c;结果如下图&#xff0c;可以看到文心一言的回答更好&#xff0c;文心一言是由百度开发的人工智能语言模型&#xff0c;它的中文理解能力主要是基于百度强大的搜索引擎和自然语言处理技术。文心一言更加注重…

深入理解栈与队列:从基本概念到高级实现

&#x1f493; 博客主页&#xff1a;江池俊的博客⏩ 收录专栏&#xff1a;数据结构探索&#x1f449;专栏推荐&#xff1a;✅cpolar ✅C语言进阶之路&#x1f4bb;代码仓库&#xff1a;江池俊的代码仓库&#x1f525;编译环境&#xff1a;Visual Studio 2022&#x1f389;欢迎大…

算法设计与分析复习--贪心(二)

文章目录 上一篇哈夫曼编码单源最短路最小生成树Kruskal算法Prim算法 多机调度问题下一篇 上一篇 算法设计与分析复习–贪心&#xff08;一&#xff09; 哈夫曼编码 产生这种前缀码的方式称为哈夫曼树 哈夫曼树相关习题AcWing 148. 合并果子 #include <iostream> #inc…

Network(三)动态路由与ACL配置

一 三层交换机 1 三层交换机概述 三层交换二层交换三层转发 2 虚拟接口概述 在三层交换机上配置的VLAN接口为虚拟接口&#xff0c;使用Vlanif&#xff08;VLAN虚拟接口&#xff09;实现VLAN间路由&#xff0c;VLAN接口的引入使得应用更加灵活 三层交换机VLAN间通信的转发…

基于Qt QList和QMap容器类示例

## QList<T> QList<T>容器是一个数组列表,特点如下: 1.大多数情况下可以用QList。像prepend()、append()和insert()这种操作,通常QList比QVector快的多。这是因为QList是基于index标签存储它的元素项在内存中(虽然内存不连续,这点与STL的list 是一样的),比…

EDA实验-----4*4矩阵键盘与数码管显示测试(Quartus ‖)

目录 一、实验目的 二、实验仪器设备 三、实验原理 四、实验要求 五、实验步骤 六、实验报告 七、实验过程 1.矩阵键盘按键原理 2.数码管原理 3.分频器代码 4.电路图连接 5.文件烧录 一、实验目的 了解数码管的工作原理&#xff1b;掌握4*4矩阵键盘和数码管显示的编…

gradle8.0或者其他版本下载太慢或者time out超时(完美解决方法)

官网镜像地址 如果其他软件除了android studio可以在下面完整直接下载 地址&#xff1a;https://mirrors.cloud.tencent.com/gradle/ Android Stuiod如何配置更换 项目名称\gradle\wrapper\gradle-wrapper.properties 下面是我已经更改后的了&#xff0c;大家如果跟这个不一样换…

解决WPF项目xaml出现“正在等待IntelliSense完成”的问题

在WPF项目xaml里经常出现“正在等待IntelliSense完成”的场景&#xff0c;如下图&#xff1a; 解决办法 工具–选项

Rust与其他语言对比:优势在哪里?

大家好&#xff01;我是lincyang。 今天&#xff0c;我们将深入探讨Rust语言与其他编程语言比较的优势&#xff0c;并通过具体的代码示例和性能数据来加深理解。 Rust与其他语言的比较 1. 内存安全性 Rust&#xff1a;采用所有权系统&#xff0c;编译器在编译时检查内存安全…

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

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

Android修行手册-POI操作中文API文档

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

uview-plus中二级菜单左右联动更改为uni-app+vue3+vite写法

uview-plus3.0重磅发布&#xff0c;全面的Vue3移动组件库 该插件使用的vue2写法&#xff0c;但支持vue3引用&#xff0c;在此基础上修改为uni-appvue3vite; <template><view class"u-wrap mainClass"><!-- <back-header :title"pageTitle&quo…

【python】--python基础学习

目录 一、基础语法二、基础数据类型1、变量赋值2、数值型3、字符串型4、列表List5、元组Tuple6、字典dictionary7、数据类型转换 三、python运算符四、条件控制与循环五、常用函数1、字符串函数2、format函数 一、基础语法 标识符是允许作为变量&#xff08;函数、类等&#x…

RHCSA --- Linux存储管理

存储管理 Boot&#xff1a;可引导操作系统的分区&#xff08;必须是主分区&#xff09; 分区 ll /dev/nvme0n* 表示的是 nvme接口的磁盘 0n1 1 0n2 2 0n3 3 brw-rw----. 1 root disk 259, 0 Nov 15 19:31 /dev/nvme0n1 磁盘1 brw-rw----. 1 ro…

Python3.7+PyQt5 pyuic5将.ui文件转换为.py文件、Python读取配置文件、生成日志

1.实际开发项目时&#xff0c;是使用Qt Designer来设计UI界面&#xff0c;得到一个.ui的文件&#xff0c;然后利用PyQt5安装时自带的工具pyuic5将.ui文件转换为.py文件&#xff1a; pyuic5 -o mywindow.py mywindow.ui #先是py文件名&#xff0c;再是ui文件名样式图 QT5 UI&am…

SQLite 安装和 Java 使用教程

SQLite是一个C语言库&#xff0c;它实现了一个小型、快速、自包含、高可靠性、功能齐全的SQL数据库引擎。SQLite是世界上使用最多的数据库引擎。SQLite内置于所有手机和大多数计算机中&#xff0c;并捆绑在人们每天使用的无数其他应用程序中。 SQLite文件格式稳定、跨平台、向…

分库分表

分库&#xff0c;分表&#xff0c;分库分表 “只分库“&#xff0c;“只分表“&#xff0c;“既分库又分表" 何时分库 在面对高并发的情况下&#xff0c;数据库连接成为性能瓶颈。当数据QPS过高导致数据库连接数不足时&#xff0c;考虑分库。在读多写少的场景下&#x…

场景交互与场景漫游-交运算与对象选取(8-1)

交运算与对象选取 在面对大规模的场景管理时&#xff0c;场景图形的交运算和图形对象的拾取变成了一项基本工作。OSG作为一个场景管理系统&#xff0c;自然也实现了场景图形的交运算&#xff0c;交运算主要封装在osgUtil 工具中在OSG中&#xff0c;osgUtil是一个非常强有力的工…

基于学生心理学算法优化概率神经网络PNN的分类预测 - 附代码

基于学生心理学算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于学生心理学算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于学生心理学优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针…

电子学会2023年6月青少年软件编程(图形化)等级考试试卷(四级)真题,含答案解析

青少年软件编程(图形化)等级考试试卷(四级) 一、单选题(共10题,共30分) 1. 下列积木运行后的结果是?( )(说明:逗号后面无空格) A.