Quote Originally Posted by Salem View Post
"All" is an over simplification.
If you're talking about modern desktop OS, then memory from using malloc is reclaimed.
Good point. Really, even though I asked about memory allocated, it could be any resource that need to be freed. FILE* streams returned by fopen() come to mind. For the sake of simplicity, let's assume only space allocated by functions like malloc(), realloc() or calloc() are resources needed to be freed.

Quote Originally Posted by Salem View Post
Put it this way, if I ran valgrind with your program and found no memory leaks, I would be a lot more confident that you'd been paying attention to all the details.

You can avoid a lot of the tediousness through careful arrangement of the code.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define NAME_LENGTH 30

void dowork(char *name, size_t buflen) {
    fputs("Enter your name: ", stderr);
    fflush(stderr);
    if (fgets(name, buflen, stdin) == NULL) {
        fputs("Either EOF was encountered and no bytes were read, or an error"
              " ocurred when reading from standard input\n", stderr);
    } else {
        char *newline = strchr(name, '\n');
        if (newline != NULL) {
            *newline = '\0';
        }
        printf("Hello %s\n", name);
    }
}
 
int main(void) {
    char *name = malloc(NAME_LENGTH);
    if (name == NULL) {
        fputs("Not enough memory\n", stderr);
        exit(EXIT_FAILURE);
    } else {
        dowork(name, NAME_LENGTH);
        free(name);
    }
    return 0;
}
Valgrind is certainly a tool I definitely must check, because I'm currently using cppcheck to find errors in my code and it gives false positives sometimes, especially when I exit within the calls of other functions, like this:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NAME_LENGTH 30

void exit_with_msg(const char *msg) {
    fprintf(stderr, "%s\n", msg);
    exit(EXIT_FAILURE);
}

int main(void) {
    char *name = malloc(NAME_LENGTH);
    if (name == NULL) {
        fputs("Not enough memory\n", stderr);
        exit(EXIT_FAILURE);
    }
    
    fputs("Enter your name: ", stderr);
    fflush(stderr);
    if (fgets(name, NAME_LENGTH, stdin) == NULL) {
        free(name);
        exit_with_msg("Either EOF was encountered and no bytes were read, or an"
                      "error ocurred when reading from standard input");
    }
    
    char *newline = strchr(name, '\n');
    if (newline != NULL) {
        *newline = '\0';
    }
    
    printf("Hello %s\n", name);
    
    free(name);
    
    return 0;
}
cppcheck prints the following:
warning: Memory pointed to by 'name' is freed twice. [doubleFree]

I guess it's because it doesn't keep track of functions that don't return to their caller.

By the way, I like the way you concatenate long strings instead of using the backslash like I usually do haha. I had no idea it could be done like that.

Also, totally unrelated to the topic and I have no intention to be nitpicking. If you define buflen as size_t and pass it to the size paramater of fgets() which is of type int, wouldn't that cause overflow on systems where SIZE_MAX > INT_MAX? Really, 30 is by far less than the limits defined by the standard so I know it's not a problem, it just caught my attention that you passed a different type.