Metin Usta
Metin Usta

Reputation: 185

Why is my solution for Super Reduced String(HackerRank) question working fine on my computer but giving wrong answers in HackerRank?

When I run my code in Hackerrank it fails 6/16 test cases but when I try the same test cases on my computer it works fine.

This is the code that I run on my computer:(I use Clion as ide and the latest MinGW as compiler.)

I initialize the string with one of the test cases that fail on HackerRank.

#include <string.h>
#include <stdio.h>
//#include <stdlib.h>
char* superReducedString(char* s);
int contain(char *S,char find);
void copyWithout(char *S,char *T,char trash);
int countWithout(char *S,char trash);
int findSize(char *S);
void fillString(char *S,char filler);
int main(){
    char s[] = {"ppffccmmssnnhhbbmmggxxaaooeeqqeennffzzaaeeyyaaggggeessvvssggbbccnnrrjjxxuuzzbbjjrruuaaccaaoommkkkkxx"};
    char *result = superReducedString(s);
    printf("%s",result);
}
int findSize(char *S){
    int i = 0;
    while(*(S+i) != '\0'){
        i++;
    }
    return i;
}
void fillString(char *S,char filler){
    int i = 0;
    while(*(S+i) != '\0'){
        *(S+i) = filler;
        i++;
    }
}
void copyWithout(char *S,char *T,char trash){
    fillString(T,'0');
    int i = 0;
    int count = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) != trash){
            *(T+count) = *(S+i);
            count++;
        }
        i++;
    }
}
int countWithout(char *S,char trash){
    int i = 0;
    int count = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) != trash){
            count++;
        }
        i++;
    }
    return count;
}
int contain(char *S,char find){
    int i = 0;
    int flag = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) == find){
            flag = 1;
        }
        i++;
    }
    return flag;
}
char* superReducedString(char* s){
    static char empty[] = "Empty String";
    static char result[1024];
    int flag = 1;
    char temp[findSize(s)];
    fillString(temp,'0');
    int i,j;//Loop variable.
    i = 0;
    while(*(s + i) != '\0'){
        j = 0;
        //Checking if adjacent numbers is same. If it is changing them to '0'.
        while(s[j] != '\0') {
            if (s[j] == s[j + 1]) {
                *(s + j) = '0';
                *(s + j + 1) = '0';
            }
            j++;
        }
        if(contain(s,'0') == 0){ //If there is no zero in original string that means nothing changed.
            return s;
        }else{
            copyWithout(s,temp,'0');//If there are zeros in it, copy it to a temp char array without zeros.
        }
        strcpy(s,temp);//Copy temp to s again for swapping.
        i++;
    }
    int count = countWithout(s,'0'); //Calculate the size of original string without zeros.
    char finalString[count];//Initialize a new string with the calculated size.
    copyWithout(s,finalString,'0'); //Copy original string to finalString without zeros to obtain a clear zeroless string.
    strcpy(result,finalString);//copy finalstring to static result string to return it.
    i = 0;
    while(*(result+i) != '\0'){ //Check if result string consists of zeroes. If it is code will return empty string.
        if(*(result+i) != '0'){
            flag = 0;
        }
        i++;
    }
    if(flag == 0){
        return result;
    }else{
        return empty;
    }
}

and this is the code that I run on HackerRank:

#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* superReducedString(char* s);
int contain(char *S,char find);
void copyWithout(char *S,char *T,char trash);
int countWithout(char *S,char trash);
int findSize(char *S);
void fillString(char *S,char filler);
char* readline();
int main()
{
    FILE* fptr = fopen(getenv("OUTPUT_PATH"), "w");

    char* s = readline();

    char* result = superReducedString(s);

    fprintf(fptr, "%s\n", result);

    fclose(fptr);

    return 0;
}

