重新分配,堆内存泄漏

时间:2019-01-05 22:29:29

标签: c memory-management valgrind

这是我的看法,并从leetcode解决方案说出问题。但是随着内存泄漏https://leetcode.com/problems/count-and-say/

我的makefile文件

df1['to_move'] = ((df1['A']==False) & (df1['B']>0))
indexes_to_move = list(df1[df1['to_move']].index)
for ind in indexes_to_move:
    temp = df1.loc[ind:,'B']
    to_change = temp[temp==0].index.min()
    df1.loc[ind, 'A'] = True
    df1.loc[to_change, 'A'] = False
del df1['to_move']

我的构建命令

build:
    gcc main.c -Wall -g -o main; \
    $(PWD)/main; \

或使用valgrind:

make

输出:(正确,经过测试)

make
valgrind --leak-check=yes ./main

来自Valgrind

count and say 30 = 3113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112212211131221121321131211132221123113112221131112311332211211133112111311222112111312211311123113322112111312211312111322212321121113121112133221121321132132211331121321132213211231132132211211131221232112111312212221121123222112311311222113111231133211121321321122111312211312111322211213211321322123211211131211121332211231131122211311123113321112131221123113111231121123222112111331121113112221121113122113111231133221121113122113121113221112131221123113111231121123222112111312211312111322212321121113121112131112132112311321322112111312212321121113122122211211232221121321132132211331121321231231121113112221121321132132211322132113213221123113112221133112132123222112111312211312112213211231132132211211131221131211322113321132211221121332211231131122211311123113321112131221123113111231121113311211131221121321131211132221123113112211121312211231131122211211133112111311222112111312211312111322211213211321223112111311222112132113213221133122211311221122111312211312111322212321121113121112131112132112311321322112111312212321121113122122211211232221121321132132211331121321231231121113112221121321132132211322132113213221123113112221133112132123222112111312211312112213211231132132211211131221131211322113321132211221121332211213211321322113311213212312311211131122211213211331121321123123211231131122211211131221131112311332211213211321223112111311222112132113213221123123211231132132211231131122211311123113322112111312211312111322111213122112311311123112112322211213211321322113312211223113112221121113122113111231133221121321132132211331222113321112131122211332113221122112133221123113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112311332111213122112311311123112112322211322311311222113111231133211121312211231131112311211232221121113122113121113222123211211131221132211131221121321131211132221123113112211121312211231131122113221122112133221121321132132211331121321231231121113121113122122311311222113111231133221121113122113121113221112131221123113111231121123222112132113213221133112132123123112111312211322311211133112111312211213211311123113223112111321322123122113222122211211232221121113122113121113222123211211131211121311121321123113213221121113122123211211131221121311121312211213211321322112311311222113311213212322211211131221131211221321123113213221121113122113121113222112131112131221121321131211132221121321132132211331121321232221123113112221131112311322311211131122211213211331121321122112133221121113122113121113222123112221221321132132211231131122211331121321232221121113122113121113222123211211131211121332211213111213122112132113121113222112132113213221232112111312111213322112132113213221133112132123123112111311222112132113311213211221121332211231131122211311123113321112131221123113112221132231131122211211131221131112311332211213211321223112111311222112132113212221132221222112112322211211131221131211132221232112111312111213111213211231131112311311221122132113213221133112132123222112311311222113111231132231121113112221121321133112132112211213322112111312211312111322212321121113121112131112132112311321322112111312212321121113122122211211232221121311121312211213211312111322211213211321322123211211131211121332211213211321322113311213211322132112311321322112111312212321121113122122211211232221121321132132211331121321231231121113112221121321133112132112312321123113112221121113122113111231133221121321132122311211131122211213211321222113222122211211232221123113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112311332111213213211221113122113121113222112132113213221232112111312111213322112132113213221133112132123123112111312211322311211133112111312212221121123222112132113213221133112132123222113223113112221131112311332111213122112311311123112112322211211131221131211132221232112111312111213111213211231132132211211131221131211221321123113213221123113112221131112211322212322211231131122211322111312211312111322211213211321322113311213211331121113122122211211132213211231131122212322211331222113112211

main.c

