Search code examples
cstringstructmemory-leaksio

Why do I get the error "Process finished with exit code -1073741819 (0xC0000005) in my code", but it still works if I add a unrelated print statement?


I am still new to C, so I have no idea what might be happening here.

In this implementation of a String struct which should behave in a object-oriented way, there seems to be some error in the set function as I get this diagnostic:

Process finished with exit code -1073741819 (0xC0000005)

This is my .h file:

#include <string.h>
#include <stdbool.h>

typedef struct String_Struct
{
    char* value;
    unsigned int length;

    void (*set) (struct String_Struct* self, char* value);
    bool (*equals) (const struct String_Struct* self, const struct String_Struct* other);
    int (*compareTo) (const struct String_Struct* self, const struct String_Struct* other);
    void (*concat) (struct String_Struct* self, const struct String_Struct* other);
    void (*freeString) (struct String_Struct* self);
} String;

String* newString (char* value);
void set (String* self, char* value);
bool equals (const String* self, const String* other);
int compareTo (const String* self, const String* other);
void concat (String* self, const String* other);
void freeString (String* self);

This is its implementation:

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

void set (String* self, char* value)
{
    // Only proceed if self and value exist
    if (!self || !value)
    {
        return;
    }

    free(self->value);
    self->length = strlen(value) + 1;
    self->value = (char*) malloc(sizeof(char) * self->length);
    strcpy(self->value, value);
}

int compareTo (const String* self, const String* other)
{
    if ((!self && other) || (self && !other))
        return INT_MIN;

    return strcmp(self->value, other->value);
}

bool equals (const String* self, const String* other)
{
    if ((!self && other) || (self && !other))
        return false;

    if (self == other)
        return true;

    return strcmp(self->value, other->value) == 0;
}

void concat (String* self, const String* other)
{
    if (!self || !other)
    {
        return;
    }

    char* result = (char*) malloc(sizeof(char) * (strlen(self->value) + strlen(other->value) + 2));

    strcpy(result, self->value);
    strcat(result, other->value);

    self->set(self, result);
}

void freeString (String* self)
{
    free(self->value);
    free(self);
}

String* newString (char* value)
{
    String* str = (String*) malloc(sizeof(String));

    str->set = &set;
    str->equals = &equals;
    str->compareTo = &compareTo;
    str->concat = &concat;
    str->freeString = &freeString;

    str->set(str, value);

    return str;
}

And this is my main.c:

#include <stdio.h>
#include "mystring.h"

int main()
{
    String* string = newString("Hello");

    printf("%s", string->value);

    return 0;
}

When I run this code, I get the error which I provided above. But when I add a unrelated printf statement in "set" like so:

void set (String* self, char* value)
{
    // Only proceed if self and value exist
    if (!self || !value)
    {
        return;
    }

    printf("Debug");

    free(self->value);
    self->length = strlen(value) + 1;
    self->value = (char*) malloc(sizeof(char) * self->length);
    strcpy(self->value, value);
}

This is the console output: DebugHello Process finished with exit code -1073741819 (0xC0000005)

Can anyone explain why?


Solution

  • There is at least a problem in the set function:

      free(self->value);                 //  you free a pointer that has 
      self->length = strlen(value) + 1;  //  never been initialized
                                        
    

    Freeing pointer that has never been initialized doesn't make sense and it results in undefined behaviour (most of the time some kind of crash).

    You should initialize that pointer to NULL in newString:

      ...
      str->freeString = &freeString;
      str->value = NULL;  // <<< add this
    
      str->set(str, value);
      ...
    

    With that modification your code seems to work. I didn't investigate any further, so there might be more problems (bugs and/or design errors) elsewhere in this code.