Generating a string with only one space between the words
Always specify length of array pointers.

In C, it is not always guaranteed that an array of char will be null terminated and therefore, the size can be determined by calling strlen. Always pass along the length of the array when passing a pointer to a function. This is not just for strings, but also for other pointer types which point to a dynamically allocated and static arrays.

Naming

Choose a consistent naming plan. The most commonly found style in most C code is snake_case. But whatever you choose, stick to it and don't deviate.

Const-correctness

If a method is not going to modify it's parameters, make that intention clear by accepting the arguments as const. This form of programming is what makes code self-documenting because you don't need to tell anyone that the function does not modify it's parameter, the const specifier tells the whole story.

Malloc + free

Always remember, for every malloc, there should be an equal and opposite free. Not freeing memory leads to unexpected memory leakages. This may not apply to you now, but just know this, many man hours have gone into developing tools for detecting memory leaks (valgrind, leakSanitizer, etc) when the best programmers are making extra effort not to leak memory, but still fail. Memory leaks are no joke. Free the memory when you are finished with it.



With all that being said, here is my rendition of your code

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt; /* isspace */
#include &lt;stddef.h&gt; /* size_t */

#define SIZE (size_t)80

void inputStr(char*, size_t);
char* upgradeString(const char const*, size_t);

int main() {
    char string[SIZE] = {'\0'}, *result;
    printf("Enter string: ");
    inputStr(string, SIZE);

    size_t strLength = strlen(string);

    if (strLength &gt; 0 &amp;&amp; isspace(string[strLength - 1])) {
        string[--strLength] = '\0';
    }

    result = upgradeString(string, strLength);
    puts(result);
    free(result);
}

void inputStr(char* str, size_t length) {
    fgets(str, length, stdin);
}

char* upgradeString(const char const* oldText, size_t length) {

    size_t i, newSize = 0, foundSpace = 0;
    for (i = 0; i &lt; length; i++) {
        if (isspace(oldText[i])) {
            if (foundSpace) {
                continue;
            }
            foundSpace = 1;
        } else {
            foundSpace = 0;
        }
        newSize++;
    }

    char *result = malloc((sizeof *result) * (newSize + 1));

    if (result) {
        char *temp = result;
        foundSpace = 0;
        for (i = 0; i &lt; length; i++) {
            if (isspace(oldText[i])) {
                if (foundSpace) {
                    continue;
                }
                foundSpace = 1;
            } else {
                foundSpace = 0;
            }
            *temp++ = oldText[i];
        }
    }

    return result;
}


The changes made are based on the following additional considerations:


What happens if the user enters nothing (standard input is empty)?
What happens if the user just presses enter?


Conclusion

In conclusion be precise, be constant with naming, be explicit with intent. This will make your code robust and potentially bug free.

P.S.
It is not necessary to cast the result of malloc