==1796== Memcheck, a memory error detector
==1796== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et 
al.
==1796== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright 
info
==1796== Command: ./main
==1796== 
==1796== Invalid read of size 1
==1796==    at 0x100000930: countAndSay (main.c:62)
==1796==    by 0x100000ECA: main (main.c:209)
==1796==  Address 0x100df6f80 is 0 bytes inside a block of size 2 
free'd
==1796==    at 0x1000AC2DA: realloc (vg_replace_malloc.c:829)
==1796==    by 0x100000D10: countAndSay (main.c:172)
==1796==    by 0x100000ECA: main (main.c:209)
==1796==  Block was alloc'd at
==1796==    at 0x1000AB2C5: malloc (vg_replace_malloc.c:302)
==1796==    by 0x100000892: countAndSay (main.c:40)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== Invalid read of size 1
==1796==    at 0x10000096B: countAndSay (main.c:73)
==1796==    by 0x100000ECA: main (main.c:209)
==1796==  Address 0x100df6f80 is 0 bytes inside a block of size 2 
free'd
==1796==    at 0x1000AC2DA: realloc (vg_replace_malloc.c:829)
==1796==    by 0x100000D10: countAndSay (main.c:172)
==1796==    by 0x100000ECA: main (main.c:209)
==1796==  Block was alloc'd at
==1796==    at 0x1000AB2C5: malloc (vg_replace_malloc.c:302)
==1796==    by 0x100000892: countAndSay (main.c:40)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== Invalid read of size 1
==1796==    at 0x1000009D7: countAndSay (main.c:89)
==1796==    by 0x100000ECA: main (main.c:209)
==1796==  Address 0x100df6f80 is 0 bytes inside a block of size 2 
free'd
==1796==    at 0x1000AC2DA: realloc (vg_replace_malloc.c:829)
==1796==    by 0x100000D10: countAndSay (main.c:172)
==1796==    by 0x100000ECA: main (main.c:209)
==1796==  Block was alloc'd at
==1796==    at 0x1000AB2C5: malloc (vg_replace_malloc.c:302)
==1796==    by 0x100000892: countAndSay (main.c:40)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== Invalid read of size 16
==1796==    at 0x100655A65: _platform_memchr$VARIANT$Base (in 
/usr/lib/system/libsystem_platform.dylib)
==1796==    by 0x1002E99E9: __sfvwrite (in 
/usr/lib/system/libsystem_c.dylib)
==1796==    by 0x1002F35FE: __vfprintf (in 
/usr/lib/system/libsystem_c.dylib)
==1796==    by 0x100318058: __v2printf (in 
/usr/lib/system/libsystem_c.dylib)
==1796==    by 0x1002EF741: vfprintf_l (in 
/usr/lib/system/libsystem_c.dylib)
==1796==    by 0x1002ED7CA: printf (in 
/usr/lib/system/libsystem_c.dylib)
==1796==    by 0x100000EE0: main (main.c:210)
==1796==  Address 0x10545d410 is 1 bytes after a block of size 4,463 
alloc'd
==1796==    at 0x1000AB2C5: malloc (vg_replace_malloc.c:302)
==1796==    by 0x1000AC30C: realloc (vg_replace_malloc.c:829)
==1796==    by 0x100000C67: countAndSay (main.c:157)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== Conditional jump or move depends on uninitialised value(s)
==1796==    at 0x100655A7D: _platform_memchr$VARIANT$Base (in 
/usr/lib/system/libsystem_platform.dylib)
==1796==    by 0x1002E99E9: __sfvwrite (in 
/usr/lib/system/libsystem_c.dylib)
==1796==    by 0x1002F35FE: __vfprintf (in 
/usr/lib/system/libsystem_c.dylib)
==1796==    by 0x100318058: __v2printf (in 
/usr/lib/system/libsystem_c.dylib)
==1796==    by 0x1002EF741: vfprintf_l (in 
/usr/lib/system/libsystem_c.dylib)
==1796==    by 0x1002ED7CA: printf (in 
/usr/lib/system/libsystem_c.dylib)
==1796==    by 0x100000EE0: main (main.c:210)
==1796== 
count and say 30 = 3113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112212211131221121321131211132221123113112221131112311332211211133112111311222112111312211311123113322112111312211312111322212321121113121112133221121321132132211331121321132213211231132132211211131221232112111312212221121123222112311311222113111231133211121321321122111312211312111322211213211321322123211211131211121332211231131122211311123113321112131221123113111231121123222112111331121113112221121113122113111231133221121113122113121113221112131221123113111231121123222112111312211312111322212321121113121112131112132112311321322112111312212321121113122122211211232221121321132132211331121321231231121113112221121321132132211322132113213221123113112221133112132123222112111312211312112213211231132132211211131221131211322113321132211221121332211231131122211311123113321112131221123113111231121113311211131221121321131211132221123113112211121312211231131122211211133112111311222112111312211312111322211213211321223112111311222112132113213221133122211311221122111312211312111322212321121113121112131112132112311321322112111312212321121113122122211211232221121321132132211331121321231231121113112221121321132132211322132113213221123113112221133112132123222112111312211312112213211231132132211211131221131211322113321132211221121332211213211321322113311213212312311211131122211213211331121321123123211231131122211211131221131112311332211213211321223112111311222112132113213221123123211231132132211231131122211311123113322112111312211312111322111213122112311311123112112322211213211321322113312211223113112221121113122113111231133221121321132132211331222113321112131122211332113221122112133221123113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112311332111213122112311311123112112322211322311311222113111231133211121312211231131112311211232221121113122113121113222123211211131221132211131221121321131211132221123113112211121312211231131122113221122112133221121321132132211331121321231231121113121113122122311311222113111231133221121113122113121113221112131221123113111231121123222112132113213221133112132123123112111312211322311211133112111312211213211311123113223112111321322123122113222122211211232221121113122113121113222123211211131211121311121321123113213221121113122123211211131221121311121312211213211321322112311311222113311213212322211211131221131211221321123113213221121113122113121113222112131112131221121321131211132221121321132132211331121321232221123113112221131112311322311211131122211213211331121321122112133221121113122113121113222123112221221321132132211231131122211331121321232221121113122113121113222123211211131211121332211213111213122112132113121113222112132113213221232112111312111213322112132113213221133112132123123112111311222112132113311213211221121332211231131122211311123113321112131221123113112221132231131122211211131221131112311332211213211321223112111311222112132113212221132221222112112322211211131221131211132221232112111312111213111213211231131112311311221122132113213221133112132123222112311311222113111231132231121113112221121321133112132112211213322112111312211312111322212321121113121112131112132112311321322112111312212321121113122122211211232221121311121312211213211312111322211213211321322123211211131211121332211213211321322113311213211322132112311321322112111312212321121113122122211211232221121321132132211331121321231231121113112221121321133112132112312321123113112221121113122113111231133221121321132122311211131122211213211321222113222122211211232221123113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112311332111213213211221113122113121113222112132113213221232112111312111213322112132113213221133112132123123112111312211322311211133112111312212221121123222112132113213221133112132123222113223113112221131112311332111213122112311311123112112322211211131221131211132221232112111312111213111213211231132132211211131221131211221321123113213221123113112221131112211322212322211231131122211322111312211312111322211213211321322113311213211331121113122122211211132213211231131122212322211331222113112211
==1796== 
==1796== HEAP SUMMARY:
==1796==     in use at exit: 29,301,895 bytes in 40,712 blocks
==1796==   total heap usage: 80,412 allocs, 39,700 frees, 58,326,719 
bytes allocated
==1796== 
==1796== 72 bytes in 3 blocks are possibly lost in loss record 25 of 51
==1796==    at 0x1000ABD72: calloc (vg_replace_malloc.c:755)
==1796==    by 0x10075A7C2: map_images_nolock (in 
/usr/lib/libobjc.A.dylib)
==1796==    by 0x10076D4E0: map_images (in /usr/lib/libobjc.A.dylib)
==1796==    by 0x100007C64: dyld::notifyBatchPartial(dyld_image_states, 
bool, char const* (*)(dyld_image_states, unsigned int, dyld_image_info 
const*), bool, bool) (in /usr/lib/dyld)
==1796==    by 0x100007E39: dyld::registerObjCNotifiers(void (*) 
(unsigned int, char const* const*, mach_header const* const*), void (*) 
(char const*, mach_header const*), void (*)(char const*, mach_header 
const*)) (in /usr/lib/dyld)
==1796==    by 0x10022571D: _dyld_objc_notify_register (in / 
/usr/lib/system/libdyld.dylib)
==1796==    by 0x10075A073: _objc_init (in /usr/lib/libobjc.A.dylib)
==1796==    by 0x1001AFB34: _os_object_init (in 
/usr/lib/system/libdispatch.dylib)
==1796==    by 0x1001AFB1B: libdispatch_init (in 
/usr/lib/system/libdispatch.dylib)
==1796==    by 0x1000BE9C2: libSystem_initializer (in 
/usr/lib/libSystem.B.dylib)
==1796==    by 0x100019AC5: 
ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) 
(in /usr/lib/dyld)
==1796==    by 0x100019CF5: 
ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (in 
/usr/lib/dyld)
==1796== 
==1796== 168 bytes in 56 blocks are definitely lost in loss record 28 
of 51
==1796==    at 0x1000AB2C5: malloc (vg_replace_malloc.c:302)
==1796==    by 0x1000AC30C: realloc (vg_replace_malloc.c:829)
==1796==    by 0x100000D10: countAndSay (main.c:172)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== 570 bytes in 1 blocks are possibly lost in loss record 37 of 
51
==1796==    at 0x1000AC2DA: realloc (vg_replace_malloc.c:829)
==1796==    by 0x100000DCD: countAndSay (main.c:184)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== 1,512 bytes in 378 blocks are definitely lost in loss record 
38 of 51
==1796==    at 0x1000AB2C5: malloc (vg_replace_malloc.c:302)
==1796==    by 0x1000AC30C: realloc (vg_replace_malloc.c:829)
==1796==    by 0x100000DCD: countAndSay (main.c:184)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== 4,462 bytes in 1 blocks are definitely lost in loss record 45 
of 51
==1796==    at 0x1000AB2C5: malloc (vg_replace_malloc.c:302)
==1796==    by 0x100000867: countAndSay (main.c:29)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== 17,848 bytes in 1 blocks are definitely lost in loss record 46 
of 51
==1796==    at 0x1000AB2C5: malloc (vg_replace_malloc.c:302)
==1796==    by 0x100000857: countAndSay (main.c:28)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== 19,257 (240 direct, 19,017 indirect) bytes in 1 blocks are d 
definitely lost in loss record 48 of 51
==1796==    at 0x1000AB2C5: malloc (vg_replace_malloc.c:302)
==1796==    by 0x100000839: countAndSay (main.c:19)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== 61,644 bytes in 406 blocks are definitely lost in loss record 
49 of 51
==1796==    at 0x1000AB2C5: malloc (vg_replace_malloc.c:302)
==1796==    by 0x1000AC30C: realloc (vg_replace_malloc.c:829)
==1796==    by 0x100000C67: countAndSay (main.c:157)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== 80,493 bytes in 379 blocks are definitely lost in loss record 
50 of 51
==1796==    at 0x1000AC2DA: realloc (vg_replace_malloc.c:829)
==1796==    by 0x100000D10: countAndSay (main.c:172)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== 29,093,648 bytes in 39,299 blocks are definitely lost in loss 
record 51 of 51
==1796==    at 0x1000AC2DA: realloc (vg_replace_malloc.c:829)
==1796==    by 0x100000DCD: countAndSay (main.c:184)
==1796==    by 0x100000ECA: main (main.c:209)
==1796== 
==1796== LEAK SUMMARY:
==1796==    definitely lost: 29,260,015 bytes in 40,521 blocks
==1796==    indirectly lost: 19,017 bytes in 29 blocks
==1796==      possibly lost: 642 bytes in 4 blocks
==1796==    still reachable: 200 bytes in 6 blocks
==1796==         suppressed: 22,021 bytes in 152 blocks
==1796== Reachable blocks (those to which a pointer was found) are not 
shown.
==1796== To see them, rerun with: --leak-check=full --show-leak- 
kinds=all
==1796== 
==1796== For counts of detected and suppressed errors, rerun with: -v
==1796== Use --track-origins=yes to see where uninitialised values come 
from
==1796== ERROR SUMMARY: 124 errors from 15 contexts (suppressed: 11 
from 11)

