我是C的新手,对不起,如果这个问题已经回答了,我找不到一个直接的答案,所以我们开始了。
我试图了解 malloc() 在 C 中的工作原理。我有这个代码:
#define MAXLINE 100
void readInput(char **s)
{
char temp[MAXLINE];
printf("Please enter a string: ");
scanf("%s", temp);
*s = (char *)malloc((strlen(temp)+1)*sizeof(char)); // works as expected
//*s = (char *)malloc(2*sizeof(char)); // also works even when entering 10 chars, why?
strcpy ((char *)*s, temp);
}
int main()
{
char *str;
readInput(&str);
printf("Your string is %sn", str);
free(str);
return 0;
}
问题是为什么当我像这样调用 malloc() 时程序没有崩溃(或至少去除剩余的字符):
*s = (char *)malloc(2*sizeof(char)); // also works even when entering 10 chars, why?
如果我输入包含两个以上字符的字符串,这不会导致缓冲区溢出吗?正如我所理解的 malloc(),它为数据分配了一个固定的空间,因此当然只为两个字符分配空间将允许字符串最多有一个可用字符('0\' 是第二个),但它仍然打印出所有输入的 10 个字符。
附言我正在使用Xcode,如果这有什么不同的话。
谢谢Simon
效果很好,因为你很幸运!通常,操作系统会为您的程序提供一个大于 2 个字节的块。
如果操作系统在你要求 2 个字节时实际上给了你 16 个字节,你可以在操作系统没有注意到的情况下写入 16 个字节。但是,如果您的程序中有另一个使用其他 14 个字节的malloc()
,您将覆盖该变量内容。
操作系统不在乎你在自己的程序中乱搞。只有当你在操作系统给你的内容之外写入时,你的程序才会崩溃。
尝试写入 200 字节,看看它是否崩溃。
编辑:
malloc()
和 free()
使用一些堆空间来维护有关已分配内存的信息。此信息通常存储在内存块之间。如果缓冲区溢出,此信息可能会被覆盖。
是的,将更多数据写入分配的缓冲区是缓冲区溢出。 但是,C 中没有缓冲区溢出检查,如果缓冲区后恰好有有效内存,则代码看起来可以正常工作。
但是,您所做的是将不属于您的内存写入内存,并且可能已损坏堆。 你对free
或malloc
的下一次调用可能会崩溃,或者如果不是下一个调用,以后的某个调用可能会崩溃,或者你可能很幸运,malloc
给你一个比你请求的更大的缓冲区,在这种情况下,你永远不会看到问题。
如果我输入包含两个以上字符的字符串,这不会导致缓冲区溢出吗?
绝对。 但是,C 在运行时不进行边界检查;它假定您在分配内存时知道自己在做什么,并且知道有多少可用内存。 如果你越过缓冲区的尽头,你会破坏以前存在的东西。
这是否会导致您的代码崩溃取决于以前存在的内容以及您破坏它的内容。 并非所有溢出都会杀死您的程序,堆中的溢出可能根本不会导致任何(明显的)问题。
这是因为即使您没有分配内存,内存也存在。您正在访问不属于您的数据,并且可能使用良好的调试器或静态分析器,您会看到错误。
此外,如果你有一个变量就在你分配的块后面,它可能会被你输入的内容覆盖。
简单地说,这是未定义行为的情况之一。你很不幸,你得到了预期的结果。
它确实会导致缓冲区溢出。但是 C 不做任何事情来防止缓冲区溢出。malloc的大多数实现也是如此。
通常,缓冲区溢出的崩溃仅在以下情况下发生:
- 它溢出页面 - malloc 实际从操作系统获取的内存单元。Malloc 将满足来自同一内存页的许多单独分配请求。
- 溢出会损坏缓冲区后面的内存。这不会导致立即崩溃。当其他代码运行时,它会导致崩溃,这取决于该内存的内容。
(...但这些事情取决于所涉及的系统的具体情况。
如果幸运的话,缓冲区溢出完全有可能永远不会导致崩溃。尽管它可能会产生其他不太明显的问题。
>malloc() 是在 Stdlib.h 头文件中指定的函数调用。如果您使用的是数组,则必须在使用之前固定内存长度。但是在 malloc() 函数中,您可以在需要时以所需的大小分配内存。当您通过 malloc() 分配内存时,它将搜索内存模块并找到空闲块。即使内存块位于不同的地方,它也会分配一个地址并连接所有块。流程完成后,您可以释放它。免费意味着,分配内存仅在 RAM 中。处理函数并生成一些数据后,会将数据转移到硬盘或任何其他永久存储中。之后,您可以释放块,以便可用于其他数据。如果你正在通过指针函数,如果没有 malloc(),你不能制作数据块。New() 是 c++ 的关键字。
当你不知道当你在编程时你需要多大的内存空间时,你可以使用函数malloc
空 *马洛克(size_t大小);malloc() 函数应为对象分配未使用的空间,该对象的大小(以字节为单位)由大小指定,其值未指定。
它是如何工作的是一个问题...
所以您的系统具有自由链列表,其中列出了所有可用的内存空间,malloc 会搜索此列表,直到找到您需要的足够大的空间。然后它将这个空间分成 2 个,向您发送所需的空间,并将另一个放回列表中。它分成 2^n 大小的碎片,这样您的列表中就不会有奇怪的空间大小,这使得它像乐高一样容易。
当您调用"免费"时,您的区块将回到免费链列表。