在C中使用malloc

时间:2017-07-08 11:28:34

标签: c malloc realloc

我是C的初学者。我想知道,malloc是如何工作的。 这是一个示例代码,我在试图理解它的工作时写了。

CODE:

#include<stdio.h>
#include<stdlib.h>
int main() {
  int i;
  int *array = malloc(sizeof *array);
  for (i = 0; i < 5; i++) {
    array[i] = i+1;
  }
  printf("\nArray is: \n");
  for (i = 0; i < 5; i++) {
    printf("%d ", array[i]);
  }
  free(array);
  return 0;
}

输出:

Array is: 
1 2 3 4 5

在上面的程序中,我只为1个元素分配了空间,但现在该数组包含5个元素。因此,当程序顺利运行而没有任何错误时,realloc()的目的是什么。

有人可以解释原因吗?

提前致谢。

3 个答案:

答案 0 :(得分:6)

程序运行顺利并不意味着它是正确的! 尝试在某种程度上增加for循环中的5(例如,500000就足够了)。在某些时候,它将停止工作,为您提供SEGFAULT

这称为未定义行为。

valgrind也会警告您有关以下内容的问题。

==16812== Invalid write of size 4
==16812==    at 0x40065E: main (test.cpp:27)

答案 1 :(得分:3)

这是典型的undefined behavior(UB)。

您不能像这样编码。作为一个初学者,认为这是一个错误,一个错误,一个罪恶,一些非常肮脏的东西等。

  

有人可以解释原因吗?

如果您需要了解真正正在发生什么(并且细节很复杂),您需要深入了解您的实施细节(而且您并不想)。例如,在Linux上,您可以学习C标准库,内核,编译器等的源代码。您需要了解编译器生成的机器代码(所以使用GCC编译时gcc -S -O1 -fverbose-asm获取.s汇编程序文件。)

另请参阅this(其中包含更多参考资料)。

尽快阅读Lattner的博客What Every C programmer should know about undefined behavior。每个人都应该阅读它!

关于UB最糟糕的事情是,遗憾的是,有时,它出现到&#34;工作&#34;就像你想要的那样(但事实上并非如此)。

尽可能快地学习以系统地避免UB。

顺便说一下,启用编译器中的所有警告可能会有所帮助(但在您的特定情况下可能不会)。如果使用GCC,请习惯使用gcc -Wall -Wextra -g进行编译。

请注意,您的程序没有任何数组。 array变量是指针(不是数组),因此命名非常糟糕。您需要阅读有关指针和C dynamic memory allocation的更多信息。

 int *array = malloc(sizeof *array); //WRONG

非常错误。名称array的选择非常糟糕(它是一个指针,而不是一个数组;你应该花几天时间阅读有什么区别 - 以及#34;数组如何衰减成指针& #34;意思是)。您分配的sizeof(*array)sizeof(int)完全相同(通常至少4个字节,至少在我的机器上)。因此,您只为一个 int元素分配空间。除此之外的任何访问(即具有任何甚至小的正索引,例如array[1]array[i]且具有一些正i)都是undefined behavior。你甚至不能测试malloc可以发生)的失败。

如果你想为({比如说)8 int - s分配内存空间,你应该使用:

int* ptr = malloc(sizeof(int) * 8);

当然你应该检查失败,至少:

if (!ptr) { perror("malloc"); exit(EXIT_FAILURE); };

你需要初始化那个数组(你的内存包含不可预测的垃圾),例如

for (int i=0; i<8; i++) ptr[i] = 0;

或者您可以使用

清除所有位(在我知道的所有机器上具有相同的结果)
memset(ptr, 0, sizeof(int)*8);

请注意,即使在成功执行此类malloc(或失败的sizeof(ptr)之后,您总是malloc相同(在我的Linux / x86-64框中,它是8个字节),因为它是指针的大小(即使你int - 为一百万 #define MY_ARRAY_LENGTH 8 - s的内存区域。

实际上,当您使用C dynamic memory allocation时,您需要知道常规该指针的已分配大小。在上面的代码中,我在几个的地方使用了8个,这样的风格很差。至少

会更好
MY_ARRAY_LENGTH

并使用8,而不是 int* ptr = malloc(MY_ARRAY_LENGTH*sizeof(int)); ,从

开始
expectedDate = [int(i) for i in (input().split(" "))]
actualDate = [int(i) for i in (input().split(" "))]

在实践中,分配的内存通常具有运行时定义的大小,并且您将保留大小的某个位置(在变量,参数等中......)。

研究一些现有免费软件项目的源代码(例如在github上),您将学习非常有用的东西。

还阅读(可能在一两周内)flexible array members。有时它们非常有用。

答案 2 :(得分:1)

  

因此程序运行顺利,没有任何错误

那只是因为你很幸运。继续运行此程序,您可能很快就会出现段错误。您依赖未定义的行为(UB),这总是一件坏事。

  

realloc()的目的是什么?

从手册页:

void *realloc(void *ptr, size_t size);
  

realloc()函数改变指向的内存块的大小   通过ptr来调整字节大小。内容将在该范围内保持不变   从该地区的起点到新旧规模的最小值。如果新尺寸大于旧尺寸,则添加   记忆          不会被初始化。如果ptr为NULL,则对于所有size值,调用等效于malloc(size);如果大小相等   零,          并且ptr不为NULL,则调用等效于free(ptr)。除非ptr为NULL,否则它必须由a返回   之前调用malloc(),calloc()或realloc()。如果指向的区域被移动,则完成免费(ptr)。