realloc()浪费了很多空间,我做错了什么?

时间:2014-05-21 19:37:41

标签: c memory heap realloc

所以,我正在做这个练习:

  

写一个C函数void occurrence(char * s,char c,char *** occp,   int * n)给定一个字符串s和一个char c,计算其数量   在字符串s中出现char c,在n中返回该数字,并在中返回新的char 数组的地址,其中包含每个c的地址   发生在s

     

主要样本:

#include <stdio.h>

int main(){
    int i, n;
    char** occ;
    occorrenze("engineering", 'n', &occ, &n);
    for (i=0; i<n; ++i) printf("%s\n", occ[i]); // prints ngineering neering ng
    free(occ);
}

最初我用这种方式写了这个函数:

void occurrences(char* s1, char c, char*** s, int* n){
    *n=0;
     char* arr[2];
     int length=strlen(s1);
     int i;
     for(i=0; i<length; i++){
        if(s1[i]==c)(*n)++;
     }
     *s=(malloc((*n)*sizeof(char**)));
     int a=0;
     for(i=0; i<length; i++){
        if(s1[i]==c){
           (*s)[a]= &s1[i];
           a++;
        }
     }
}

工作得很好,但我想尝试重新编写一次迭代字符串。我想过使用realloc(),这是我以前从未使用过的函数,最终我想出了这个:

void occurrences(char* s1, char c, char*** s, int* n){
    *n=0;
    *s=malloc(0);
     char* arr[2];
     int length=strlen(s1);
     int i,a=0;
     for(i=0; i<length; i++){
        if(s1[i]==c){
            (*n)++;
            *s=realloc(*s,(*n)*sizeof(char**));
            (*s)[a]= &s1[i];
            a++;

        }
     }
}

这个似乎运作良好,但后来我运行Valgrind:

==4893== HEAP SUMMARY:
==4893==     in use at exit: 0 bytes in 0 blocks
==4893==   total heap usage: 4 allocs, 4 frees, 48 bytes allocated
==4893== 
==4893== All heap blocks were freed -- no leaks are possible
==4893== 
==4893== For counts of detected and suppressed errors, rerun with: -v
==4893== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

分配了48个字节?它应该是24个字节,对吧? 总堆大小为8 * n!而不是8 * n ......我想我错过了一些XD

编辑:复制了正确的函数lol

3 个答案:

答案 0 :(得分:4)

在整个应用程序的执行过程中,valgrind不会测量总分配的内存吗?

0 + 8 + 16 + 24 = 48。

答案 1 :(得分:0)

HEAP USAGE:

如果你malloc(1),系统会为你分配一块能够容纳一个字节的内存。你可能没有意识到,系统通常永远不会分配一个字节。实际上,分配的内存块很可能要大得多;也许至少8,16或32字节。因此,malloc() ed空格不等于heap space - 使用。

由于上述“最小”系统内存分配,函数realloc()可能返回与给定的相同的地址;如果该地址的系统分配足够大,以适应(在您的情况下)更大的大小。一旦系统分配变得太小,realloc()将向更大的系统内存块返回一个新地址(并且很可能比realloc请求的更大)。


一些评论:

void occurrences(char* s1, char c, char*** s, int* n){
   *n=0;
   *s=NULL;   

更改了以上内容。无需malloc(0);sNULL)的值将传递到realloc(),然后就像malloc()一样,

    char* arr[2];
    int length=strlen(s1);
    int i,a=0;
    for(i=0; i<length; i++){
    if(s1[i]==c){
        (*n)++;
        *s=realloc(*s,(*n) * sizeof(char**));  // !DANGER!

请考虑以下替代方案,而不是上述内容:

    if(s1[i]==c){
        char *tmp;
        (*n)++;
        tmp=realloc(*s,(*n) * sizeof(char**));  // Much better.
        if(NULL == tmp)
           {
           /* Handle realloc() failure. */
           ...
           }
        else
           *s = tmp;  

        ...

如果您不按上面所示进行操作,如果realloc()失败,则先前分配的内存(由s指向)将丢失;由NULL替换。

        (*s)[a]= &s1[i];
        a++;

    }
 }

}

答案 2 :(得分:0)

如果您不使用 *n 和 *occp 作为变量,而是使用局部变量并将它们存储在函数的最后,您可以省去大麻烦。使事情更清晰,并减少出现错误的机会。