如何使用 malloc 和 free 进行动态内存分配

Posted

技术标签:

【中文标题】如何使用 malloc 和 free 进行动态内存分配【英文标题】:How to use malloc and free for Dynamic Memory Allocation 【发布时间】:2017-02-08 12:42:48 【问题描述】:

我刚开始学习 C,来自 php。我还不明白如何使用 malloc 和 free。

1) 在下面的示例代码中,我可以在哪里放置“免费”?

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

int strLen(char* text) 
  int c = 0;
  for (int i = 0; text[i] != '\0'; ++i) ++c;
  return c;



char* reverse(char* text) 

  int count = strLen(text);
  char* t = malloc(count);

  for (int i = count; i > 0; --i)  t[count - i] = text[i-1]; 
  t[count] = '\0'; /* Add end of string */

  return t;




int main (int argc, char** argv) 

  if (argc > 1) 
    for (int i = 1; i < argc; ++i)  
      printf("%d\t%s\t%s\n", i, argv[i], reverse(argv[i])); 
    
  

  return 0;

2) 这是 valgrind 的输出。错误“Invalid write of size 1”和“Invalid read of size 1”是什么意思?

valgrind ./reverse Text ONe
==3124== Memcheck, a memory error detector
==3124== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3124== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==3124== Command: ./reverse Text ONe
==3124==
==3124== Invalid write of size 1
==3124==    at 0x40060F: reverse (in /localServer/temp/C/reverse)
==3124==    by 0x400654: main (in /localServer/temp/C/reverse)
==3124==  Address 0x5203044 is 0 bytes after a block of size 4 alloc'd
==3124==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3124==    by 0x4005C6: reverse (in /localServer/temp/C/reverse)
==3124==    by 0x400654: main (in /localServer/temp/C/reverse)
==3124==
==3124== Invalid read of size 1
==3124==    at 0x4E88CC0: vfprintf (vfprintf.c:1632)
==3124==    by 0x4E8F898: printf (printf.c:33)
==3124==    by 0x400682: main (in /localServer/temp/C/reverse)
==3124==  Address 0x5203044 is 0 bytes after a block of size 4 alloc'd
==3124==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3124==    by 0x4005C6: reverse (in /localServer/temp/C/reverse)
==3124==    by 0x400654: main (in /localServer/temp/C/reverse)
==3124==
1 Text  txeT
2 ONe eNO
==3124==
==3124== HEAP SUMMARY:
==3124==     in use at exit: 7 bytes in 2 blocks
==3124==   total heap usage: 3 allocs, 1 frees, 1,031 bytes allocated
==3124==
==3124== LEAK SUMMARY:
==3124==    definitely lost: 7 bytes in 2 blocks
==3124==    indirectly lost: 0 bytes in 0 blocks
==3124==      possibly lost: 0 bytes in 0 blocks
==3124==    still reachable: 0 bytes in 0 blocks
==3124==         suppressed: 0 bytes in 0 blocks
==3124== Rerun with --leak-check=full to see details of leaked memory
==3124==
==3124== For counts of detected and suppressed errors, rerun with: -v
==3124== ERROR SUMMARY: 4 errors from 2 contexts (suppressed: 0 from 0)

谢谢。

【问题讨论】:

【参考方案1】:

在你使用reverse返回的指针之后,你应该把free放在循环中,如下。

int main (int argc, char** argv) 
    char *reverseStrPtr;

    if (argc > 1) 
        for (int i = 1; i < argc; ++i) 
            reverseStrPtr = reverse(argv[i]);
            printf("%d\t%s\t%s\n", i, argv[i], reverseStrPtr); 
            free(reverseStrPtr);
        
    

    return 0;

此外,valgrind 错误基于reverse 中的以下行。

t[count] = '\0'; /* Add end of string */

简单地说,当你分配 count-many 字节时,你的索引范围是[0, count)。所以尝试访问count相当于访问(count+1)th位,这是访问冲突。

您需要更正的是您分配的内存量,即(count+1) 字节。需要额外的字节来放置终止 '\0' 字符。

char* reverse(char* text) 
    int count = strLen(text);
    char* t = malloc(count+1); // +1 for the terminating '\0'

    for (int i = count; i > 0; --i)  t[count - i] = text[i-1];
    t[count] = '\0'; /* Add end of string */

    return t;

【讨论】:

【参考方案2】:

您需要保留从reverse(argv[i])free 返回的指针。

一种方法是将main稍微调整为

int main (int argc, char** argv) 
    char* s;

    // if (argc > 1)  Comment out the redundant check
        for (int i = 1; i < argc; ++i)  
            printf("%d\t%s\t%s\n", i, argv[i], s = reverse(argv[i]));
            free(s); 
        
    //
    return 0;

表达式深处的赋值并不符合每个人的口味(因为它们可能会混淆),但它们在这样的情况下工作得很好。我是你应该习惯在 C 中这样的事情的同类。

另外,t[count] = '\0'; 超出了您的缓冲区 - 其行为是未定义。你需要malloc(1 + count);

【讨论】:

以上是关于如何使用 malloc 和 free 进行动态内存分配的主要内容,如果未能解决你的问题,请参考以下文章

动态内存函数+经典笔试题@动态内存管理---malloc +free + calloc + realloc

11动态分配内存malloc/free

c语言中啥是动态分配内存?

malloc 和 free 是如何实现的?

梦开始的地方—— C语言动态内存管理(malloc+calloc+realloc+free)

C++内存管理第一篇:(malloc/deldete和malloc/free)