我和一个朋友一起学习C语言动态分配malloc realloc.但有一个问题.我想到了记忆集



此代码在动态分配5个数组后,当达到分配给数组的大小(cur)时,通过增加3来写入额外的数据。

我写的代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
int i = 0;
int* arr = (int*)malloc(sizeof(int) * 5);
int curs = sizeof(arr) * 5 / sizeof(int);
while (1) {
printf("Input Num : (-1 input exit): ");
scanf("%d", &arr[i]);
if (arr[i] == -1)
break;
if ((i + 1) == curs) {
arr = (int*)realloc(arr, sizeof(int) * (3 + curs));
printf("Add Allocation Arr!n");
curs += 3;
}
i++;
}
printf(" Arr : ");
for (int j = 0; j < i; j++) {
printf("%d ", arr[j]);
}
free(arr);
return 0;
}

当我按如下方式输入数据时,它工作正常。

Input Data(Input -1 Exit): 1

Input Data(Input -1 Exit): 2

Input Data(Input -1 Exit): 3

Input Data(Input -1 Exit): 4

Input Data(Input -1 Exit): 5

Add Allocation Arr!

Input Data(Input -1 Exit): 1

Input Data(Input -1 Exit): 2

Input Data(Input -1 Exit): 3

Add Allocation Arr!

Input Data(Input -1 Exit): -1

Arr: 1 2 3 4 5 1 2 3

在这里,一个朋友尝试了一件事。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int* arr = (int*)malloc(sizeof(int) * 5);
int i = 0;
int curs = sizeof(arr) * 5 / sizeof(int);
while (1) {
printf("Input Data(Input -1 Exit): ");
scanf("%d", &arr[i]);
if (arr[i] != -1) {
if ((i + 1) == curs) {
printf("Add Allocation Arr!n");
curs += 3;
i++; // ★<-- don't use realloc, just i++
continue;
}
else {
i++;
continue;
}
}
else {
printf("Arr: ");
for (int j = 0; j < i; j++) {
printf("%d ", arr[j]);
}
break;
}
}
free(arr);
return 0;
}

如果您看一下上面注释中的★,您可以看到通过简单地增加i而不使用realloc来访问数组。

当我按如下方式输入数据时,它工作正常。

Input Data(Input -1 Exit): 1

Input Data(Input -1 Exit): 2

Input Data(Input -1 Exit): 3

Input Data(Input -1 Exit): 4

Input Data(Input -1 Exit): 5

Add Allocation Arr!

Input Data(Input -1 Exit): 1

Input Data(Input -1 Exit): 2

Input Data(Input -1 Exit): 3

Add Allocation Arr!

Input Data(Input -1 Exit): 1

Input Data(Input -1 Exit): 2

Input Data(Input -1 Exit): 3

Add Allocation Arr!

Input Data(Input -1 Exit): -1

Arr: 1 2 3 4 5 1 2 3 1 2 3

为什么这个在运行?

我很好奇,我使用下面的代码来检查内存状态。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int* arr = (int*)malloc(sizeof(int) * 5);
int i = 0;
int curs = sizeof(arr) * 5 / sizeof(int);
for (i = 0; i < 20; i++)
{
printf("%d ", arr[i]);
}
free(arr);
return 0;
}

执行结果如下:

-842150451 -842150451 -842150451 -842150451 -842150451 -33686019 7077988 108 -969574923 134254852 12127432 12077032 12127440 12077040 12127448 12077048 2076049408 2076489216 1527808 4456514

我想只使用分配的5内存访问它。预计在访问arr[4]索引后会出现错误,但是打印了结果。这很令人困惑。

C语言不会对数组进行任何类型的边界检查,相信程序员会做正确的事情。这是它快速的部分原因。但这也意味着,如果你没有做正确的事情,就不能保证你的程序会像预期的那样工作。

你所看到的是未定义行为的表现。当您读取/写入超过数组末尾时,程序可能会崩溃,它可能输出奇怪的结果,或者可能(如在本例中)看起来正常工作。更糟糕的是,通过对代码进行看似无关的更改,例如未使用的局部变量或调用printf进行调试,可能会改变未定义行为的显示方式。

程序可能崩溃并不意味着崩溃。

这很奇怪:

int curs = sizeof(arr) * 5 / sizeof(int);

如果这是试图计算数组中元素的数量,那么它是不正确的(并且是多余的,因为您已经知道您已经为5个元素留出了空间)。sizeof(arr)给出指向int指针的大小,而不是int的大小。老实说,这里只需要

int curs = 5;

分配和重新分配内存的通用协议如下所示:

/**
* Define some symbolic constants for the initial size
* and the number of elements to add.
*/
#define START_SIZE 5
#define EXTENT     3
/**
* Track the number of elements that have been allocated.
* Using size_t instead of int since that’s what’s
* usually used to represent sizes 
*/
size_t size = START_SIZE;
/**
* Unless you’re compiling this as C++ or using an
* *ancient* K&R C implementation, you should not
* cast the result of malloc, calloc, or realloc
*/
int *arr = malloc( sizeof *arr * size ); // sizeof *arr == sizeof (int)
/**
* ALWAYS check the result of malloc, calloc,
* and realloc.    
*/
if ( !arr )
{
/**
* Handle initial allocation failure here.  In
* this case we just print an error message and exit.
*/
fputs( "Initial allocation failure, exiting", stderr );
exit( 0 );
}
size_t i = 0;
/**
* In this example, "done” is just a placeholder for whatever
* logic you use to determine when to end the loop.
*/
while ( !done ) 
{
if ( i == size ) 
{
/**
* We’ve run out of space in the array, so we
* need to extend it with realloc.
*
* Since realloc can return NULL if it can’t satisfy
* the request, ALWAYS assign the result to a temporary
* variable, otherwise you will lose your reference
* to the previously-allocated memory.
*/
int *tmp = realloc( arr, sizeof *arr * (size + EXTENT) );
if ( !tmp )
{
/**
* The realloc operation failed.  How you handle this
* depends on the needs of you program, but realize
* that the previously-allocated memory is still
* there and that arr still points to it.  In this
* case, we’ll just print an error message and exit
* the loop.
*/
fputs( "Realloc failed, not accepting any more input", stderr );
done = 1;
continue;
}
else
{
size += 3;
arr = tmp;
}
}
/**
* The following line is just a placeholder for whatever
* logic you use to obtain the next value for the array.
* We’ll assume it sets the "done" condition appropriately
* and doesn’t increment i unnecessarily.
*/
arr[i++] = new_value();
}

相关内容

最新更新