我知道这不是最好的算法,但是它可以工作。据我了解,可以使用realloc来避免 这样就可以将malloc的内存堆积到循环的内存中,就像这样。我的怀疑是,这样做会将内存移动到不容易找到和释放的位置。我是否沿着正确的思路走上正确的道路?简单的重新分配

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

#define MAX_SEQUENCE_COUNT 30
#define BUFFER_MAX 4462

char* countAndSay(int n) {

    int msc;
    if (n > 0 && n <= 30) {
         msc = MAX_SEQUENCE_COUNT;
    } else {
         fprintf(stderr, "Error: The range for this count and say method is 1...30\n");
         exit(1);
    }

    //Holds the array of sequences
    char **out_buffer = malloc(msc * sizeof(char*));
    //Holds current sequence
    char *out;
    int size = n;

    //Holds previous sequence
    char *prev_chunk = NULL;

    //memory for the counts and says
    int *counts = malloc(BUFFER_MAX*sizeof(int));
    char *says = malloc(BUFFER_MAX*sizeof(char));

    //index into the buffer memory of sequences
    int index = 0;

    //solve iteratively
    while (size > 0) {
        //base condition
        //size counts down to 0, filling chunks, populating the next chunk to be processed
        //filled chunks are placed in the out buffer at the index which is counting 
        if (index == 0) {
            out = malloc(2 * sizeof(char));
            out[0] = '1';
            out[1] = '\0';
            prev_chunk = out;
            size -= 1;
            index += 1;
            out_buffer[0] = out;
            continue;
       }

       //from 0 to index - 1 get the chunk to be processed, use it to put together 
    //the count and say chunk for adding to the index slot
        for (int s = 0; s < index; s++) {           
            if (s == 0) {
                prev_chunk = out_buffer[0];
            } else {
                prev_chunk = out_buffer[index];
            }

            //count the length of the current chunk
            int length = 0;
            for (int e = 0; e <= BUFFER_MAX; e++) {
                if (prev_chunk[e]) {
                   length += 1;
                } else {
                   break;
                }
            }

            //The count of says at each iteration
            int count = 0;

            //say is a char byte from the previous chunk memory
            char say = prev_chunk[0];
            //skip is used in the iteration process 
            int skip = 0;

            //The idx into memory for the counts and says
            int idx = 0;

            //iteratively generate the count and say chunk for this index
            for (int i = 0; i < length; i++) {
                if (skip > 0) {
                    if (i < length - 1) {
                        say = prev_chunk[i + 1];
                    }
                    skip -= 1;
                    continue;
                }
                if (prev_chunk[i] == say) {
                    count += 1;
                    counts[idx] = count;
                    says[idx] = say;
                    //if at the end of the iteration add one
                    //as a terminator for the counts, says, pairs
                    if (i == length - 1) {
                        idx += 1;
                        break;
                    }
                } else {
                    count = 0;
                    if (i == length - 1) {
                        //finish off
                        idx += 1;
                        count += 1;
                        counts[idx] = count;
                        says[idx] = prev_chunk[i];
                        say = says[idx];
                        idx += 1;
                    } else {
                        idx += 1;
                        count += 1;
                        counts[idx] = count;
                        says[idx] = prev_chunk[i];
                        char next_say = prev_chunk[i + 1];
                        say = prev_chunk[i];
                        //Takes care of itself with idx
                        if (next_say != prev_chunk[i]) {
                            count = 0;
                            continue;
                        } 

                        int y = i;
                        while (next_say == say && y < length -1) {
                            count += 1;
                            //dont need to up the index because we are counting howmany there are
                            says[idx] = say;
                            counts[idx] = count;
                            //skip because this is the next loop 
                            skip += 1;
                            //subtract 1 because we want this to be in the final index slot
                            //count because we added an index
                            y += 1;
                            next_say = prev_chunk[y + 1];
                        }
                        idx += 1;
                        count = 0;
                    }
                }
            }      

            //Could have just generated the sequence from above but felt like doing this manually at the time
            //If I get around to it ill change  
            int chunk_offset = 0;
            char *temp = NULL;
            for (int u = 0; u < idx; u++) {
                 int c = counts[u];
                 //TODO: factor out or use sprintf, or maybe not, maybe this is just faster
                 char cc;
                 if (c >= 10) {
                     cc = 'A' + c - 10;
                 } else {
                     cc = '0' + c;
                 }

                 char say = says[u];
                 if (u == idx - 1) {
                     temp = realloc(temp, chunk_offset + 3);
                     if (chunk_offset > 0) {
                        for (int y = 0; y < chunk_offset; y++) {
                            temp[y] = out[y];
                        }

                        temp[chunk_offset] = cc;
                        temp[chunk_offset + 1] = say;
                        temp[chunk_offset + 2] = '\0';
                    } else {
                        temp[0] = cc;
                        temp[1] = say;
                        temp[2] = '\0';
                    }

                    out = realloc(out, chunk_offset + 3);
                    out = temp;
                    temp = NULL;
                    free(temp);
                } else {
                    temp = realloc(temp, chunk_offset + 2);
                    for (int ii = 0; ii < chunk_offset; ii++) {
                        temp[ii] = out[ii];
                    }
                    temp[chunk_offset] = cc;
                    temp[chunk_offset + 1] = say;
                    chunk_offset += 2;
                    out = realloc(out, chunk_offset + 2);
                    out = temp;
                    temp = NULL;
                    free(temp);
               }
           }        
         out_buffer[index] = out;
         out = NULL;
         free(out);
       }
     index += 1;
     size -= 1;
   }

   free(prev_chunk);
   prev_chunk = NULL;
   free(counts);
   counts = NULL;
   free(says);
   says = NULL;

   return out_buffer[n - 1];
 }

