0

A little more than 20 years ago I had some grasp of writing something small in C , but even at that time, I probably didn't really do things right all the time. Now I'm trying to learn C again, so I'm really a newbie.

Based on this article: Using realloc to shrink the allocated memory , I made this test, which works, but troubles me:

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

int test (char *param) {
    char *s = malloc(strlen(param));
    strcpy(s, param);
    printf("original string    : [%4d] %s \n",  strlen(s), s);
    // reduce size
    char *tmp = realloc(s, 5);
    if (tmp == NULL) {
        printf("Failed\n");
        free(s);
        exit(1);
    } else {
        tmp[4] = 0;
    }
    s = tmp;
    printf("the reduced string : [%4d] %s\n", strlen(s), s );
    free(s);
}

void main(void){
    test("This is a string with a certain length!");
}
  1. If I leave out "tmp[4] = 0", then I still get back the whole string. Does this mean the rest of the string is still in memory, but not allocated anymore?
  2. how does c free memory anyway? Does it keep track of memory by itself or is it something that is handled by the OS?
  3. I free the s string "free(s)", do I also need to free the tmp str (it does point to the same memory block, yet the (same) address it holds is probably stored on another memory location?

These are most likely just basics, but none of what I have read so far has given me a clear answer (including mentioned article).

BartM
  • 31
  • 5
  • 3
    `char *s = malloc(strlen(param));` too short by `1` -- recall the `'\0'` (nul terminating character) – David C. Rankin Nov 11 '21 at 02:09
  • `realloc()` automatically frees the original memory and returns the pointer to the reallocated memory (unless the new allocation failed). You don't need to free them both. – Barmar Nov 11 '21 at 02:10
  • 1
    "how does c free memory anyway" -- it's implementation-dependent, you don't have to worry about it. – Barmar Nov 11 '21 at 02:11
  • 2
    Some notes. 1) `main` must return an `int`. 2) `test` never returns anything, it should be `void test`. 3) `strlen` returns a `size_t`. Use the special `%zu` format, not `%d`. 4) `malloc` + `strcpy` risks allocating the wrong amount of memory; you're off by one. Use [`strdup`](https://en.cppreference.com/w/c/experimental/dynamic/strdup) instead. 5) Turn on compiler warnings. – Schwern Nov 11 '21 at 02:24
  • A pointer is simply a normal variable that holds an address as its value. When you `free()` memory you are passing the starting address for the memory block. When you do `s = tmp;`, both `s` and `tmp` hold the same address as their value (e.g. both point to the same address in memory). You only need to free once (or you will find a `"double-free or corruption"` error staring back at you...) Also note `strdup()` is POSIX not standard C, so you may or may not have it available. – David C. Rankin Nov 11 '21 at 02:25
  • One question per question, please. – TomServo Nov 11 '21 at 02:31

1 Answers1

5
  1. If I leave out "tmp[4] = 0", then I still get back the whole string.

You've invoked undefined behavior. All the string operations require the argument to be a null-terminated array of characters. If you reduce the size of the allocation so it doesn't include the null terminator, you're accessing outside the allocation when it tries to find it.

Does this mean the rest of the string is still in memory, but not allocated anymore?

In practice, many implementations don't actually re-allocate anything when you shrink the size. They simply update the bookkeeping information to say that the allocated length is shorter, and return the original pointer. So the remainder of the string stays the same unless you do another allocation that happens to use that memory.

This can even happen when you grow the size. Some designs always allocate memory in specific granularities (e.g. powers of 2), so if you grow the allocation but it doesn't exceed the granularity, it doesn't need to copy the data.

  1. how does c free memory anyway? Does it keep track of memory by itself or is it something that is handled by the OS?

Heap management is part of the C runtime library. It can use a variety of strategies.

  1. I free the s string "free(s)", do I also need to free the tmp str (it does point to the same memory block, yet the (same) address it holds is probably stored on another memory location?

After s = tmp;, both s and tmp point to the same allocated memory block. You only need to free one of them.

BTW, the initial allocation should be:

char *s = malloc(strlen(param)+1);

You need to add 1 for the null terminator, since strlen() doesn't count this.

Barmar
  • 741,623
  • 53
  • 500
  • 612