据我所知,malloc(x)返回一个x字节长的内存块。
所以为了存储一个4字节的整数,我会这样做:
int *p = (int *)malloc(4);
*p = 100;
因为sizeof(int)为我返回4。
但是,如果我这样做:
int *p = (int *)malloc(1);
*p = 100;
它似乎完全相同,没有存储值的问题。
为什么malloc()请求的内存量似乎不重要?不应该是4字节整数需要malloc(4)吗?
答案 0 :(得分:4)
如果这适用于您的情况,它只是偶然的工作,并不保证工作。它是未定义的行为(比较this SO question),一切都可能发生。
您期望发生什么?你的程序崩溃了?
如果您更频繁地拨打for (int i = 0; i <= dt.Rows.Count; i++)
和for (int i = 0; i < dt.Rows.Count; i++)
,可能仍会发生这种情况。 malloc
通常比请求的字节数多一些,并使用额外的空间进行管理(所有内存块的链表,内存块的大小)。如果你在分配的块之前或之后写了一些字节,那么你很可能会混淆内部管理结构,而free
的后续malloc
会崩溃。
如果malloc内部总是分配最少n个字节,那么如果访问字节n + 1,程序可能只会崩溃。此外,操作系统通常仅基于页面保护存储器。如果一个页面的大小为512字节,并且您的malloc-ed字节位于页面的中间,那么您的进程可能能够读写页面的其余部分,并且只会在访问下一个内存页面时崩溃。但请记住:即使这有效,也是未定义的行为。
答案 1 :(得分:2)
它似乎完全相同,没有存储值的问题。
您使用代码调用未定义的行为,因此您无法确定它是否有效。为了为整数分配内存,你应该这样做:
int *p;
p = malloc(sizeof (*p) ); //you can use sizeof(*p) as p is already declared and here you use the size of its content, which is actually the size of an int
if (p != NULL)
*p = 100;
答案 2 :(得分:2)
C编程语言让你能够用脚射击自己。
它故意给程序员带来负担,他们应该知道他们在做什么。从广义上讲,原因是要实现性能,可读性和可移植性。
代码的行为是未定义。如果要求1个字节,则期望只返回一个可用字节。事实上,操作系统和C运行时库似乎给你的回馈不过是一个奇怪的特点。
在其他情况下,编译器可能只是吃你的猫。
最后,在malloc
的调用中使用int
,而不是硬编码sizeof(int)
类型的大小:在许多系统上sizeof(int)
是2,4,这是常见的,并且标准允许所有大于1的值。在您的情况下,可以使用sizeof(*p)
或sizeof
。有些人喜欢后者,因为那时你并没有在sizeof(*p)
调用中硬编码变量的类型,所以要防止可能的变量类型更改。 (注意p
是编译时可评估的并且使用静态类型信息;因此它可以在[ 2017-01-24 08:27:50.0090 24342/7f8d9164f780 apache2/Hooks.cpp:718 ]: Unexpected error in mod_passenger: Cannot connect to the helper agent at /tmp/passenger.1.0.20176/generation-0/request
Backtrace:
in 'Passenger::FileDescriptor Hooks::connectToHelperAgent()' (Hooks.cpp:283)
in 'int Hooks::handleRequest(request_rec*)' (Hooks.cpp:532)
[Tue Jan 24 08:36:41.659372 2017] [mpm_prefork:notice] [pid 20176] AH00169: caught SIGTERM, shutting down
[ 2017-01-24 08:36:41.6769 20188/7ff6b3484780 agents/LoggingAgent/Main.cpp:289 ]: Caught signal, exiting...
[ 2017-01-24 08:36:43.6948 29025/7f612a691740 agents/Watchdog/Main.cpp:538 ]: Options: { 'analytics_log_user' => 'nobody', 'default_group' => 'nogroup', 'default_python' => 'python', 'default_ruby' => '/usr/bin/ruby1.9.1', 'default_
[ 2017-01-24 08:36:43.6976 29028/7ff0c7127740 agents/HelperAgent/Main.cpp:643 ]: PassengerHelperAgent online, listening at unix:/tmp/passenger.1.0.29024/generation-0/request
[ 2017-01-24 08:36:43.7020 29033/7fe594edb780 agents/LoggingAgent/Main.cpp:321 ]: PassengerLoggingAgent online, listening at unix:/tmp/passenger.1.0.29024/generation-0/logging
[ 2017-01-24 08:36:43.7021 29025/7f612a691740 agents/Watchdog/Main.cpp:728 ]: All Phusion Passenger agents started!
[ 2017-01-24 08:36:43.7205 29047/7fa61ed1c740 agents/Watchdog/Main.cpp:538 ]: Options: { 'analytics_log_user' => 'nobody', 'default_group' => 'nogroup', 'default_python' => 'python', 'default_ruby' => '/usr/bin/ruby1.9.1', 'default_
[ 2017-01-24 08:36:43.7234 29051/7f78162fe740 agents/HelperAgent/Main.cpp:643 ]: PassengerHelperAgent online, listening at unix:/tmp/passenger.1.0.29045/generation-0/request
[ 2017-01-24 08:36:43.7277 29057/7f83146cc780 agents/LoggingAgent/Main.cpp:321 ]: PassengerLoggingAgent online, listening at unix:/tmp/passenger.1.0.29045/generation-0/logging
[ 2017-01-24 08:36:43.7279 29047/7fa61ed1c740 agents/Watchdog/Main.cpp:728 ]: All Phusion Passenger agents started!
[Tue Jan 24 08:36:43.737820 2017] [mpm_prefork:notice] [pid 29045] AH00163: Apache/2.4.6 (Ubuntu) Phusion_Passenger/4.0.40 PHP/5.5.3-1ubuntu2.2 configured -- resuming normal operations
[Tue Jan 24 08:36:43.737856 2017] [core:notice] [pid 29045] AH00094: Command line: '/usr/sbin/apache2'
App 29105 stdout:
App 29105 stderr: /var/lib/gems/1.9.1/gems/passenger-4.0.40/lib/phusion_passenger/platform_info.rb:352: warning: Insecure world writable dir /usr/local/bin in PATH, mode 040777
[ 2017-01-24 08:36:50.8464 29051/7f7816207700 Pool2/SmartSpawner.h:301 ]: Preloader for /usr/share/redmine started on PID 29105, listening on unix:/tmp/passenger.1.0.29045/generation-0/backends/preloader.29105
App 29145 stdout:
本身&#34;存在&#34;之前使用,如果你明白我的意思。)
答案 3 :(得分:1)
为此,我们应该知道malloc函数在内部如何工作。为了动态分配内存,每个操作系统都使用系统调用。我们可以使用这些系统调用动态分配内存。这些系统调用与一个操作系统不同。
因此,一个操作系统的系统调用可能不适用于另一操作系统。而且,如果我们使用系统调用动态分配内存,那么我们的程序将依赖于平台。因此,为了避免这种依赖性,我们使用malloc函数。现在,malloc函数负责根据操作系统进行适当的系统调用以动态分配内存。
因此,malloc本身会调用系统调用,这将是一个非常缓慢的过程,因为每次我们请求动态内存时,它都必须利用系统调用。为了避免这种情况,每当我们请求动态内存时,它通常都会分配额外的内存,以便下次可以避免系统调用并可以使用先前分配的内存的剩余块。这就是为什么您的程序在malloc分配额外的内存时工作的原因。
答案 4 :(得分:0)
通常malloc
的实现方式是,它分配的内存大小不小于段落大小等于16个字节。
因此,当您需要例如4个字节的内存{{1}}实际分配16个字节时。但是,此行为未在C标准中描述,您可能不会依赖它。结果,这意味着您显示的程序具有未定义的行为。
答案 5 :(得分:0)
我认为这是因为填充,即使你正在调用malloc(1)
填充字节随内存一起提供。
请查看此链接http://www.delorie.com/gnu/docs/glibc/libc_31.html
答案 6 :(得分:0)
malloc
,因为来自C运行时或OS内核的所有内存块分配函数都针对内存访问和对象对齐进行了优化。
此外,malloc
具体而言,在分配的空间前分配一个隐藏的控制块,以跟踪分配(所需空间,空间分配等)。
malloc
还必须保证分配的内存地址适合任何存储对象,这意味着该块将以8,16,32甚至64或8开始128字节边界取决于处理器和一般来自硬件(即一些特殊MMU)。边界也取决于访问速度,某些处理器具有不同的行为,具有不同的存储器访问(1,2,4,8,...字节)和地址边界。这种约束驱动malloc
代码规范和分配器逻辑内存块分区。
在实际的一面让我们考虑一个X86处理器的分配器,它通常会返回一个在8字节边界(32位代码)上对齐的块,这对int,float和偶数都很有用。为此,malloc
将可用内存区域划分为最小分配空间的“块”。当您分配甚至1个字节时,该函数至少分配一个块。最终这个块可以托管一个整数,甚至是一个double,,但它依赖于实现,你不能认为它是确定性的,因为在同一个函数的未来版本中,行为可以改变。
现在,我希望,很清楚,因为您的代码似乎有效,请记住这是未定义的行为,您必须保留它。 IT现在可以工作,而不是下一次修订,它可能会在某些硬件上崩溃,而不会在另一台处理器或机器上崩溃。
答案 7 :(得分:0)
简单地说,当你为 int 分配 1 个字节时,后面还有 3 个字节实际上没有分配给它,但你仍然可以使用它们。您很幸运,这些在您的测试期间没有被其他东西改变,并且它没有覆盖任何重要的东西(或者可能是)。所以本质上,一旦其他东西需要这 3 个字节,这将导致错误 - 始终分配正确的大小。