int main(int argc, char **argv) {
    char *cs = countAndSay(30);
    printf("count and say 30 = %s\n", cs);
}

瓦尔格隆德的产量:

char *e = NULL;
for (int i = 0; i < 10; i++) {
    e = realloc(e, i + 1);
    if (i == 9) {
        e[i] = '\0';
    } else {
        e[i] = 'e';
    }
}
printf("%s\n", e);
free(e);

我一直在用valgrind来运行此程序,以试图解决泄漏的问题。我也看到了这样的解决方案,但没有运气尝试过:"Pointer being freed was not allocated." error after malloc, realloc

我相信我在这里遇到的主要问题是我第一次“分配”出内存。之后,我每次在循环中重新分配它。 Valgrind在main.c:184行给出了最大的泄漏:“ out = realloc(out,chunk_offset + 2);”。看起来realloc只是在决定将内存放在堆中的某个位置,而我无法到达它。我知道地址可以从realloc更改,但是我仍然无法实现。在我的判断中,我怎么能肯定输到0。

3 个答案:

答案 0 :(得分:2)

您的问题是,即使您保存了后代指针,也要释放在循环结束时分配的指针。

基于此代码,我想说您想做几件事:

  1. 不要仅仅因为保留了指针上的变量就释放了内存而已。
  2. 将其更改为malloc而不是realloc,因为您显然希望为循环中的每个遍历分配单独的空间。
  3. 获取一个可以帮助您缩进的编辑器,或者学习配置用于帮助您缩进的编辑器。这听起来像是一种意见,但这看起来像我发现的那种问题,如果您的缩进意味着某种意义,则更容易诊断。它也可能会帮助您获得帮助,因为很少有专业的程序员想要处理这样的不一致的缩进。我的印象是,我是看到这样的东西并决定将其弹出到vim中的少数人之一,然后键入=gg重新格式化所有内容。 (注意:如果您不使用vi,nvi或vim,请不要仅仅因为我就使用它-这三个编辑器都有很大的学习曲线,大多数编程编辑器都可以做同样的事情。)

