0

I have a my_string object made that contains a char pointer, a size, and a capacity. I am trying to read words from a dictionary text file into the my_string object and print them to the screen. The default capacity is 7, so when I read a word that is longer than 7 characters, I need to reallocate some space at the end of the string. I haven't been able to implement this functionality correctly yet. It seems to work correctly, but when I run it in valgrind, there is apparently a memory leak somewhere in my code. Not sure where this is coming from, because I free the entire string after the program runs. If someone could help me with this you'd be a lifesaver. Here is my driver code, and my my_string.c file: main.c

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

int main(int argc, char* argv[]) {

  MY_STRING hMy_String = NULL;
  FILE* fp;

  hMy_String = my_string_init_default();
  fp = fopen("dictionary.txt", "r");

  int len;

  while(my_string_extraction(hMy_String, fp)) {

        len = my_string_get_size(hMy_String);

        if(len == 8){
                my_string_insertion(hMy_String, stdout);


                printf("\n");

                if(fgetc(fp) == ' '){
                        printf("Found a space after the string\n");
                }
        }

  }

  my_string_destroy(&hMy_String);
  fclose(fp);

  return 0;

}

my_string.c

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

struct my_string {

        int size;
        int capacity;
        char* data;

};

typedef struct my_string My_String;

MY_STRING my_string_init_default(void){
        //default capacity of string is 7

        //initializes pointer to My_String, set to NULL for good practice
        My_String* pMy_String = NULL;

        //allocates memory for default string
        pMy_String = (My_String*)malloc(sizeof(My_String));

        if(pMy_String != NULL) {
                pMy_String->size = 0;
                pMy_String->capacity = 7;
                pMy_String->data = (char*)malloc(sizeof(char) * pMy_String->capacity);
                if(pMy_String->data == NULL) {
                        free(pMy_String);
                        pMy_String = NULL;
                }
        }
        //returns copy of address to default string
        return pMy_String;
}


MY_STRING my_string_init_c_string(char* c_string) {
        int i = 0;
        //initializes a pointer to a My_String
        My_String* theString = NULL;

        //loops through string, for every character, i increases 1
        while((*c_string) != '\0'){
                c_string++;
                i++;
        }

        //resets c_strings value from before the loop
        c_string = c_string - i;
        i++; //i needs to be 1 greater than the length of the string

        //allocation
        theString = malloc(sizeof(My_String) + i);

        //if there was an error, return NULL
        if(theString == NULL)
                return NULL;
        else {
                //sets the values of the object to the given values
                (*theString).size = (i - 1);
                (*theString).capacity = i;
                (*theString).data = c_string;
        }

        //returns address of the initialized string
        return theString;
}


int my_string_get_capacity(MY_STRING hMy_string){

        return sizeof(hMy_string);
}

int my_string_get_size(MY_STRING hMy_string) {

        char* str = (char*) hMy_string;
        int size = 0;

        while(str[size] != '\0')
                size++;

        return size;
}

int my_string_compare(MY_STRING hLeft_string, MY_STRING  hRight_string) {

        // sets the strings to pointers to the My_String data type
        My_String* Left = hLeft_string;
        My_String* Right = hRight_string;
        //variables for lexicographical value of each string
        int left_lex = 0;
        int right_lex = 0;

        //loops through left string, adds up left_lex value
        while((*Left->data) != '\0') {
                left_lex += (*Left->data);
                (*Left).data++;
        }

        //loops through right string, adds up right_lex value
        while((*Right->data) != '\0') {
                right_lex += (*Right->data);
                (*Right).data++;
        }


        //does the comparison and returns the corrosponding value
        if(left_lex < right_lex){
                return -1;
        }else if (left_lex == right_lex) {
                return 0;
        }else {
                return 1;
        }

}