char* readline() {
    size_t alloc_length = 1024;
    size_t data_length = 0;
    char* data = malloc(alloc_length);

    while (true) {
        char* cursor = data + data_length;
        char* line = fgets(cursor, alloc_length - data_length, stdin);

        if (!line) {
            break;
        }

        data_length += strlen(cursor);

        if (data_length < alloc_length - 1 || data[data_length - 1] == '\n') {
            break;
        }

        alloc_length <<= 1;

        data = realloc(data, alloc_length);

        if (!data) {
            data = '\0';

            break;
        }
    }

    if (data[data_length - 1] == '\n') {
        data[data_length - 1] = '\0';

        data = realloc(data, data_length);

        if (!data) {
            data = '\0';
        }
    } else {
        data = realloc(data, data_length + 1);

        if (!data) {
            data = '\0';
        } else {
            data[data_length] = '\0';
        }
    }

    return data;
}
int findSize(char *S){
    int i = 0;
    while(*(S+i) != '\0'){
        i++;
    }
    return i;
}
void fillString(char *S,char filler){
    int i = 0;
    while(*(S+i) != '\0'){
        *(S+i) = filler;
        i++;
    }
}
void copyWithout(char *S,char *T,char trash){
    fillString(T,'0');
    int i = 0;
    int count = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) != trash){
            *(T+count) = *(S+i);
            count++;
        }
        i++;
    }
}
int countWithout(char *S,char trash){
    int i = 0;
    int count = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) != trash){
            count++;
        }
        i++;
    }
    return count;
}
int contain(char *S,char find){
    int i = 0;
    int flag = 0;
    while(*(S+i) != '\0'){
        if(*(S+i) == find){
            flag = 1;
        }
        i++;
    }
    return flag;
}
char* superReducedString(char* s){
    static char empty[] = "Empty String";
    static char result[1024];
    int flag = 1;
    char temp[findSize(s)];
    fillString(temp,'0');
    int i,j,k;//Loop variable.
    i = 0;
    while(*(s + i) != '\0'){
        j = 0;
        while(s[j] != '\0') {
            if (s[j] == s[j + 1]) {
                *(s + j) = '0';
                *(s + j + 1) = '0';
            }
            j++;
        }
        if(contain(s,'0') == 0){
            return s;
        }else{
        //    printf("temp0 = %s s0 = %s\n",temp,s);
            copyWithout(s,temp,'0');
        //    printf("temp1 = %s s1 = %s\n",temp,s);
        }
        //printf("%s\n",temp);
        strcpy(s,temp);
        i++;
    }
    int count = countWithout(s,'0');
    char finalString[count];
    copyWithout(s,finalString,'0');
    strcpy(result,finalString);
    i = 0;
    while(*(result+i) != '\0'){
        if(*(result+i) != '0'){
            flag = 0;
        }
        i++;
    }
    if(flag == 0){
        return result;
    }else{
        return empty;
    }
}

The only difference is main function and the functions that HackerRank uses for getting input.

I don't know if this helps but sometimes my code can give wrong answers for same input. What I mean is:

input = "acdqglrfkqyuqfjkxyqvnrtysfrzrmzlygfveulqfpdbhlqdqrrqdqlhbdpfqluevfgylzmrzrfsytrnvqyxkjfquyqkfrlacdqj"

While it should give "acdqgacdqj" as answer, it gives "acdqgacdqjÑ" The last char randomly changes.

But for other inputs no matter how many times I run it it gives the correct answer on my computer.

Upvotes: 1

Views: 196

Answers (2)

KamilCuk
KamilCuk

Reputation: 141975

  • char temp[findSize(s)]; fillString(temp,'0'); is invalid. In fillString you iteratate until the element is equal to '\0'. temp is uninitialized - you can't expect it to have any certain value (and even reading an uninitialized value is undefined behavior).
  • In char finalString[count]; count is too small - it doesn't account for zero terminating character. copyWithout(s,finalString,'0'); is not copying zero terminating character. Which results in strcpy(result,finalString); accessing array out-of-bounds when searching for.... zero terminating character.

When working with C string you usually see a magical + 1 everywhere in the code.

Advices:

  • Prefer not use variable length arrays (arrays where the size expression is not a constant expression). Prefer using dynamic allocation.
  • findSize is just strlen...
  • fillString is just memset(string, value, strlen(string));
  • When using a compiler, always enable all options. When using gcc, you could use gcc -g -Wall -Wextra -fsanitize=address sourcefile.c - sanitize will allow to really fast find all out-of-bounds accesses on stack variables. Use valgrind to find dynamic allocation leaks.
  • I advise to change order of argument in copyWithout to (destination, source, fill) so it's the same as strcpy(destination, source) - ie. destination is first.

Seems like fixing parts of code to:

char* superReducedString(char* s){
    ...
    // char temp[findSize(s)];
    char temp[findSize(s) + 1];
    // fillString(temp,'0');
    memset(temp, '0', findSize(s));
    temp[findSize(s)] = '\0';
    ...
    char finalString[count + 1];//Initialize a new string with the calculated size.
    memset(finalString, '0', count);
    finalString[count] = '\0';
}

is enough for me to -fsanitize to stop erroring.

Upvotes: 2

gnasher729
gnasher729

Reputation: 52632

I have no idea where exactly your bug is, but it is quite clear from the output that you are using uninitialised memory. And on your computer, that uninitialised memory contains a zero by pure coincidence, and on the computer used for the test it doesn't.

Generally if you have a problem "it works on computer A but not on computer B" then very often undefined behaviour in your code is the answer, and here it is most like uninitialised memory.

Upvotes: 1

Related Questions