malloc如何获取比分配的字节数更多的数据

malloc如何获取比分配的字节数更多的数据,c,pointers,malloc,free,dynamic-memory-allocation,C,Pointers,Malloc,Free,Dynamic Memory Allocation,根据我对malloc()的理解,它允许我们在运行时动态分配内存。下面是我正在研究的代码 #include<conio.h> #include<stdio.h> #include<stdlib.h> #include<string.h> void main() { char *description; clrscr(); description = malloc(2*sizeof(char)); strcpy(description,

根据我对
malloc()
的理解,它允许我们在运行时动态分配内存。下面是我正在研究的代码

#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main() {
  char *description;
  clrscr();
  description = malloc(2*sizeof(char));
  strcpy(description,"Hello there!");
  printf("%s",description);
  free(description);
  printf("%s",description);
  getch();
}
#包括
#包括
#包括
#包括
void main(){
字符*描述;
clrsc();
description=malloc(2*sizeof(char));
strcpy(描述,“你好!”;
printf(“%s”,说明);
免费(描述);
printf(“%s”,说明);
getch();
}
我的问题是,我要求系统在
malloc()
函数中分配2个字节的内存。因此,当我尝试填充字符串
“您好!”
并打印相同的内容时,我应该只得到字符串的前两个字符作为输出,但我得到的是在输出中的
strcpy()
函数中给出的整个字符串


同样,在我使用
free()
函数之后,如果我再次尝试打印
description
,如果我没有错的话,我应该不会得到任何输出,但我仍然得到相同的字符串。也许你知道这是怎么回事。我使用Turbo C++编译器。

Malc分配2字节。这意味着从一个起点(malloc返回的起点)给我2个字节。 strcpy复制字符串“hello there!”中从描述中的地址开始的所有字节。这与分配无关,它只是复制字节。printf中的%s告诉printf查找以null结尾的字符串

free()用于告诉内存管理器字节可以再次用于其他目的。它不会删除已经存在的数据


正如@Michael Foukarakis指出的,在未分配的内存中写入字节可能会导致未定义的行为。如果在语句之间未分配的内存中写入其他内容,则会中断

如果你放更多的数据,那么merory大小的beaviour将是不可预测的

没有任何东西会警告您的错误操作,但内存故障随时可能发生

description = malloc(2*sizeof(char));
您正在请求2字节的存储空间。如果成功,所有的内存
description
将指向您可以安全使用的内存

strcpy(description,"Hello there!");
您正在写入的内存超过了分配给
malloc
(证明:“你好!”的长度超过2),因此您的程序调用未定义的行为

printf("%s",description);
free(description);
printf("%s",description);
在调用未定义行为的程序中,上述三行都没有任何意义。他们的任何期望都是毫无根据和错误的

此外,尝试在
自由(描述)之后打印
描述所指向的字符串(假定为)
还调用未定义的行为。

函数
malloc()
至少分配您请求的内存量,尽管它可能更大。然而,
malloc()
提供的内存量并不是这里真正的核心问题

C编程语言是为速度和效率而设计的,这意味着其他语言所做的许多检查都没有完成。因此,您可以编写一个程序,它做了一些错误的事情,它仍然会在某些情况下工作,在其他情况下不工作

在C语言中,指针是内存位置的地址。C不检查地址是否为有效地址。C不会检查您尝试使用的内存量是否正确

这是你的程序的注释版本

#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main() {
  char *description;   // create a variable that will contain the address of a character
  clrscr();
  // allocate an array of characters. the number of characters is 2 so this
  // will allocate a minimum size memory area that will hold 2 characters.
  // malloc() may round up the size or it may not but all you can count on
  // is 2 characters in size.
  description = malloc(2*sizeof(char));
  // copy a constant string to the memory location pointed to by the variable
  // description. the strcpy() function does not check on the limits of the
  // memory. after the malloc() is done there is no size information available
  // to strcpy() or any other of the C runtime library functions in the C Standard Library
  // this is copying 11 characters plus the end of string for a total of 12 characters
  // so to be correct the memory area pointed to by description should be at least
  // 12 characters however we know from the malloc() above it is guaranteed to
  // be only 2 characters so we are going past the memory area with this strcpy().
  strcpy(description,"Hello there!");
  // however we get lucky and it works anyway.
  printf("%s",description);
  // tell the memory allocation library that you are done with the memory and it
  // can be used for something else now. the pointer will probably still be good
  // for a while because the memory allocation, which gets its memory from the
  // operating system, does not normally give any freed memory back to the OS.
  // instead it normally just keeps it until the application terminates.
  // as long as this freed memory is not used for something else, more than
  // likely whatever you put there will remain there as is. however the moment
  // the memory is given to something else, the values will change.
  free(description);
  printf("%s",description);
  getch();
}
使用Visual Studio 2013并在调试模式下运行时,我会收到一条关于应用程序终止时内存被覆盖的警告。当我执行发布构建并运行它时,没有错误,我得到以下输出。正如您所看到的,
strcpy()
函数只是复制了覆盖相邻内存的字符。看起来Visual Studio 2013编译器正在双字边界上对齐内存,以便在相邻内存区域中只能看到字符串的最后几个字符。Visual Studio填充了变量
array2[]
,以便分配的下一个变量位于双字边界上