仅是为了强调最后一点:一旦我将其重新格式化为具有一致的缩进形式,问题就跳到我了。汤姆几乎明白了,但我认为他认为那是函数的结尾,而不是循环的结尾。

答案 1 :(得分:2)

让我们从这个块开始吧:

             if (u == idx - 1) {
                 temp = realloc(temp, chunk_offset + 3);
                 if (chunk_offset > 0) {
                    for (int y = 0; y < chunk_offset; y++) {
                        temp[y] = out[y];
                    }

                    temp[chunk_offset] = cc;
                    temp[chunk_offset + 1] = say;
                    temp[chunk_offset + 2] = '\0';
                } else {
                    temp[0] = cc;
                    temp[1] = say;
                    temp[2] = '\0';
                }

                out = realloc(out, chunk_offset + 3);
                //    *** MEMORY LEAK ***
                out = temp;
                temp = NULL;
                //    NOT NEEDED
                free(temp);
            } else {
                temp = realloc(temp, chunk_offset + 2);
                for (int ii = 0; ii < chunk_offset; ii++) {
                    temp[ii] = out[ii];
                }
                temp[chunk_offset] = cc;
                temp[chunk_offset + 1] = say;
                chunk_offset += 2;
                out = realloc(out, chunk_offset + 2);
                //    *** MEMORY LEAK ***
                out = temp;
                temp = NULL;
                //    NOT NEEDED
                free(temp);
           }

if的两个部分中,您都扩大了out的大小,但是随后立即用out的值覆盖了temp,从而泄漏了{ {1}}指向。

由于out包含您想要的值,因此您不再需要temp中的内容,因此,请摆脱out上的realloc,而改为out以前在那里。另外,也不需要free,因为它指向NULL,并且您可以将free(temp)替换为realloc,因为malloc在该时刻始终为NULL:

temp

然后将其放在 if (u == idx - 1) { temp = malloc(chunk_offset + 3); if (chunk_offset > 0) { for (int y = 0; y < chunk_offset; y++) { temp[y] = out[y]; } temp[chunk_offset] = cc; temp[chunk_offset + 1] = say; temp[chunk_offset + 2] = '\0'; } else { temp[0] = cc; temp[1] = say; temp[2] = '\0'; } } else { temp = malloc(chunk_offset + 2); for (int ii = 0; ii < chunk_offset; ii++) { temp[ii] = out[ii]; } temp[chunk_offset] = cc; temp[chunk_offset + 1] = say; chunk_offset += 2; } free(out); out = temp; 循环的底部:

for

您每次泄漏内存都会覆盖for (int s = 0; s < index; s++) { ... out_buffer[index] = out; out = NULL; free(out); } 的内容。您首先需要out_buffer[index]的旧内容,最后也要删除不需要的free,因为此时它包含NULL。这也意味着您需要在进入循环之前将free(out)初始化为NULL。

out_buffer[index]

然后您在这里遇到问题:

out_buffer[index] = NULL;
for (int s = 0; s < index; s++) {
     ...
     free(out_buffer[index]);
     out_buffer[index] = out;
     out = NULL;
}

在循环的下一次迭代之前无法将 if (index == 0) { out = malloc(2 * sizeof(char)); out[0] = '1'; out[1] = '\0'; prev_chunk = out; size -= 1; index += 1; out_buffer[0] = out; continue; } 设置为NULL,这将导致out得到释放并随后从释放的内存中读取。所以在这里添加:

out_buffer[0]

然后在末尾:

    if (index == 0) {
        out = malloc(2 * sizeof(char));
        out[0] = '1';
        out[1] = '\0';
        prev_chunk = out;
        size -= 1;
        index += 1;
        out_buffer[0] = out;
        out = NULL;
        continue;
   }

您不希望free(prev_chunk); prev_chunk = NULL; free(counts); counts = NULL; free(says); says = NULL; return out_buffer[n - 1]; 指向已经释放的free(prev_chunk);的旧副本。您也不会释放out或它指向的任何字符串。当然,您不想释放返回的字符串,因此请跳过该字符串:

out_buffer

最后,一旦完成char *rval = out_buffer[n - 1]; for (int i = 0; i < n - 1; i++) { free(out_buffer[i]); } free(out_buffer); free(counts); free(says); return rval; ,请确保您free完成此函数的结果:

main

现在,您可以通过valgrind进行干净运行了,没有内存泄漏或无效的读/写/释放错误。

另一方面,此代码有很多低效率的地方。在外部char *cs = countAndSay(30); printf("count and say 30 = %s\n", cs); free(cs); 循环的每次迭代中,您将生成从1到while的当前值的整个列表。因此,在第一次迭代中,您计算​​n = 1,然后在下一次迭代中,计算n = 1,2,然后在下一次迭代中,计算n = 1,2,3,依此类推。

这里您只需要一个循环。这也意味着您不必重复使用n的当前值,而只需引用先前的值即可。我会将这些更改留给读者练习。

答案 2 :(得分:1)

如果我们看一下看和说算法的工作原理,则会发现每个字符(或相同字符的序列)在输出中产生一个字符对。因此,如果输入的长度是 N 个字符,则输出的长度最多是2 N 个字符。

让我们看一下一个函数,该函数会按照“先说后说”顺序生成 next 字符串:

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

char *look_and_say(const char *src)
{
    const size_t  srclen = (src) ? strlen(src) : 0;
    char         *dst;

    if (srclen < 1) {
        /* Nothing to look or say. */
        return NULL;
    }

    /* The result can be up to twice as long as the source,
       plus the string-terminating nul char. */
    dst = malloc(2*srclen + 1);
    if (!dst) {
        /* Not enough memory for the result. */
        return NULL;
    }

    {
        const char *const  end = src + srclen;
        char              *pos = dst;

        while (src < end) {
            const char *const was = src;

            /* Skip repeated source characters. */
            do {
                src++;
            } while (src < end && *src == *was);

            /* The longest allowed sequence is 9. */
            if ((size_t)(src - was) > 9) {
                free(dst);
                return NULL;
            }

            *(pos++) = '0' + (size_t)(src - was);
            *(pos++) = *was;
        }

        *pos = '\0';

        return dst;
    }
}

以上内容并不关心输入字符串是什么;您可以提供任何东西。如果输入字符串为NULL或为空,则将返回NULL。如果它不能分配内存(输入字符串的长度的两倍,再加上一个以字符结尾的nul '\0'字符的字符),则它将返回NULL。如果一个字符连续重复超过9次,该函数将返回NULL。

“看-说”序列为整数序列在线百科全书中的OEIS A005150,指出RG Wilson v在2004年展示的数字仅为123存在于序列中。因此,对于整数序列,可以对数字是否重复(两次或三次)进行开放编码测试。