Status my_string_extraction(MY_STRING hMy_string, FILE* fp) {
        My_String* pMy_string = hMy_string;

        int start = 0, end = 0;
        char ch;
        int strLength, capacity, i;

        while(!feof(fp)){

                ch = fgetc(fp);


                if(ch == ' ' || ch == '\t' || ch == '\n' ||ch == '\r') {
                        continue;
                }
                else {
                        start = ftell(fp) - 1;
                        end = start + 1;
                        break;
                }
        }


        if(end == 0){
                return FAILURE;
        }


        while(!feof(fp)) {

                ch = fgetc(fp);
                end++;

                if(ch == ' ' || ch == '\t' || ch == '\n' ||ch == '\r'){
                        break;
                }

        }

        strLength = end - start - 1;
        (*pMy_string).size = strLength;

        if(strLength == 0){
                return FAILURE;
        }

        capacity = my_string_get_capacity(hMy_string);

        if(strLength >= capacity){
                hMy_string = realloc(hMy_string, strLength + 1);

        }

        fseek(fp, start, SEEK_SET);

        char* str = (char*)hMy_string;

        for(i = 0; i < strLength; i++) {
                str[i] = fgetc(fp);
        }

        str[i] = '\0';

        return SUCCESS;

}

Status my_string_insertion(MY_STRING hMy_string, FILE* fp) {
        char* str = (char*)hMy_string;


        if(fprintf(fp, "%s", str))
                return SUCCESS;
        else
                return FAILURE;
}

void my_string_destroy(MY_STRING* phMy_string){

        free(*phMy_string);
        *phMy_string = NULL;

}
  • `while(!feof(fp))` is suspicious. [ref](https://stackoverflow.com/q/5431941/2410359) – chux - Reinstate Monica Sep 24 '20 at 15:45
  • `void f(int x) {x = 5;} int main() {int j = 12; f(j); printf("%d\n", j);}` <- in your own words, what does it print and why? – user253751 Sep 24 '20 at 15:51
  • @user253751 it is going to print 12 because function f is not returning anything, therefore the value of j is never truly changed. – Dante Suarez Sep 24 '20 at 15:57
  • 2
    Always start *simple*, like with only an empty `main` function. Then add a *small* new thing, testning the code until you're sure everything works. By doing this it's much easier to rollback or debug when there's a problem. – Some programmer dude Sep 24 '20 at 15:57
  • @DanteSuarez Okay so what about this program: `void f(char *x) {free(x); x = malloc(1);} int main() {char *j = malloc(1); f(j); free(j);}` - does it have any problems? – user253751 Sep 24 '20 at 15:59
  • @user253751 I think there is a memory leak of 1 byte. I don't totally grasp why that is though. Isn't free(j) freeing the memory that was allocated in the f function? Obviously I'm missing something – Dante Suarez Sep 24 '20 at 16:18
  • @DanteSuarez Is it? Why does `j` change by `x = malloc(1);` but not by `x = 12;`? – user253751 Sep 24 '20 at 16:24
  • @user253751 I was thinking because x is a pointer, so the address of j would be holding the memory that was allocated in the f function – Dante Suarez Sep 24 '20 at 16:47
  • 1
    @DanteSuarez pointers are just normal variables – user253751 Sep 24 '20 at 16:48
  • @user253751 ah okay i see, I don't think I really understood what the free function actually does. In relation to my program though, doesn't realloc just allocate memory on the end of the desginated string? And wouldn't this mean that when I free hMy_string that it frees the whole thing including memory allocated onto the end? – Dante Suarez Sep 24 '20 at 17:02
  • @DanteSuarez Sometimes it does. But usually it allocates a new block of memory and it copies the data from the old block to the new block and frees the old block. – user253751 Sep 24 '20 at 17:03
  • @user253751 do you know of a way to account for that situation? or should I try to come up with a different solution for this functionality? thanks for all the help by the way. – Dante Suarez Sep 24 '20 at 17:58
  • @DanteSuarez well you need to go a nd put the pointer to the new block where the pointer to the old block was, so that next time, you use the pointer to the new block instead of the pointer to the old block. – user253751 Sep 24 '20 at 18:00

0 Answers0