简体   繁体   English

尽管在 malloc'ed 字符串上使用 realloc 还是无法工作

[英]realloc not working despite using it on a malloc'ed string

I'm not really sure why this is happening but in the code below I made a simple program to help me understand how malloc works.我不太确定为什么会发生这种情况,但在下面的代码中,我编写了一个简单的程序来帮助我了解 malloc 的工作原理。 I was basically trying to see how resizing arrays works in term of memory addresses.我基本上是想看看如何根据 memory 地址调整 arrays 的大小。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[])
{

    
    char* buff;
    buff = malloc(10);
    buff = "hi";
    printf("%c\n", buff[0]);
    printf("%p\n", &buff[0]);

   if (realloc(buff, (size_t) 20) == NULL){
       printf("no\n");
       exit(1);
   }
    
    printf("%p\n", &buff[0]);
    
    return 0;
}

But when I run it, realloc returns NULL.但是当我运行它时,realloc 返回 NULL。 Here it is running with valgrind.在这里,它与 valgrind 一起运行。

valgrind ./test
==3421== Memcheck, a memory error detector
==3421== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==3421== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==3421== Command: ./test
==3421==
h
0x400734
==3421== Invalid free() / delete / delete[] / realloc()
==3421==    at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3421==    by 0x400673: main (in /home/puf311/cs3733/practice/test)
==3421==  Address 0x400734 is not stack'd, malloc'd or (recently) free'd
==3421==
no==3421==
==3421== HEAP SUMMARY:
==3421==     in use at exit: 10 bytes in 1 blocks
==3421==   total heap usage: 2 allocs, 1 frees, 15 bytes allocated
==3421==
==3421== LEAK SUMMARY:
==3421==    definitely lost: 10 bytes in 1 blocks
==3421==    indirectly lost: 0 bytes in 0 blocks
==3421==      possibly lost: 0 bytes in 0 blocks
==3421==    still reachable: 0 bytes in 0 blocks
==3421==         suppressed: 0 bytes in 0 blocks
==3421== Rerun with --leak-check=full to see details of leaked memory
==3421==
==3421== For counts of detected and suppressed errors, rerun with: -v
==3421== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

As far as I know, the string is malloc'ed, and I definitely didn't free it earlier.据我所知,字符串是 malloc 的,而且我之前肯定没有释放它。 So, what's going on here?那么,这里发生了什么?

Here:这里:

buff = malloc(10);
buff = "hi";

You've reassigned the address held in buff ...您已经重新分配了buff中保存的地址...

You probably meant:你可能的意思是:

strcpy( buff, "hi" );

And, you need to capture the returned pointer from realloc() in case that function has relocated your data to grow/shrink the buffer.而且,您需要从realloc()捕获返回的指针,以防 function 已重新定位您的数据以增大/缩小缓冲区。

Further, ALWAYS check return codes from any system call.此外,始终检查任何系统调用的返回码。 You probably test if fopen() returned NULL.您可能会测试fopen()是否返回 NULL。 Well, memory allocation can fail, too!好吧,memory 分配也可能失败!

char *buff = malloc( 10 );
if( buff == NULL ) {
    fprintf( stderr, "malloc failed\n" );
    exit( EXIT_FAILURE ); // probably not going to get much further
}

EDIT: That was too easy.编辑:那太容易了。 Here's an annotated version that (omitting typos) should show how you should/could use realloc()这是一个带注释的版本(省略拼写错误)应该显示您应该/可以如何使用realloc()

int main() {
    char *buff = malloc( 10 );
    if( buff == NULL ) {
        fprintf( stderr, "Failed to launch!\n" );
        exit( EXIT_FAILURE );
    }

    strcpy( buff, "hi" ); // should fit!
    puts( buff ); // working???

    printf( "%c\n", buff[0] ); // should be 'h'

    printf( "%p\n", &buff[0] ); // should be the same as...
    printf( "%p\n",  buff    ); // this

    { // NB: 'tmp' is only within the 'scope' of this pair of braces
        char *tmp = realloc( buff, 20 ); // delicately
        if ( tmp == NULL ) {
            // Here it is, but this need not be a "hard error"
            // Report problem, but could perhaps continue with same sized buffer, somehow...
            fprintf( stderr, "Cannot grow the buffer, but,,, ");
            printf( "still have '%s' and 'Good-bye'\n", buff );
            free( buff );
            exit( EXIT_FAILURE);
        }
        buff = tmp; // Got it. (Don't replace if "soft error" of tmp being NULL, of course)
    }

    printf( "%p\n", buff ); // just to see if block relocated

    free( buff ); // don't forget about this

    return 0;
}

Caveat: It's up to you, the programmer who 'reserves' blocks of heap memory, to track how big that block is and not "scribble" outside of that playground.警告:这取决于你,“保留”堆 memory 块的程序员,来跟踪那个块有多大,而不是在那个操场之外“乱涂乱画”。 free() will do the right thing, but between malloc() and free() , and made more complex with realloc() there is a lot of opportunity to overrun the buffer and invoke "undefined behaviour". free()会做正确的事情,但是在malloc()free()之间,并且使用realloc()变得更加复杂,有很多机会超出缓冲区并调用“未定义的行为”。

Taking this one step further...更进一步……

In fact, on some occasions the code is better using only realloc() that "acts like malloc() " when it receives a NULL as the first parameter...事实上,在某些情况下,当代码接收 NULL 作为第一个参数时,使用“行为类似于malloc() ”的realloc()会更好......

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

int main() {
    char sentence[] = "The  quick brown   fox jumps   over the lazy dog";
    char **words = NULL;

    // Chop up a mutable string (sentence), isolating each word
    // accessible via its own pointer.
    // realloc() "grows" the array of pointers to words.
    int i = 0; 
    for( char *p = sentence; (p = strtok( p, " " )) != NULL; p = NULL ) {
        char **tmp = realloc( words, (i+1) * sizeof *tmp );
        if ( tmp == NULL ) {
            fprintf( stderr, "realloc failed on %d - %s\n", i, p );
            free( words );
            exit( EXIT_FAILURE);
        }
        words = tmp;
        words[ i++ ] = p;
        printf( "cnt(%d) ", i ); // debugging
    }
    putchar( '\n' ); // debugging

    while( i-- ) // reverse order
        puts( words[i] ); 

    free( words );

    return 0;
}

Output Output

cnt(1) cnt(2) cnt(3) cnt(4) cnt(5) cnt(6) cnt(7) cnt(8) cnt(9)
dog
lazy
the
over
jumps
fox
brown
quick
The

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM