0

I read a text file with a content like this "sasdfsdf" with the following code:

char* o = new char[size];
c = 0;
for (i = 0; i < n; i++)
{
    fseek(pFile, i, SEEK_SET);
    b = fgetc(pFile);
    if (b == '\r') {
        o[c] = b;
        c++;
        o[c] = '\n';
    }
    else {
        o[c] = b;
    }
    c++;
}
fclose(pFile);

SetWindowTextA(TextBox1.hWnd, (n > 0) ? o : NULL);

delete[] o;

First I would like to know if this code is clean. I assume it is not because I am new to C/Cpp and have sometimes some problems with understanding the allocating-stuff. I would like to use the C-style (FILE*, fopen, fseek, fgetc) to get the content of the file. The problem is that the char* o is always added something. I have an example: instead of "sasdfsdf" (text file content) it writes "sasdfsdf¨‰»3" into the edit control. I found out that the "¨‰»3" is added when the for-loop-scope is left. I assume it is something like a memory leak. I have no other idea where this characters should come from.

mch
  • 8,070
  • 2
  • 24
  • 39
rwCapt
  • 1
  • 1

2 Answers2

2

As the comments indicate, you are writing in C, but have tagged your question C++. Here, C++ provides a much shorter solution that does not require any dynamic allocation on your part (and even your C style code, none is needed, simply using constexpr size_t nelem = size; char o[nelem] = ""; would create a simple array of the desired length).

The part you are missing above is that fgetc() advances the flle-position each time is reads a character from the file stream, so there is no need for fseek(pFile, i, SEEK_SET); at all, it is simply superfluous.

In C++, you are much better off reading from a fstream rather than using C FILE*. You are much better off using std::string than char* as std::string eliminates the possibility of writing beyond he end of your array (which you fail to check for in your loop). After you read a line from your file with getline(), you can simply use std::replace() to replace all '\r' with '\n'. When you are done, all memory is freed automatically.

You would write your routine similar to:

#include <fstream>
#include <string>
#include <algorigthm>

void somefunc (std::fstream& stream)
{
    std::string line{}, windowtext{};
    
    while (getline (stream, line)) {
        std::replace (line.begin(), line.end(), '\r', '\n');
        windowtext += line;
    }
    
    SetWindowTextA (TextBox1.hWnd, windowtext.length() > 0 ? windowtext : nullptr);
    
    /* close file back in caller */
}

(note: in C++ the open file stream will be closed when the file stream object goes out of scope, so you won't need to manually close the stream)

Also Note as @RemyLebeau points out in the comments, on windows, getline() will remove both the CR and LF that make up the DOS line endings. If you need the manual '\n' to create a line-break, then you will need windowtext += line + '\n'; instead of std::replace to inject the '\n'.

Look things over and let me know if you have questions.

David C. Rankin
  • 69,681
  • 6
  • 44
  • 72
  • 1
    This code is clearly running on Windows. There is no need for `std::replace('\r', '\n')` as `std::getline()` on Windows will handle reading both `\n` and `\r\n` line breaks for you, and not include any line breaks in the output `string` at all. If you want line breaks in the `string`, you will have to add them yourself (is `TextBox1` configured to allow multiple lines? If not, then why bother with line breaks at all?) – Remy Lebeau Mar 22 '21 at 18:35
  • @RemyLebeau If I understand the question, the line breaks ARE wanted for `SetWindowTextA`. The OP is building text for a dialog that needs the line breaks. (if that's not the case -- then you are correct, there is no need for `std::replace()`) – David C. Rankin Mar 22 '21 at 18:38
  • @DavidCRankin My point was, there won't be anything for `std::replace()` to replace, because `std::getline()` won't output any `\r` characters to begin with, so you would need something more like `while (getline (stream, line)) { windowtext += line + '\n'; }`. But there is no indication in the OP's question where `TextBox1` is configured as a **single-line** or **multi-line** UI control (different settings at the OS API layer). – Remy Lebeau Mar 22 '21 at 18:46
  • That makes sense, but testing with DOS CRLF on Linux, the `'\r'` is left by `getline()` and it's replacement provides the line breaks. But it would make sense on windows that both CRLF would be stripped. What's also unclear in the question if reading with `fgetc()` both `'\r'` and `'\n'` would be part of the input, so as written the OP is injecting a `"\n\n"` for every `"\r\n"`. – David C. Rankin Mar 22 '21 at 18:50
  • @RemyLebeau - I updated the answer to reflect the discussion. – David C. Rankin Mar 22 '21 at 18:55
  • @DavidCRankin yes, `getline()` on Linux does not handle `\r\n` only `\n`, so `\r` would be output on a DOS-style file. However, `SetWindowTextA()` is a Windows-only function, so I'm not concerned about Linux behavior in this question. – Remy Lebeau Mar 22 '21 at 20:31
0

You must terminate the string by adding terminating null-character '\0'.

                    char* o = new char[size];
                    c = 0;
                    for (i = 0; i < n; i++)
                    {
                        fseek(pFile, i, SEEK_SET);
                        b = fgetc(pFile);
                        if (b == '\r') {
                            o[c] = b;
                            c++;
                            o[c] = '\n';
                        }
                        else {
                            o[c] = b;
                        }
                        c++;
                    }
                    o[c] = '\0'; // add this to terminate the string
                    fclose(pFile);

                    SetWindowTextA(TextBox1.hWnd, (n > 0) ? o : NULL);

                    delete[] o;
MikeCAT
  • 61,086
  • 10
  • 41
  • 58