1

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. I was basically trying to see how resizing arrays works in term of memory addresses.

#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. Here it is running with 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. So, what's going on here?

3
  • 1
    realloc returns the new pointer. If you don't save it, you loose the memory. But remember, if realloc fails and returns NULL, the old pointer is still valid, so don't reassign back to the same pointer you pass as argument to realloc. Commented Sep 15, 2022 at 6:22
  • 2
    buf = "hi"; throws away the pointer that was returned by malloc and replaces it with a pointer to a string literal. You can't pass a pointer to a string literal to realloc. If you want to put the string "hi" into the memory that malloc returned, then use strcpy(buf, "hi");. Commented Sep 15, 2022 at 6:22
  • 1
    With buff = "hi"; you reassign the original pointer returned by malloc. It's like doing int a = 10; a = 5; and then wondering why a isn't equal to 10 anymore. Commented Sep 15, 2022 at 6:23

1 Answer 1

3

Here:

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

You've reassigned the address held in 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.

Further, ALWAYS check return codes from any system call. You probably test if fopen() returned NULL. Well, memory allocation can fail, too!

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()

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. 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".

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...

#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

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.