我å¯ä»¥ä½¿ç”¨æ¯”使用malloc()分é…的内存更多的内存,为什么?

时间:2010-08-18 07:08:18

标签: c

char *cp = (char *) malloc(1);
strcpy(cp, "123456789");
puts(cp);
gcc(Linux)和Visual C ++ Express上的

输出是“123456789â€ï¼Œè¿™æ˜¯å¦æ„味ç€å½“有空闲内存时,我实际上å¯ä»¥ä½¿ç”¨çš„内容超过我用malloc()分é…的内容?

以åŠä¸ºä»€ä¹ˆmalloc(0)ä¸ä¼šå¯¼è‡´è¿è¡Œæ—¶é”™è¯¯ï¼Ÿ

感谢。

17 个答案:

答案 0 :(得分:61)

你问过一个éžå¸¸å¥½çš„问题,也许这会激起你对æ“作系统的兴趣。您已ç»çŸ¥é“自己已ç»è®¾æ³•é€šè¿‡æ­¤ä»£ç å®žçŽ°äº†ä¸€äº›æ‚¨é€šå¸¸ä¸å¸Œæœ›åšçš„事情。因此,您永远ä¸ä¼šåœ¨æƒ³è¦ç§»æ¤çš„代ç ä¸­æ‰§è¡Œæ­¤æ“作。

更具体地说,这完全å–决于您的æ“作系统和CPU架构,æ“作系统会为您的程åºåˆ†é…“页é¢â€å†…å­˜ - 通常这å¯èƒ½æ˜¯4åƒå­—节的顺åºã€‚æ“作系统是页é¢çš„守护者,将立å³ç»ˆæ­¢å°è¯•è®¿é—®å°šæœªåˆ†é…的页é¢çš„任何程åºã€‚

å¦ä¸€æ–¹é¢ï¼Œ

mallocä¸æ˜¯æ“作系统函数,而是C库调用。它å¯ä»¥é€šè¿‡å¤šç§æ–¹å¼å®žçŽ°ã€‚您对malloc的调用å¯èƒ½ä¼šå¯¼è‡´æ¥è‡ªæ“作系统的页é¢è¯·æ±‚。然åŽmalloc决定给你一个指å‘该页é¢å†…å•ä¸ªå­—节的指针。当你从你给出的ä½ç½®å†™å…¥å†…存时,你åªæ˜¯å†™åœ¨æ“作系统授予你程åºçš„“页é¢â€ä¸­ï¼Œå› æ­¤æ“作系统ä¸ä¼šçœ‹åˆ°ä»»ä½•é”™è¯¯çš„æ“作。

当然,当您继续致电malloc以分é…更多内存时,真正的问题就会开始。它最终将返回指å‘您刚刚写入的ä½ç½®çš„指针。当您写入åˆæ³•çš„内存ä½ç½®ï¼ˆä»Žæ“作系统的角度æ¥çœ‹ï¼‰æ—¶ï¼Œè¿™ç§°ä¸ºâ€œç¼“冲区溢出â€ï¼Œä½†å¯èƒ½ä¼šè¦†ç›–程åºçš„å¦ä¸€éƒ¨åˆ†ä¹Ÿå°†ä½¿ç”¨çš„内存。

如果你继续了解这个主题,你将开始ç†è§£å¦‚何使用这ç§â€œç¼“冲区溢出â€æŠ€æœ¯æ¥åˆ©ç”¨ç¨‹åº - 甚至å¯ä»¥å¼€å§‹å°†æ±‡ç¼–语言指令直接写入将è¦å­˜å‚¨çš„内存区域。由你的程åºçš„å¦ä¸€éƒ¨åˆ†æ‰§è¡Œã€‚

当你进入这个阶段时,你将获得很多智慧。但请éµå®ˆé“德规范,ä¸è¦ç”¨å®ƒæ¥ç ´å宇宙ï¼