Before
  array1
  array2
  array3
description Hello there!

After
  array1
  array2 Hello there!
  array3 ere!
如果我们将上述程序修改为以下内容:

#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main() {
    char array1[12] = { 0 };
    char array2[2] = { 0 };
    char array3[12] = { 0 };
    char *description;
    int  *values;
    printf("Before\n  array1 %s\n", array1);
    printf("  array2 %s\n", array2);
    printf("  array3 %s\n", array3);

    description = &array2[0];
    strcpy(description, "Hello there!");
    printf("description %s\n", description);

    printf("\nAfter\n  array1 %s\n", array1);
    printf("  array2 %s\n", array2);
    printf("  array3 %s\n", array3);

    description = malloc(8 * sizeof(char));
    strcpy(description, "this");
    printf("\n\nMalloc\n  first description %p %s\n", description, description);
    free(description);

    values = malloc(1 * sizeof(int));
    *values = 0;
    printf("  pointer %p and value %d\n", values, *values);
    printf("  second description %p %s\n", description, description);

}
资源所有权原则

此示例演示了使用
malloc()
free()
时的两条规则

使用
malloc()
分配所需的内存量,并且永远不要超过所请求的内存量。如果需要更多,请查看
realloc()
函数

使用
free()
释放内存区域后,切勿再次使用该指针值。一旦内存区域被释放,您就不再拥有它


当您使用
malloc()
时,您将成为内存的所有者,但只拥有您请求的内存。当你使用
free()
时,你放弃了对内存的所有权,你不应该再使用它,因为你不再拥有它。

你是在自食其果。传统的设计决策是,C语言允许你开枪打自己的脚。像C这样的系统语言必须允许你开枪打自己的脚。解决办法是不要这样做。更直截了当地说,C要求你知道你到底在做什么,对你不拥有的内存进行写入或读取总是未定义的行为。它有时似乎会起作用。它也会经常破裂。别这样,谢谢你,帕特里克!我想知道,即使在使用free()函数将分配从描述中释放出来之后,如何仍能打印数据。free()用于告诉内存管理器字节可以再次用于其他目的。它不会删除已经存在的数据谢谢。这就解释了我的疑问:)谢谢你解释得这么好,迈克尔。我确实是在打自己的脚。
#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main() {
    char array1[12] = { 0 };
    char array2[2] = { 0 };
    char array3[12] = { 0 };
    char *description;
    int  *values;
    printf("Before\n  array1 %s\n", array1);
    printf("  array2 %s\n", array2);
    printf("  array3 %s\n", array3);

    description = &array2[0];
    strcpy(description, "Hello there!");
    printf("description %s\n", description);

    printf("\nAfter\n  array1 %s\n", array1);
    printf("  array2 %s\n", array2);
    printf("  array3 %s\n", array3);

    description = malloc(8 * sizeof(char));
    strcpy(description, "this");
    printf("\n\nMalloc\n  first description %p %s\n", description, description);
    free(description);

    values = malloc(1 * sizeof(int));
    *values = 0;
    printf("  pointer %p and value %d\n", values, *values);
    printf("  second description %p %s\n", description, description);

}
Before
  array1
  array2
  array3
description Hello there!

After
  array1
  array2 Hello there!
  array3 ere!


Malloc
  first description 00944B28 this
  pointer 00944B28 and value 0
  second description 00944B28