1

I'm trying to learn about the basics in C and I can't quite get malloc() and free() to work.

This is my code that's going to print a word in the center of the screen depending on input. (removed some declarations and includes to shorten it)

char *bridge_text;
char menu1[] = "Key input:  \n\t n. car arrive north \
                            \n\t s. car arrive south \
                            \n\t r. empty bridge \
                            \n\t q. quit";
int main()
{
    bridge_text = malloc(sizeof(char)*(LEN+1)); //misprinted here before

    initscr();
    getmaxyx(stdscr,row, col);

    mvprintw(2, 4, menu1);
    refresh();
    while(run)
    {
        switch(getchar())
        {
            case 'q':
                run = 0;
                break;
            case 'n':
                /*not shown: char north[] = "NORTH";*/
                bridge_text = north; 
                break;
            case 's':
                bridge_text = south;
                break;
            case 'r':
                bridge_text = empty;
                break;
            default:
                bridge_text = empty;
                break;
        }

        mvprintw(row/2, (col-5)/2, bridge_text);
        refresh();
    }
    endwin();

    /* adding free() here results in core dump. */
    free(bridge_text);

    return 0;}

I use gcc with cygwin and the program is executed properly and I can quit the program using 'q'-key, however...

  • If first press 'n', 'e' or 'r' (assign bridge_text a string) and then try to exit, it results in a core-dump. This works fine if I remove free()

I do have an error when running executables with cygwin: *

fatal error MapViewOfFileEx shared 5'(0x66) Win 32 error 6.

maybe that's the problem but I assumed it wasn't related to this.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
dekuShrub
  • 466
  • 4
  • 20
  • delete `bridge_text = malloc(sizeof(LEN+1));` and `free(bridge_text);` – BLUEPIXY Jun 30 '15 at 15:09
  • You need to study the basics of pointers before attempting dynamic memory allocation. The problem is that you aren't doing string assignment correctly. – Lundin Jun 30 '15 at 15:13
  • You can use concatenation of adjacent string literals instead of line continuation: `"\tn. car arrive north\n"` `"\ts. car arrive south\n"` each on its own line. – pmg Jun 30 '15 at 15:27
  • sizeof(LEN+1) is a misprint. I was trying both (LEN+1) and sizeof(char)*(LEN+1) so I accidently typed like that. Is sizeof(char)*(LEN+1) any good? – dekuShrub Jun 30 '15 at 15:35
  • 1
    sizeof(char) is ALWAYS 1 in C. so remove that expression from the parameter to malloc(), as it has no effect and just clutters the code. – user3629249 Jul 01 '15 at 03:45
  • where is 'LEN' defined? what is its' value? where are 'row' and 'col' defined? – user3629249 Jul 01 '15 at 03:51
  • the code block beginning with switch(getchar()) is not handling the '\n' that follows each character – user3629249 Jul 01 '15 at 03:53
  • the menu1 is never being displayed to the user. – user3629249 Jul 01 '15 at 04:00
  • @user3629249 I'm using ncurses, so because of `initscr()` it doesn't wait for '\n'. It's the terminal setting that makes it wait for '\n' before processing input, not `getchar` in my understanding. Also `menu1` is printed to the ncurses-screen at `mvprintw` then it is made sure to be shown on screen on every call to `refresh`. _(I didn't include all definitions, to shorten the question)_ – dekuShrub Jul 01 '15 at 07:35

5 Answers5

4

Problems

  1. sizeof(LEN+1) will evaluate to size of an integer
  2. Dynamically allocated memory is lost when string is assigned

Change

bridge_text = malloc(sizeof(LEN+1));

to

bridge_text = malloc(LEN + 1);

and instead of assigning bridge_text = north, use strcpy

strcpy(bridge_text, north);
Shreevardhan
  • 12,233
  • 3
  • 36
  • 50
2

While doing

 bridge_text = north;

and simmilar assignments, you're overwriting the actual pointer returned by malloc(). Now, calling free() with non-dynamically allocated pointer (memory) is undefined behaviour. If you want, you can refer this answer for details.

Actually, to copy the content to already allocated memory, you can (and should) use strcpy(). Otherwise, by assigning, you're also creating memory leak, as the original pointer is lost.

Then,

 bridge_text = malloc(sizeof(LEN+1));

is also wrong. You need to change that to,

 bridge_text = malloc(LEN+1);   //sizeof(char) is 1 in c

After that, don't forget to check for the success of malloc(), too.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 1
    I think the real trick here is to never malloc in the first place, and simply point bridge_text to the chosen direction – Eregrith Jun 30 '15 at 15:05
  • @Eregrith yes, that can also be another approach, but in that case, `bridge_text` elemnts cannot be modified, right? – Sourav Ghosh Jun 30 '15 at 15:08
  • Yes but based on the code and the only call being `mvprintw(row/2, (col-5)/2, bridge_text);` (a print I guess), I think the `bridge_text` pointer is only there as a selection pointer – Eregrith Jun 30 '15 at 15:14
0

You cannot call free() on a non-dynamically allocated pointer.

What you malloc()'d is lost when you do bridge_text = north;

Eregrith
  • 4,263
  • 18
  • 39
0

bridge_text is declared as char *. This is not a string class as other languages have - it is simply a pointer to some memory that is to be read as a sequence of chars.

By assigning other values to bridge_text you have lost its original value (and therefore leaked the memory you malloc'd) and pointed it at another part of memory. This is why your program crashes when you try to free(bridge_text) - the pointer is no longer valid for freeing.

Also, as an aside, the sizeof operator gets the byte size of whatever you pass it - in this case a, presumably, integer constant - so you are actually only allocating 5 or 9 bytes (depending on system), not (LEN + 1).

You have a number of options to fix your code:

  • Don't dynamically allocate your char buffer. Change the declaration to char bridge_text[LEN + 1] and remove the malloc and free calls. Then use strcpy to populate it with data.
  • Simply use bridge_text as a pointer to other buffers containing items you want to print. This works if everything is constant or you put anything dynamic in a separate buffer (don't forget to make sure your dynamic buffer doesn't go out of scope though), e.g.

    char dynamic_string [50];
    int value = 10;
    sprintf(dynamic_string,"Value = %d", value);
    bridge_text = dynamic_string;
    
  • Keep using it as you are but fix your malloc size issue and change the bridge_text = <something> to strcpy(bridge_text,<something>).

0

This kind of line:

bridge_text = north; 

does not copy the text string in north[] to the char array bridge_text[].

it only copies pointers..

suggest:

strcpy( bridge_text, north ); 

in the current code, the malloc'd pointer in bridge_text is being overlayed by the assignment statements.

That is why the free() causes an abort.

suggest using 'strcpy()' to copy the strings into where bridge_text points

user3629249
  • 16,402
  • 1
  • 16
  • 17