cgcctcc

C code compiles and runs under Tiny C Compiler, but it does not run under GCC


I'm relearning C. The following code segment compiles and runs as expected under Tiny C Compiler (TCC). It compiles without complaint under GCC, but it doesn't produce any output under Windows 10.

When compiled and ran under Ubuntu, Tiny C Compiler works just as well, but GCC reports a segmentation fault (core dump). Why is it failing under GCC?

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

void UpCase(char * str);
void LowCase(char * str);

int main()
{
    void (* func)(char *) = &UpCase;
    func("Ab12Cd3EfG*h&");

    func = &LowCase;
    func("HiJ12kLm&No");
}

void UpCase(char * str)
{
    int i = 0;
    int ch = 0;

    for(i=0; str[i] != '\0'; i++)
    {
        ch = (int)str[i] + 0;
        if(ch > 96 && ch < 123)
            str[i] = (char)(ch - 32);
    }

    printf("UpCase: %s\n", str);
}

void LowCase(char * str)
{
    int i = 0;
    int ch = 0;

    for(i=0; str[i] != '\0'; i++)
    {
        ch = (int)str[i] + 0;
        if(ch > 64 && ch < 91)
            str[i] = (char)(ch + 32);
    }

    printf("LowCase: %s\n", str);
}

I'm a retired programmer trying to reconnect with C after decades of development in C# and T-SQL. My experience in C is way out of date since I wrote code under the K&R way back in the 1990s.


Solution

  • Modifying string literals invokes undefined behavior. On some systems, string literals are placed to read-only regions and trying to modify them leads to termination of the program.

    Instead of passing string literals to functions that modifies input strings, you should declare arrays with strings and pass them.

    int main()
    {
        char str1[] = "Ab12Cd3EfG*h&";
        char str2[] = "HiJ12kLm&No";
        void (* func)(char *) = &UpCase;
        func(str1);
        
        func = &LowCase;
        func(str2);
    }