What makes this C program unusable when compiled in different versions of GCC or Clang?

Asked

Viewed 53 times

2

This C language program is compiled in all versions of GCC without any error message, but specifically in GCC 6.3 and 8.3, the executable produces totally inconsistent results. In GCC 8.1 and 10.2 (the ones I use on my machine) it works perfectly. What can be the explanation?

/*
    Crie uma função do zero para determinar se uma string é palíndromo ou não
    (ignoring case and blank spaces). A utilização da biblioteca <string.h> não 
    é permitida.
*/

/*libraries*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
/*libraries*/

/*Fixed string max size*/
#define SIZE 100
/*Fixed string max size*/

/*strlen from scratch*/
size_t strlength(char *str) {
    size_t size = 0;
    while (str[++size] != '\0');
    return size;
}
/*strlen from scratch*/

/*Take off '\n' from fgets input*/
void takeOffNewLine(char *str) {
    str[strlength(str) - 1] = ('\0');
}
/*Take off '\n' from fgets input*/

/*strcpy from scratch*/
void strcopy(char *strDest, char *strSource) {
    size_t sourceSize = strlength(strSource);

    for (size_t i = 0; i <= sourceSize; i++) {
        strDest[i] = strSource[i];
    }
}
/*strcpy from scratch*/

/*Take off ' ' whitespaces from a string*/
void takeOffBlankChars(char *str) {
    size_t size = strlength(str);
    
    for (size_t i = 0; str[i] != '\0'; i++) {
        if (str[i] == ' ') {
            for (size_t j = i; j <= size; j++) {
                str[j] = str[j + 1]; 
            }
            i--; 
            /*
             * O decremento do iterador "i" 
             * mantém o array de caracteres na 
             * mesma posição onde o caractere 
             * em branco foi encontrado, com o 
             * intuito de checar se há outro 
             * whitespace em "str[i + 1]", que 
             * foi reposicionado para "str[i]".
             */  
        }
    }
}
/*Take off ' ' whitespaces from a string*/

/*entire string to lowercase*/
void strToLower(char *str) {
    size_t size = strlength(str);

    for (size_t i = 0; i < size; i++) {
        str[i] = tolower(str[i]);
    }
    str[size] = '\0';
}
/*entire string to lowercase*/

/*invert string*/
void invertStr(char *strSource, char *strInverted) {
    size_t size = strlength(strSource);
    
    for (size_t i = 0; i < size; i++) {
        strInverted[i] = strSource[size - i - 1];
    }
    strInverted[size] = ('\0');
}
/*invert string*/

/*check if they're palindromes*/
bool strccmp (char *str1, char *str2) {
    size_t sizeStr1 = strlength(str1);
    size_t sizeStr2 = strlength(str2);

    if(sizeStr1 != sizeStr2) {
        return false;
    }

    size_t size = sizeStr1;

    char *str1LwrCase = malloc(sizeof(char) * (size + 1));
    char *str2LwrCase = malloc(sizeof(char) * (size + 1));
    if (str1LwrCase == 0 || str2LwrCase == 0)
    {
        printf("Memory Allocation error in <<strccmp()>>\n");
        return false;
    }
    
    strcopy(str1LwrCase, str1);
    strcopy(str2LwrCase, str2);

    takeOffBlankChars(str1LwrCase);
    takeOffBlankChars(str2LwrCase);

    strToLower(str1LwrCase);
    strToLower(str2LwrCase);

    bool isEqual = true;
    for (size_t i = 0; str1LwrCase[i] != '\0'; i++) {
        if(str1LwrCase[i] != str2LwrCase[i]) {
            isEqual = false;
            free(str1LwrCase);
            free(str2LwrCase);
            return isEqual;
        }
    }
    free(str1LwrCase);
    free(str2LwrCase);
    return isEqual;
}
/*check if they're palindromes*/

int main(void) {
    char s1[SIZE] = {'\0'};
    char s2[SIZE] = {'\0'};

    fgets(s1, SIZE, stdin);
    takeOffNewLine(s1);
    
    invertStr(s1, s2);

    if (strccmp(s1, s2)) {
        printf("It's a palindrome.\n");
    } 
    else {
        printf("It's not a palindrome.\n");
    }
    
    return EXIT_SUCCESS;
}

String input (which is a palindrome) tested by me: L V R E of the vile power

Incorrect result in:

  • ideone (GCC 8.3)
  • codechef (GCC 6.3)

Correct result in:

  • onlinegdb
  • programmable
  • tutorialspoint
  • repl.it (Clang 7.0)
  • jdoodle (GCC 5.3, 7.2, 8.1 and 9.1)
  • On my Windows 10 machine with Mingw64 and GCC 10.2, and on WSL with GCC (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
  • 2

    It is not the cause of the problem but its function strlength gives a wrong result to an empty string. You are assuming the function fgets at all times add a ' n' as the last character of the read string, which may not be true. Here https://ideone.com/fIfGt1 worked as expected (gcc 8.3).

  • You killed the riddle. The problem is in the way the string is read, it has nothing to do with the compiler. Only when input is given via command line does fgets capture the \n / enter . And thank you for strlength() . I’ll check whether or not newline in function takeOffNewLine()

No answers

Browser other questions tagged

You are not signed in. Login or sign up in order to post.