0

I'm coding a program in which one of the tasks I need to complete is to store each line of a text file (the name of which is provided via command line) as a separate string for future manipulation.

I have two issues with my program.

The first is the problem of storing the string inside an array. When I assign an index of the array with the string, everything works fine. But as soon as I free() the string for allocation of another string, both strings get deleted.

userText[numStrings - 1] = currentString; 
/* Both userText at index and currentString hold the same value at this point */
free(currentString);
/* Both userText at index and currentString are free'd */

It could be a simple thing that I'm not understanding, I'm still quite new to C.

The second problem I have, is that I have no clue how to loop until the end of the file. I know that feof() exists, but that's kind of pointless since it will only return true until AFTER the end of the file, so I will be looping once more.

Here's the code: note it won't run until you set some condition in the last do/while loop.

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

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

    char** userText = NULL;
    char* currentString = NULL;
    int currentStringSize = 0;
    int numStrings = 0;


    FILE* fp = fopen(argv[1],"r");


    do{

        numStrings++;
        currentStringSize = 0;
        do{
            currentStringSize++;
            currentString = (char*)realloc(currentString, currentStringSize * sizeof(char));
            fscanf(fp, "%c", &currentString[currentStringSize - 1]);

        }while(!(currentString[currentStringSize - 1] == '\n'));
        currentString[currentStringSize - 1] = '\0';

        userText = (char**) realloc(userText, numStrings * sizeof(char*));

        for (int i = 0; i < numStrings; i++){
            userText[i] = (char*) realloc(userText[i], currentStringSize * sizeof(char));
        }

        userText[numStrings - 1] = currentString;
        free(currentString);
        currentString = NULL;
        } while (//the end of the file *insert code here*);


    for (int i = 0; i < numStrings; i++){
        free(userText[i]);
    }
    free(userText);
    fclose(fp);

    return 0;
}

Thank you for you help.

IrvinLesh
  • 25
  • 7
  • 1
    Three (unrelated) things: First you might want to read [this discussion about casting the result of `malloc`](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) (and related functions). Then `sizeof(char)` is defined by the C specification to always be `1`, so multiplying with is is not needed. Lastly, an expression like `!(a == b)` is equal to `a != b`. The latter is usually easier to read. – Some programmer dude Jun 02 '17 at 05:26
  • Delete `for (int i = 0; i < numStrings; i++){ userText[i] = (char*) realloc(userText[i], currentStringSize * sizeof(char)); }` , `userText[numStrings - 1] = currentString;` --> `userText[numStrings - 1] = strdup(currentString);` – BLUEPIXY Jun 02 '17 at 05:28
  • 1
    `free(currentString);` shouldn't be there. I'd start by understanding that. You spend quite a bit of time building that thing character by character in arguably the most expensive memory allocation scheme one could imagine. Saving the pointer, then immediately invalidating it by freeing it would be counter-productive. Pretty sure you just want the clear-to-null there. – WhozCraig Jun 02 '17 at 05:30
  • If possible, use `getline` to read a line. – BLUEPIXY Jun 02 '17 at 05:41

1 Answers1

1

These lines are very problematic:

for (int i = 0; i < numStrings; i++){
    userText[i] = (char*) realloc(userText[i], currentStringSize * sizeof(char));
}

userText[numStrings - 1] = currentString;
free(currentString);

First you allocate memory for userText[i], overwriting the pointers already existing in userText.

Then you simply overwrite the last pointer you allocated, making you lose the allocation you just did.

Lastly you free the memory pointed to by userText[numStrings - 1] (both that pointer and currentString are pointing to the same memory).

The solution to all these problems is simple: Just do

userText[numStrings - 1] = currentString;

That's it! That's all you need.


And as mentioned in a comment, you do need to make currentString a null pointer, before going back to the top of the loop and your calls to realloc.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 2
    The trailing `currentString = NULL;` is important. Only the `free` should be removed. – WhozCraig Jun 02 '17 at 05:30
  • Thank you so much for you help guys! It worked! Any ideas on how I could loop up until the end of the file? – IrvinLesh Jun 02 '17 at 06:33
  • @IrvinLesh Check what [`fscanf`](http://en.cppreference.com/w/c/io/fscanf) *returns*. If it returns anything but `1` (for your case) it means there's an error or the end of the file. – Some programmer dude Jun 02 '17 at 06:35
  • Ok. That makes sense. While testing the code, I found another little bug. I believe the '\0' is not being appended correctly. I tested out a text file: It\n Is\n Over 9000!!!\n. When I printed the results each time, I got: "It" "Is" "Over 9000!!!!è" The last character changes each time meaning it's just random stuff in memory. Sometimes if I add more characters, the extra characters increase in quantity. I do not see the wrong in my logic with the fscanf function. – IrvinLesh Jun 02 '17 at 07:45
  • Nevermind. It works it I key in 'enter' after my last line to put in the newline character. – IrvinLesh Jun 02 '17 at 07:58