该序列中每个术语的长度形成另一个整数序列OEIS A005341。事实证明, i 项的长度大约为1.56×1.304 i (即(size_t)(1.0 + 1.56*exp(0.26544*i))。序列中的第30个词长为4462个字符。

如果我们要生成序列中的每个值,可以使用一个动态管理的缓冲区(保存要生成的值),并保存每个结果的 duplicate

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

char *sdup(const char *src, const size_t len)
{
    char *s;

    s = malloc(len + 1);
    if (!s) {
        fprintf(stderr, "sdup(): Not enough memory for a duplicate of %zu-character string.\n", len);
        return NULL;
    }

    memcpy(s, src, len);
    s[len] = '\0';

    return s;
}

/* Initial buffer size, at least 1. */
#ifndef  INITIAL_BUFFER_SIZE
#define  INITIAL_BUFFER_SIZE  1
#endif

char **look_and_say(const size_t  count)
{
    char  **table;
    char   *src, *end;
    char   *dst, *pos;
    size_t  len, max = INITIAL_BUFFER_SIZE;
    size_t  i, k;

    if (count < 1) {
        fprintf(stderr, "look_and_say(): Count is less than 1.\n");
        return NULL;
    }

    /* Allocate memory for the array of pointers. */
    table = calloc(count + 2, sizeof *table);
    if (!table) {
        fprintf(stderr, "look_and_say(): Not enough memory for an array of %zu strings.\n", count);
        return NULL;
    }

    /* First and last entries are NULLs; sentinels, if you will. */
    table[0] = NULL;
    table[count + 1] = NULL;

    /* Allocate memory for the dynamic buffer. */
    dst = malloc(max);
    if (!dst) {
        fprintf(stderr, "look_and_say(): Not enough memory for a %zu-character work buffer.\n", max);
        free(table);
        return NULL;
    }

    /* The sequence starts with "1". */
    dst[0] = '1';
    len = 1;

    /* Save that. */
    table[1] = sdup(dst, len);

    /* Loop over the rest of the entries to be generated. */
    for (i = 2; i <= count; i++) {
        /* The source is the last item in the sequence. */
        src = table[i - 1];
        end = table[i - 1] + len;

        /* Ensure we have enough room for the next value in the sequence. */
        if (2*len > max) {
            /* TODO: Better growth policy! */
            max = 2*len;

            pos = realloc(dst, max);
            if (!pos) {
                fprintf(stderr, "look_and_say(): Not enough memory to grow work buffer to %zu chars.\n", max);
                free(dst);
                for (k = 1; k < i; k++)
                    free(table[k]);
                free(table);
                return NULL;
            }
            dst = pos;
        } else
            pos = dst;

        /* Source is [src, end[. pos is the next position in work buffer. */
        while (src < end) {
            const int  nc = *(src++);
            int        nn = '1';

            /* Skip if source is repeated twice or three times. */
            if (*src == nc) {
                src++;
                nn++;   /* 2 */
                if (*src == nc) {
                    src++;
                    nn++; /* 3 */
                }
            }

            *(pos++) = nn;
            *(pos++) = nc;
        }

        /* Length of the generated value. */
        len = (size_t)(pos - dst);

        /* Save to table. */
        table[i] = sdup(dst, len);
        if (!table[i]) {
            free(dst);
            for (k = 1; k < i; k++)
                free(table[i]);
            free(table);
            return NULL;
        }
    }

    /* Dynamic buffer is no longer needed. */
    free(dst);

    return table;
}

#ifndef  LIMIT
#define  LIMIT  30
#endif

int main(void)
{
    char **sequence;
    size_t i;

    sequence = look_and_say(LIMIT);
    if (!sequence)
        exit(EXIT_FAILURE);

    for (i = 1; i <= LIMIT; i++)
        printf("%zu. %s\n", i, sequence[i]);

    for (i = 1; i <= LIMIT; i++)
        free(sequence[i]);
    free(sequence);
    return EXIT_SUCCESS;
}

在这一点上,我们必须注意,我们已经有一个 O N )算法来生成序列中的下一个值,即 N 是上一个值的长度。要获得比线性性能更好的效果,需要一个更好的算法,但是据我所知,尚无比线性更好的解决方案。

我们当然可以在代码级别上优化上述代码;但是它的时间复杂度已经很好。

如果我们想“作弊”,我们可以观察到序列中前30个词的长度为1、2、2、4、6、6、8、10、14、20、26、34, 46、62、78、102、134、176、226、302、408、528、678、904、1182、1540、2012、2606、3410、4462。这表示如果我们为指针和19019个字符分配了足够的内存(长度总和+ 30(字符串结尾字符)),我们只需要分配一次即可。如果我们将第零个指针保留为NULL,则该分配为malloc(19019 + 31 * sizeof (char *))

但是,沿着这条道路继续前进,我们最终得到了以下代码或非常相似的代码:

static const char  term_1[] = "1";
static const char  term_2[] = "11";
static const char  term_3[] = "21";
static const char  term_4[] = "1211";
static const char  term_5[] = "111221";
/* term_6[] through term_30[] omitted */

static const char *sequence[31] = {
    NULL,
    term_1,  term_2,  term_3,  term_4,  term_5,
    term_6,  term_7,  term_8,  term_9,  term_10,
    term_11, term_12, term_13, term_14, term_15,
    term_16, term_17, term_18, term_19, term_20,
    term_21, term_22, term_23, term_24, term_25,
    term_26, term_27, term_28, term_29, term_30
};

这将在生成的二进制文件中生成大约19 KiB的只读(不可变)数据。即使该顺序对于操作至关重要,即使在许多微控制器上也不是问题。

如果存在使用内存的问题,可以将每个数字微不足道地打包为两位,以保持合理的访问时间,在这种情况下,仅将大约5 KiB的内存用于数据。