0

I have one problem with CString and STL's set.
It looks a bit strange to use CString and STL together, but I tried to be curious.
My code is below:

#include "stdafx.h"
#include <iostream>
#include <set>
#include <atlstr.h>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    wchar_t line[1024] = {0};
    FILE * pFile = _wfopen(L"F:\\test.txt", L"rt");

    set<CString> cstr_set;

    while (fgetws(line, 1024, pFile))
    {
        CString cstr;
        swscanf(line, L"%s\n", cstr);
        cstr_set.insert(cstr);
    }

    fclose(pFile);
    cout << "count" << cstr_set.size();
    return 0;
}

The contents of the test.txt is:

13245  
123  
2344  
45  

After the loop ends, cstr_set contains only one value.
It works as if cstr is static or const variable.
What is the problem?

secuman
  • 539
  • 4
  • 12
  • I'm pretty sure `swscanf` does not know how to populate a `CString` and that all kinds of fun memory corruption ensue. – Quentin Sep 23 '21 at 07:47
  • So why is the local variable `cstr` continue to be used? If I run this in debug mode step by step, the buffer of the local variable 'cstr' is using the same memory in each loop, and so it does not seem to add a value to set. – secuman Sep 23 '21 at 07:53
  • 1
    @secuman: Undefined Behavior is Undefined. Literally anything can happen. – MSalters Sep 23 '21 at 07:55
  • *Can CString be used with stl set?* -- You ask this question, but the code you showed is doing much more than simply setting values in a set using the `CString` type. How about a very simple `main` program, where the strings are in an array, instead of the dodgy file reading stuff that has already been pointed out? – PaulMcKenzie Sep 23 '21 at 08:07
  • @PaulMcKenzie: I ask the question when I use the `CString` directly in the `swscanf` function, it has occurred a strange operation. I think the title of the question is a bit wrong. – secuman Sep 23 '21 at 08:13
  • 1
    @secuman Well, the answer to the title is "yes, CString can be used in a std::set". The problem is that you messed up things by introducing undefined behavior using `swscanf`. Create a simple array, i.e. `const wchar_t* test[] = { L"12345", L"123", L"2344", L"45" };` -- write a loop, that assigns `test[i]` to `cstr`, and you will see that `std::set` works correctly. Why you didn't do this initially as a test, that's another story. – PaulMcKenzie Sep 23 '21 at 08:16
  • @PaulMcKenzie: I repaired the title. – secuman Sep 23 '21 at 08:23
  • @secuman Why not try opening the `test.txt` file in binary mode `rb` and see? I suspect it's an encoding problem. – Fractal Sep 23 '21 at 08:50
  • @Fractal: No, it's not encoding problem. – secuman Sep 23 '21 at 09:20

1 Answers1

2

A CString is a Microsoft implementation wrapping a character array into a C++ object to allow simpler processing.

But, swscanf is a good old C function that knows nothing about what a CString is: it just expects its arguments to be large enough to accept the decoded values. It should never be directly passed a CString.

The correct way would be:

...
#include <cstring>
...
while (fgetws(line, 1024, pFile))
{
    line[wcscspn(line, L"\n")] = 0;  // remove an optional end of line
    CString cstr(line);
    cstr_set.insert(cstr);
}
...
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • I would like to know why this problem occurs when use `CString` directly in `swscanf`. – secuman Sep 23 '21 at 09:23
  • @secuman: because `%s` in a scanf expects a char array large enough to hold the decoded string and that a CString is not that. So you just invoke Undefined Behaviour... – Serge Ballesta Sep 23 '21 at 09:37
  • You are right. When I add `cstr.GetBufferSetLength(1024);` to `swscanf`'s above the problem is solved. – secuman Sep 23 '21 at 09:48