我玩过C和不同的排序算法。我决定首先尝试声明一个大小(例如100)的自动数组而不是初始化它,而不是生成一个随机数组来排序。我预计操作系统(我在Windows XP上)会在那里放零,否则可能是某些其他进程留下的一些数据。但事实证明,这种未初始化的阵列中没有零。所以第一个问题是:它可能是什么数据,为什么它不被操作系统清理?它可能是“cmd”shell的垃圾我正在运行编译器和程序吗?
接下来,由于我尝试的排序算法没有分配任何更多的内存,只是将所有内容排序,我认为有两种可能性:(a)为数组分配的内存区域将被排序并且在下一次运行时保持这种方式,或者(b)在下一次运行时,操作系统将给程序另一部分内存,因此另一个垃圾。但事实证明,它既不是。无论我多少次排序,内存都保持不变。所以,第二个问题是:我怎么可能获得一些随机虚拟内存区域,对它进行排序,并且在下一次运行中我得到原始形式的相同区域?
以下是代码和我的步骤。
#include <stdio.h>
#define SIZE 100
void quick_sort( int *a, size_t size )
{
/* No comments here, everybody knows quicksort
and anyone will write it better! :) */
if( size <= 1 ) return;
int tmp, pivot;
int small_length, pivot_pos;
pivot_pos = size / 2;
pivot = a[pivot_pos];
tmp = a[0];
a[0] = pivot;
a[pivot_pos] = tmp;
small_length = 0;
for( int i = 1; i < size; i++ )
{
if( a[i] < pivot ){
small_length++;
tmp = a[small_length];
a[small_length] = a[i];
a[i] = tmp;
}
}
a[0] = a[small_length];
a[small_length] = pivot;
quick_sort( a, small_length );
quick_sort( a + small_length + 1, size - small_length - 1 );
}
int main( int argc, char *argv[] )
{
int a[SIZE];
int i;
quick_sort( a, SIZE );
for( i = 0; i < SIZE; i++ ) {
printf( "%d\n", a[i] );
}
return 0;
}
我使用的步骤:
quick_sort
调用注释,查看未排序的单元化数组:cc sort.c -Wall -std=c99 && a > unsorted1
(已编译的可执行文件为a.exe
)。quick_sort
来电并查看排序结果:cc ... > sorted
。cc ... > unsorted2
。unsorted1
和unsorted2
- 它们是相同的,全部是100行。我还尝试启动另一个“cmd”实例,数据相同。
予。未排序数据的十六进制转储:
0000000 0000 0000 fd7c 0022 fd74 0022 fdd8 0022
0000020 0170 0000 1448 7c91 ffff ffff 1440 7c91
0000040 0000 0024 13d2 7c91 301c 0024 3008 0024
0000060 0010 0000 b988 7c97 0000 003e 0007 0000
0000100 fd24 0022 0000 0000 fe24 0022 e900 7c90
0000120 0040 0001 002e 0000 0000 003e eeeb 7c80
0000140 fe30 0022 e900 7c90 0040 7c91 ffff ffff
0000160 003d 0001 0002 0000 fd5c 0022 0000 0000
0000200 fe50 0022 0002 0000 0002 0000 ffff ffff
0000220 003d 7c91 c2de 77c1 0000 003e 0000 0000
0000240 c2e3 77c1 a122 0040 0000 0000 2bc4 003e
0000260 2070 77c0 ffff ffff 0000 003e 2bc0 003e
0000300 0004 0000 2373 0024 1660 0040 fea0 0022
0000320 c024 77c1 0000 003e 0000 0000 c02d 77c1
0000340 1660 0040 2373 0024 1dc0 0040 fec0 0022
0000360 c024 77c1 0000 003e 0000 0000 c02d 77c1
0000400 1dc0 0040 2373 0024 0000 0000 5c94 77c2
0000420 a52e 77c2 1ae8 77c5 fedc 0022 9d60 77c2
0000440 fe88 0022 4e2f 77c2 feec 0022 5c94 77c2
0000460 a52e 77c2 1ae8 77c5 fefc 0022 9d60 77c2
0000500 0008 0000 4e2f 77c2 4e29 77c2 ff3c 0022
0000520 2373 0024 0000 0000 1dc0 0040 fed4 0022
0000540 ff08 0022 ffe0 0022 5c94 77c2 2850 77c0
0000560 ffff ffff 4e29 77c2 4e42 77c2 1dc0 0040
0000600 ffa0 0022 1e1e 0040 1dc0 0040 0020 0000
要生成转储,我必须在代码中添加一个FILE,fopen(...),fclose(...),这会改变输出。但是这些调用在数组声明之后,所以仍然不确定它会如何影响数组的内容。
II。试图将SIZE增加到10000并最终看到零。输出很多零,最后是熟悉的垃圾。我不确定内存增长的方向,我预计数据会保留在数组的开头......
答案 0 :(得分:4)
现代的多用户/多进程操作系统总是将干净的内存页面移交给请求内存的进程(以便敏感数据不会从一个进程泄漏到另一个进程)。请注意,这&#34;清洁&#34;合同仅在操作系统最初将内存移交给进程时才适用。如果进程最初将内存用于一件事,然后再将内存用于其他内容,则内存不会自动重新清理。这就是这里发生的事情 - 你的未初始化的变量在堆栈上,并且在main
运行之前,C运行时启动代码已经使用了堆栈。您正在查看启动代码留在堆栈上的任何垃圾。如果您确切地想知道它是什么,您可以阅读Microsoft Visual C运行时库源代码(它随Visual Studio一起提供)或查看反汇编程序中程序的入口点的反汇编。
这同样适用于堆。当malloc
,VirtualAlloc
等首先从操作系统获取页面时,它们将是干净的。但是当您调用free
,VirtualFree
等时,运行时库没有义务将页面返回给操作系统并重新请求它们。它可以保持它们(不清除它们)并使用它们来满足后来的要求。