一个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 

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 

int array[300][300];

int main() {
	printf("%d\n", array[5][5]);
}

运行结果如下:

0

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

局部变量

#include 

int main() {
	int array[300][300];
	printf("%d\n", array[5][5]);
}

运行结果如下:

0

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

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

-858993460

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

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

你可能感兴趣的:(C++,c语言)