PS当我说“æ“作系统â€æ—¶ï¼Œæˆ‘çš„æ„æ€æ˜¯â€œæ“作系统与特æƒCPU访问一起â€ã€‚如果进程å°è¯•ä½¿ç”¨å°šæœªåˆ†é…给该进程的页é¢ï¼Œåˆ™CPUå’ŒMMU(内存管ç†å•å…ƒï¼‰ä¼šè§¦å‘特定的æ“作系统中断或回调。然åŽï¼Œæ“作系统会干净地关闭您的应用程åºï¼Œå¹¶å…许系统继续è¿è¡Œã€‚在过去,在内存管ç†å•å…ƒå’Œç‰¹æƒCPU指令之å‰ï¼Œä½ å‡ ä¹Žå¯ä»¥éšæ—¶åœ¨å†…存中的任何地方写入 - 然åŽä½ çš„系统将完全å—到内存写入åŽæžœçš„支é…ï¼

答案 1 :(得分:21)

没有。您得到未定义的行为。这æ„味ç€ä»»ä½•äº‹æƒ…都å¯èƒ½å‘生,从它崩溃(yay)到它“工作â€ï¼ˆboo),é‡æ–°æ ¼å¼åŒ–你的硬盘并填充文本文件,说“UB,UB,UB ......â€ï¼ˆwat)。 / p>

在此之åŽæƒ³çŸ¥é“会å‘生什么是没有æ„义的,因为它å–决于你的编译器,平å°ï¼ŒçŽ¯å¢ƒï¼Œæ—¶é—´ï¼Œæœ€å–œæ¬¢çš„汽水等等,所有这些都å¯ä»¥éšå¿ƒæ‰€æ¬²åœ°åšä»»ä½•ä»–们想è¦çš„事情。

更具体地说,使用未分é…的任何内存是未定义的行为。你从malloc(1)得到一个字节,就是这样。

答案 2 :(得分:16)

当您å‘malloc询问1个字节时,它å¯èƒ½ä¼šä»Žæ“作系统获得1页(通常为4KB)。此页é¢å°†åˆ†é…给调用进程,因此åªè¦æ‚¨ä¸ç¦»å¼€é¡µé¢è¾¹ç•Œï¼Œå°±ä¸ä¼šæœ‰ä»»ä½•é—®é¢˜ã€‚

但请注æ„,它ç»å¯¹æ˜¯æœªå®šä¹‰çš„行为ï¼

