繁体   English   中英

在C编程中需要有关malloc的帮助。 它分配的空间比预期的多

[英]Need help with malloc in C programming. It is allocating more space than expected

让我先说一下,我是一个新手,我在学校的入门级C班。

我正在编写一个程序,要求我使用malloc和malloc在所有情况下分配8倍我期望的空间。 即使只是对malloc(1),它是分配8个字节而不是1,我很困惑为什么。

这是我测试过的代码。 这应该只允许输入一个字符加上转义字符。 相反,我可以输入8,所以它分配8 bytes而不是1 ,即使我只使用malloc()的整数也是如此。 请忽略x变量,它在实际程序中使用,但不在此测试中。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


int main (int argc ,char* argv[]){

    int x = 0;
    char *A = NULL;
    A=(char*)malloc(sizeof(char)+1);
    scanf("%s",A);
    printf("%s", A);
    free(A);
    return 0;
}
 A=(char*)malloc(sizeof(char)+1);

将分配至少2个字节(sizeof(char)始终为1)。 我不明白你是如何确定它分配8个字节,但是malloc被允许分配比你要求的更多的内存,只是永远不会少。

您可以使用scanf将更长的字符串写入A指向的内存这一事实并不意味着您已分配了该内存。 它会覆盖那里的任何内容,这可能会导致程序崩溃或产生意外结果。

malloc正在分配你所要求的内存。

如果您可以读取超过分配的字节数(使用scanf ),那是因为scanf也在您拥有的内存上读取:它是缓冲区溢出。

您应该限制数据scanf可以这样读取:

scanf( "%10s", ... ); // scanf will read a string no longer than 10

我正在编写一个程序,要求我使用malloc和malloc在所有情况下分配8倍我期望的空间。 即使只是对malloc(1),它是分配8个字节而不是1,我很困惑为什么。

从理论上讲,你在程序中做事的方式是不分配8 bytes

您仍然可以键入8个字节(或任意数量的字节),因为在C中没有检查,您仍然使用有效的写入位置。

你看到的是Undefined Behaviour ,原因是你在内存中写下你不应该这样做。 在使用了您分配的n个字节后,代码中没有任何内容可以停止程序。

您可能现在或稍后或从不会遇到Seg Fault 这是未定义的行为。 仅仅因为它似乎有效,并不意味着它是正确的。

现在,您的程序确实可以分配8个字节而不是1个字节。

原因是因为对齐

同一程序可能在不同的机器和/或不同的操作系统中分配不同的大小。

此外,由于你使用C你真的不需要施放。 一下这个开始。

在您的代码中,使用scanf可以加载多少数据没有限制,从而导致缓冲区溢出(安全漏洞/崩溃)。 您应该使用格式字符串将读取的数据量限制为您分配的一个或两个字节。 malloc函数可能会分配一些额外的空间来扩大规模,但你不应该依赖它。

你在运行什么系统? 如果是64位,系统可能会分配尽可能小的单位。 64位是8个字节。

编辑:只是一个感兴趣的说明:

char *s = malloc (1);

导致在iOS 4.2(Xcode 3.2.5)上分配16个字节。

允许malloc分配比你要求的内存更多的内存。 它只需要提供至少与您要求的一样多,或者如果不能提供则失败。

使用malloc或在堆栈上创建缓冲区将以单词分配内存。

在32位系统上,字大小为4字节,所以当你要求时

A=(char*)malloc(sizeof(char)+1);

(基本上是A=(char*)malloc(2);

系统实际上会给你4个字节。 在64位计算机上,您应该获得8个字节。

您使用scanf的方式很危险,因为如果字符串大于分配的大小,它会溢出缓冲区,从而在程序中留下堆溢出漏洞。 在这种情况下, scanf会尝试将任意长度的字符串填充到该内存中,因此使用它来计算分配的大小将不起作用。

如果你输入8如果只是分配2个字节sizeof(char) == 1 (unless you are on some obscure platform) ,你将把你的数字写给那个char。 然后在printf输出你存储在那里的数字。 因此,如果存储数字8,它将在命令行上显示8。 它与分配的字符数无关。 除非您在调试器或其他地方查找它实际上是在分配8个字节。

scanf不知道目标缓冲区实际有多大。 它只知道缓冲区的起始地址。 C没有边界检查,因此如果你传递一个大小为2个字符的缓冲区的地址,并输入一个长度为10个字符的字符串, scanf会在缓冲区末尾后将这8个字符写入内存。 这称为缓冲区溢出,这是一种常见的恶意软件漏洞。 无论出于何种原因,紧跟缓冲区后的六个字节不是“重要”,因此您最多可以输入8个字符,没有明显的不良影响。

您可以通过在转换说明符中包含显式字段宽度来限制scanf调用中读取的字符数:

scanf("%2s", A);

但是仍然需要确保目标缓冲区足够大以容纳该宽度。 不幸的是,没有办法像printf一样动态指定字段宽度:

printf("%*s", fieldWidth, string);

因为%*s表示scanf 完全不同的东西(基本上,跳过下一个字符串)。

您可以使用sprintf来构建格式字符串:

sprintf(format, "%%%ds", max_bytes_in_A);
scanf(format, A);

但你必须确保缓冲区format足够宽以保存结果等,等等。

这就是我通常建议用于交互式输入的fgets()原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM