我正在学习如何在 C 中使用指针和结构。自然地,我试图故意破坏我的代码以进一步了解该语言的工作原理。这是一些按我预期工作的测试代码:
#include <stdio.h>
#include <stdlib.h>
struct pair {
int x;
int y;
};
typedef struct pair pair;
void p_struct( pair ); //prototype
int main( int argc, char** argv ) {
pair *s_pair;
int size, i;
printf( "Enter the number of pair to make: " );
scanf( "%d", &size );
getchar();
printf( "\n" );
s_pair = (pair*)malloc( size * sizeof(pair) );
for( i = 0; i < size; i++ ) {
s_pair[i].x = i;
s_pair[i].y = i;
p_struct( s_pair[i] );
}
getchar();
return (EXIT_SUCCESS);
}
void p_struct( pair s_pair ) {
printf( "\n%d %d\n", s_pair.x, s_pair.y );
}
如前所述,据我所知,此代码是有效的。
然后我决定修改部分代码,如下所示:
for( i = 0; i < size + 3; i++ ) {
s_pair[i].x = i;
s_pair[i].y = i;
p_struct( s_pair[i] );
}
此修改没有产生我预期的段错误错误。尽管我超出了我在使用 scanf 函数为我的变量大小分配值时明确设置的缓冲区,但所有“对”都被打印出来了。
据我了解指针(如果我错了,请纠正我),当我为类型对s_pair的指针调用 malloc 函数时,堆中的内存管理器会保留一个大小为size*sizeof(pair)的连续内存块。我所做的是,当我将 for 循环修改为条件i < size + 3时,我超出了最后分配的内存地址。
如果我正确理解这一点,我的指针是否超出了其保留的内存限制,并且恰好是清晰的,因为它的右侧和右侧没有被其他数据占用?这是溢出缓冲区时的正常行为吗?
补充一点,当我使用i < size + 15的 for 循环条件进行测试时,我确实收到了段错误。问题是,它仍然打印输出。如中所示,根据我制作的 p_struct 函数,当屏幕上的size = 10时,它将“0 0”对“24 24”打印出来。程序只有在到达底部的 getchar() 之一后才会因段错误而崩溃。我的程序究竟如何将值分配给超出缓冲区的对,将它们打印在屏幕上,然后突然决定在到达 getchar() 时因段错误而崩溃?i < size + 3似乎没有问题(尽管它仍然是错误的)。
作为记录,我还使用常规指针数组测试了这种行为:
int size, i, *ptr;
scanf( "%d", &size );
ptr = (int*)malloc( size * sizeof(int) );
for( i = 0; i < size + 15; i++ )
ptr[i] = i;
这会产生与上面完全相同的结果。在i < size + 3处,段错误似乎没有任何问题。
最后,我也用一个数组进行了测试:
int i, array[10];
for( i = 0; i < 25; i++ )
array[i] = i;
对于条件i < 25,我会毫无故障地遇到段错误。当我将其更改为i < 15时,我没有收到段错误。
如果我没记错的话,指针数组和数组之间的唯一区别是分配给数组的内存位于堆栈而不是堆上(对此不确定)。考虑到这一点,并考虑到当array[10]不产生任何段错误时i < 15的事实,为什么i < 25会成为问题?在 for 循环期间,数组不是位于堆栈顶部吗?当它不关心 60 个额外字节时,为什么它会关心 100 个额外字节?为什么该数组缓冲区的上限不是一直到为整个堆栈保留的任意内存块的末尾?
希望所有这些对于决定阅读一个稍微醉酒的人的漫谈的人来说都是有意义的。