考虑使用mallocæ—¶å¯èƒ½å‘生的以下(å‡è®¾ï¼‰ç¤ºä¾‹ï¼š

  1. malloc(1)
  2. 如果malloc 内部内存ä¸è¶³ï¼Œå®ƒä¼šå‘æ“作系统询问更多内容。它通常会收到一个页é¢ã€‚å‡è®¾å®ƒçš„大å°ä¸º4KB,地å€ä»Ž0x1000开始
  3. 您的通è¯ä¼šè¿”回给您使用的地å€0x1000。由于您è¦æ±‚1个字节,如果您仅使用地å€0x1000,则已定义行为。
  4. 由于æ“作系统刚刚从地å€0x1000开始为您的进程分é…4KB内存,因此如果您从/å‘地å€0x1000-0x1fff读å–/写入内容,它将ä¸ä¼šæŠ±æ€¨ã€‚所以你å¯ä»¥æ„‰å¿«åœ°è¿™æ ·åšï¼Œä½†å®ƒæ˜¯æœªå®šä¹‰çš„行为。
  5. å‡è®¾ä½ åšäº†å¦ä¸€ä¸ªmalloc(1)
  6. 现在mallocä»æœ‰ä¸€äº›å†…存,所以ä¸éœ€è¦å‘æ“作系统询问更多内存。它å¯èƒ½ä¼šè¿”回地å€0x1001。
  7. 如果您使用第一个mallocæ供的地å€å†™å…¥è¶…过1个字节,则在使用第二个malloc中的地å€æ—¶ä¼šé‡åˆ°éº»çƒ¦ï¼Œå› ä¸ºæ‚¨å°†è¦†ç›–æ•°æ®ã€‚
  8. 所以é‡ç‚¹æ˜¯ä½ è‚¯å®šä»Žmalloc 得到1个字节,但它å¯èƒ½æ˜¯malloc内部有更多的内存分é…给你进程。

答案 3 :(得分:3)

没有。这æ„味ç€æ‚¨çš„程åºè¡¨çŽ°ä¸ä½³ã€‚它写入它ä¸æ‹¥æœ‰çš„内存ä½ç½®ã€‚

答案 4 :(得分:2)

你得到未定义的行为 - 任何事情都å¯èƒ½å‘生。ä¸è¦è¿™æ ·åšï¼Œä¹Ÿä¸è¦çŒœæµ‹å®ƒæ˜¯å¦æœ‰æ•ˆã€‚也许它会破å记忆,你ä¸ä¼šç«‹åˆ»çœ‹åˆ°å®ƒã€‚仅访问分é…çš„å—大å°å†…的内存。

答案 5 :(得分:2)

您å¯èƒ½è¢«å…许使用,直到内存到达æŸä¸ªç¨‹åºå†…存或您的应用程åºå¾ˆå¯èƒ½å› è®¿é—®å—ä¿æŠ¤çš„内存而崩溃的其他点

答案 6 :(得分:2)

如此多的回应,åªæœ‰ä¸€ä¸ªç»™å‡ºäº†æ­£ç¡®çš„解释。虽然页é¢å¤§å°ï¼Œç¼“冲区溢出和未定义的行为故事都是真实的(并且很é‡è¦ï¼‰ï¼Œä½†å®ƒä»¬å¹¶ä¸å®Œå…¨å›žç­”原始问题。实际上,任何åˆç†çš„malloc实现都将至少分é…int或void *的对é½è¦æ±‚的大å°ã€‚为什么,因为如果它åªåˆ†é…了1个字节,那么下一个内存å—å°†ä¸å†å¯¹é½ã€‚总是有一些书ç±ä¿å­˜å›´ç»•ä½ åˆ†é…çš„å—çš„æ•°æ®ï¼Œè¿™äº›æ•°æ®ç»“构几乎总是与4çš„å€æ•°å¯¹é½ã€‚虽然一些架构å¯ä»¥è®¿é—®æœªå¯¹é½åœ°å€ï¼ˆx86)上的å•è¯ï¼Œä½†å®ƒä»¬ç¡®å®žä¼šå› æ­¤è€Œå—到一些惩罚,因此分é…器实现者é¿å…这样åšã€‚å³ä½¿åœ¨slab分é…器中,也没有必è¦è®¾ç½®ä¸€ä¸ª1字节的池,因为实际上很å°çš„分é…很少。所以很å¯èƒ½ä½ çš„malloc字节中有4或8个字节的真实空间(这并ä¸æ„味ç€ä½ å¯ä»¥ä½¿ç”¨é‚£ä¸ª'功能',这是错误的。)

编辑此外,大多数malloc会ä¿ç•™æ¯”è¦æ±‚时更大的å—,以é¿å…在调用realloc时进行多次å¤åˆ¶æ“作。作为测试,您å¯ä»¥å°è¯•åœ¨å¢žåŠ åˆ†é…大å°çš„循环中使用realloc并比较返回的指针,您将看到它仅在æŸä¸ªé˜ˆå€¼ä¹‹åŽå‘生å˜åŒ–。

答案 7 :(得分:1)

你在那里很幸è¿ã€‚您正在写入您ä¸æ‹¥æœ‰çš„ä½ç½®ï¼Œè¿™ä¼šå¯¼è‡´æœªå®šä¹‰çš„行为。

答案 8 :(得分:1)

在大多数平å°ä¸Šï¼Œæ‚¨ä¸èƒ½åªåˆ†é…一个字节。 malloc通常还会åšä¸€äº›å†…务处ç†æ¥è®°ä½åˆ†é…的内存é‡ã€‚这就产生了这样一个事实:您通常会“分é…â€å‘下èˆå…¥åˆ°ä¸‹ä¸€ä¸ª4或8个字节的内存。但这ä¸æ˜¯ä¸€ç§å®šä¹‰çš„行为。

如果你多使用几个字节,你就会éžå¸¸å–œæ¬¢è®¿é—®å†²çªã€‚

答案 9 :(得分:1)

è¦å›žç­”您的第二个问题,该标准明确è¦æ±‚malloc(0)åˆæ³•ã€‚返回值å–决于实现,å¯ä»¥æ˜¯NULL或常规内存地å€ã€‚在任何一ç§æƒ…况下,您都å¯ä»¥ï¼ˆå¹¶ä¸”应该)在完æˆåŽåˆæ³•åœ°åœ¨è¿”回值上调用free。å³ä½¿éžNULL,您也ä¸å¾—访问该地å€çš„æ•°æ®ã€‚

答案 10 :(得分:1)

malloc 分é…您在堆中询问的内存é‡ï¼Œç„¶åŽè¿”回一个指å‘void(void *)的指针,该指针å¯ä»¥è½¬æ¢ä¸ºæ‚¨æƒ³è¦çš„任何内容。

程åºå‘˜çš„责任仅使用已分é…的内存。 在ä¸åº”该的地方写入(甚至在å—ä¿æŠ¤çš„环境中读å–)å¯èƒ½ä¼šåœ¨æ‰§è¡Œæ—¶é—´å¯¼è‡´å„ç§éšæœºé—®é¢˜ã€‚如果您幸è¿æ‚¨çš„程åºä¼šç«‹å³å´©æºƒå¹¶å‡ºçŽ°å¼‚常,您å¯ä»¥è½»æ¾æ‰¾åˆ°è¯¥é”™è¯¯å¹¶è¿›è¡Œä¿®å¤ã€‚如果你ä¸å¹¸è¿ï¼Œå®ƒå°†éšæœºå´©æºƒæˆ–产生æ„外行为。

对于墨è²å®šå¾‹ï¼Œâ€œä»»ä½•å¯èƒ½å‡ºé”™çš„东西,都会出错â€å¹¶ä½œä¸ºå…¶ä¸­çš„必然结果,“它会出错正确的时间,产生最大é‡çš„伤害“。 é—憾的是,这是真的。防止这ç§æƒ…况å‘生的唯一方法是é¿å…使用那ç§èƒ½å¤Ÿå®žé™…执行此类æ“作的语言。

现代语言ä¸å…许程åºå‘˜åœ¨å†…存中写入他/她ä¸åº”该写的内容(至少åšæ ‡å‡†ç¼–程)。这就是Java如何获得它的动力。我更喜欢 C ++ 到C。您ä»ç„¶å¯ä»¥ä½¿ç”¨æŒ‡é’ˆè¿›è¡Œä¿®å¤ï¼Œä½†ä¸å¤ªå¯èƒ½ã€‚这就是 Smart Pointers 如此å—欢迎的原因。

为了解决这些问题,malloc库的调试版å¯ä»¥å¾ˆæ–¹ä¾¿ã€‚您需è¦å®šæœŸè°ƒç”¨æ£€æŸ¥åŠŸèƒ½ä»¥æ£€æµ‹å†…存是å¦å·²æŸå。 当我以å‰åœ¨å·¥ä½œä¸­å¯†é›†ä½¿ç”¨C / C ++时,我们使用 Rational Purify ,在实践中替æ¢æ ‡å‡†çš„malloc(C ++中的新内容)和free(在C ++中删除)并且它能够返回准确报告程åºåœ¨å“ªé‡Œåšäº†ä¸€äº›ä¸åº”该åšçš„事情。但是,您永远ä¸ä¼šç¡®å®š100%您的代ç ä¸­æ²¡æœ‰ä»»ä½•é”™è¯¯ã€‚如果您的情况æžå°‘å‘生,那么当您执行该程åºæ—¶ï¼Œæ‚¨å¯èƒ½ä¸ä¼šé‡åˆ°è¿™ç§æƒ…况。它最终会在最ç¹å¿™çš„一天生æˆæœ€æ•æ„Ÿçš„æ•°æ®ï¼ˆæ ¹æ®å¢¨è²å®šå¾‹; - )

答案 11 :(得分:0)

如果传递的大å°ä¸ºé›¶ï¼Œå¹¶ä¸”pträ¸ä¸ºNULL,则调用等效于å…费。

答案 12 :(得分:0)

我的回答是回å¤Why does printf not seg fault or produce garbage?

æ¥è‡ª

  

Denis Ritchie撰写的C编程语言& Kernighan的

 typedef long Align;    /* for alignment to long boundary */
   union header {         /* block header */
       struct {
           union header *ptr; /* next block if on free list */
           unsigned size;     /* size of this block */
       } s;
       Align x;           /* force alignment of blocks */
   };
   typedef union header Header;

永远ä¸ä¼šä½¿ç”¨Align字段; 它åªä¼šå¼ºåˆ¶æ¯ä¸ªæ ‡é¢˜åœ¨æœ€å情况边界上对é½ã€‚ 在malloc中,请求的字符大å°å‘上èˆå…¥ä¸ºæ­£ç¡®æ•°é‡çš„标题大å°çš„å•ä½;è¦åˆ†é…çš„å—åŒ…å« å¦ä¸€ä¸ªå•ä½ï¼Œå¯¹äºŽheader本身,这是记录在中的值 标题的size字段。 malloc返回的指针指å‘å¯ç”¨ç©ºé—´ï¼Œè€Œä¸æ˜¯æ ‡é¢˜æœ¬èº«ã€‚

  

用户å¯ä»¥å¯¹è¯·æ±‚的空间执行任何æ“作,但如果在分é…的空间之外写入任何内容,则列表å¯èƒ½ä¼šè¢«åŠ æ‰°ã€‚

   -----------------------------------------
   |        |     SIZE     |               |
   -----------------------------------------
     |        |
  points to   |-----address returned touser
   next free
   block
        -> a block returned by malloc 

声明

char* test = malloc(1);
如果请求的字节å¯ç”¨ï¼Œ

malloc()将å°è¯•ä»ŽRAM的堆部分æœç´¢è¿žç»­çš„字节,并返回address,如下所示

 --------------------------------------------------------------
| free memory  | memory in size allocated for user |           |
----------------------------------------------------------------
                                                              0x100(assume address returned by malloc)
                                                              test

因此,当malloc(1)执行时,它ä¸ä¼šä»…分é…1个字节,它会分é…一些extra个字节æ¥ç»´æŠ¤ä¸Šé¢çš„结构/堆表。您å¯ä»¥é€šè¿‡æ‰“å°1找出仅请求test[-1]字节时分é…的实际内存é‡ï¼Œå› ä¸ºåªæ˜¯åœ¨è¯¥å—包å«å¤§å°ä¹‹å‰ã€‚

char* test = malloc(1);
printf("memory allocated in bytes = %d\n",test[-1]);

答案 13 :(得分:0)

strcpy()ä¸æ£€æŸ¥å®ƒå†™å…¥çš„内存是å¦å·²åˆ†é…。它åªèŽ·å–目标地å€å¹¶æŒ‰å­—符写入æºå­—符,直到达到'\ 0'。因此,如果分é…的目标内存å°äºŽæºï¼Œåˆ™åªéœ€å†™å…¥å†…存。这是一个å±é™©çš„错误,因为它很难追踪。

puts()写入字符串,直到达到'\ 0'。

我的猜测是malloc(0)åªè¿”回NULL并且ä¸ä¼šå¯¼è‡´è¿è¡Œæ—¶é”™è¯¯ã€‚

答案 14 :(得分:0)

没有“Cè¿è¡Œæ—¶â€ã€‚ C是美化汇编程åºã€‚它会很ä¹æ„让你走é地å€ç©ºé—´å¹¶éšå¿ƒæ‰€æ¬²åœ°åšä»»ä½•äº‹æƒ…,这就是为什么它是编写OS内核的首选语言。您的程åºæ˜¯å †æŸå错误的示例,这是一个常è§çš„安全æ¼æ´žã€‚如果你写了一个足够长的字符串到那个地å€ï¼Œä½ æœ€ç»ˆä¼šè¶…出堆的末尾并得到一个分段错误,但是在你首先覆盖很多其他é‡è¦äº‹æƒ…之å‰ä¸ä¼šè¿™æ ·ã€‚

当malloc()在其ä¿ç•™æ± ä¸­æ²¡æœ‰è¶³å¤Ÿçš„å¯ç”¨å†…å­˜æ¥æ»¡è¶³åˆ†é…时,它会以至少4 kbçš„å—çš„å½¢å¼ä»Žå†…核中抓å–页é¢ï¼Œå¹¶ä¸”通常è¦å¤§å¾—多,所以你å¯èƒ½ä¼šå†™å…¥ä¿ç•™ä½†æ˜¯å½“你最åˆè¶…出你的分é…范围时,un-malloc()ed空间,这就是你的测试用例总是有效的原因。实际上,尊é‡åˆ†é…地å€å’Œå¤§å°æ˜¯å®Œå…¨è‡ªæ„¿çš„,因此您å¯ä»¥ä¸ºæŒ‡é’ˆåˆ†é…一个éšæœºåœ°å€ï¼Œè€Œæ ¹æœ¬ä¸è°ƒç”¨malloc(),并开始将其作为字符串使用,并且åªè¦è¯¥éšæœºåœ°å€æ°å¥½ä½äºŽä¸€ä¸ªåƒå †æˆ–堆栈这样的å¯å†™å†…存段,一切似乎都会起作用,至少在你试图通过这ç§æ–¹å¼ä½¿ç”¨ä½ æ­£åœ¨è…败的内存之å‰ã€‚

答案 15 :(得分:0)

你应该在c ++中使用newå’Œdeleteè¿ç®—符...并且一个安全的指针æ¥æŽ§åˆ¶é‚£äº›æ“作没有达到分é…的数组的é™åˆ¶......

答案 16 :(得分:0)

å¯èƒ½æ˜¯ä½ å¤„于调试模å¼ï¼Œå¯¹malloc的调用实际上会调用_malloc_dbg。调试版本将分é…比您è¦æ±‚的更多空间æ¥å¤„ç†ç¼“冲区溢出。我想如果你在å‘布模å¼ä¸‹è¿è¡Œå®ƒï¼Œä½ å¯èƒ½ï¼ˆå¸Œæœ›ï¼‰ä¼šå‘生崩溃。