Problem to the codes

Hi,
Previously, I used Vector but I've changed it to use set instead below. How to correct these
// 
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <string>
#include <string.h>
#include <fstream>
#include <ctype.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <Windows.h>

using namespace std;
//

struct nameval
{
	//
	char fld_nm[100];
	wchar_t fld_nm_uni[100]; //Store Unicode name
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
	int fld_len;
	int fld_val;
};
nameval binrec;
//
//
//
//
//
//
//
bool LessComp(const nameval& a1, const nameval& a2)
{
  if(strcmp(a1.fld_nm, a2.fld_nm) < 0) return true;
  if(strcmp(a1.fld_nm, a2.fld_nm) > 0) return false;
  if(a1.fld_val < a2.fld_val) return true;
  return false;
}

int _tmain(int argc,_TCHAR* argv[])
{
	if (argc < 3)
	{
		return ERROR;
	}
	if (INVALID_FILE_ATTRIBUTES == GetFileAttributes( argv[1] ))
	{
		cout << "File does not exist!\n";
		exit(EXIT_FAILURE);
	}
    std::set<nameval> records;
	std::set<nameval>::iterator iter;
    //
	std::ifstream istrm(argv[1], std::ios::binary | std::ios::in );
	//

	//
	while (istrm.read((char*)&binrec, sizeof(nameval)))
	//
	//
	{
		//
		//
		
		//
		//
		//
		//
		//
		//
		records.insert(binrec);
	}
	if (!istrm.eof())
	{
		cout << "Error reading text/binary file!\n";
		exit(EXIT_FAILURE);
	}

	//
	//
	//
	//
	//
	
	//
	strcpy(binrec.fld_nm,argv[2]);
	//
	//
	binrec.fld_val=::atoi(argv[3]);
	//
	//
	
	iter = lower_bound(records.begin(), records.end(),
			binrec, LessComp);
	//

	if(iter != records.end()
	  && (!LessComp(*iter, binrec) && !LessComp(binrec, *iter)))
	//
	//
	  {
		  cout << "\nFound it!\n";
		  cout << "(From vector record: " << iter->fld_nm
			  << ' ' << iter->fld_val << ")\n";
	  }
	else cout << "\nDidn't find it!\n";

	//

	//
    return 0;
}

Open in new window


due to these errors?
1>------ Rebuild All started: Project: ProA, Configuration: Release x64 ------
1>  stdafx.cpp
1>  ProA.cpp
1>ProA.cpp(98): error C2664: 'strcpy' : cannot convert parameter 2 from '_TCHAR *' to 'const char *'
1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>ProA.cpp(101): error C2664: 'atoi' : cannot convert parameter 1 from '_TCHAR *' to 'const char *'
1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

Open in new window

LVL 12
HuaMin ChenProblem resolverAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ZoppoCommented:
Hi HuaMinChen,

you can't change the value of an item in a set. And this is good, because the values define the order in which i.e. iterating through the set is done.

IMO the only way is to remove the old item and insert a new item.

Hope that helps,

ZOPPO
0
ZoppoCommented:
Sorry, please ignore my last comment, I wrote it without understanding the messages ...
0
ZoppoCommented:
Do you use UNICODE in you program?
0
Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

jkrCommented:
The simple solution (if applicable); Open your project's Properties (ALT+F7), select "Configuration Properties|General" and change "Character Set" to "Use Multi-Byte Character Set".
0
HuaMin ChenProblem resolverAuthor Commented:
Many thanks all.
Phoffric,
this is not a homework, while I expect to see the way to search one binary file is fine.

JKR,
I've changed "Character Set" to "Use Multi-Byte Character Set" and then have re-built the project. But why do I get this
C:\ProA\x64\Release>ProA "c:\dp4\flout.bin" "yyy[LEJ[dndxQDp@tcaQ" 1128525

Didn't find it!

Open in new window


while the relevant record does exist within the file, and here is the binary file
https://dl.dropboxusercontent.com/u/40211031/flout.zip
0
HuaMin ChenProblem resolverAuthor Commented:
Many thanks to you. Is there any other help?
0
HuaMin ChenProblem resolverAuthor Commented:
Yes, I have unicode to the record.
0
jkrCommented:
If you are in fact using UNICODE, my advice was 'non applicable'. Instead, you should convert all functions in your code that deal with string to their 'TCHAR' equivalents or directly go for the UNICODE versions if you aready know that you onlx will use these. Which would be
1>------ Rebuild All started: Project: ProA, Configuration: Release x64 ------
1>  stdafx.cpp
1>  ProA.cpp
1>ProA.cpp(98): error C2664: 'strcpy' : cannot convert parameter 2 from '_TCHAR *' to 'const char *'

>> use '_tcscpy()' or 'wcscpy()' here

1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>ProA.cpp(101): error C2664: 'atoi' : cannot convert parameter 1 from '_TCHAR *' to 'const char *'
1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

>> use 'tcstoi()' or 'wcstoi()' here

Open in new window

0
HuaMin ChenProblem resolverAuthor Commented:
Sorry, how to correct these
	_tcscpy(binrec.fld_nm,argv[2]);
	//
	//
	binrec.fld_val=::tcstoi(argv[3]);
	...

Open in new window


due to these
1>ProA.cpp(99): error C2664: 'wcscpy' : cannot convert parameter 1 from 'char [100]' to 'wchar_t *'
1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>ProA.cpp(102): error C2039: 'tcstoi' : is not a member of '`global namespace''
1>ProA.cpp(102): error C3861: 'tcstoi': identifier not found

Open in new window

0
sarabandeCommented:
in a Unicode project, type TCHAR is defined as wchar_t. because of that you can't easily copy TCHAR to char type (as the binrec.fld_nm is) but you have to convert from wide char to multi-byte char instead.

so your code should be like:

wcscpy(binrec.fld_nm_uni, argv[2]);

wcstombs(binrec.fld_nm, argv[2], sizeof(binrec.fld_nm)-1);

Open in new window


note, those statements are independent from the container you were using.

alternatively you may check for class _bstr_t which can handle wide char's and ansi char's and also provide easy-to-use conversions from one to another.

Sara
0
sarabandeCommented:
since your characters are ansi char by design, the conversion to and from wide char is trivial, because the ansi char set is part of the utf16 layer 1 (called Unicode by MS) and the coding for each character is the same. the only difference is that the wide char has a zero byte additional to the character byte.

if your goal is to handle as much names as possible in memory, you should omit the unicode string in your structure, because you easily can do the conversion for both directions on the fly if necessary. you also may think about using a dynamic char buffer for your names if most names are much less than 100 characters. if you want to go this way you may have two structures, one for keeping a name in memory (in the nodes of a std::set) and one for writing to a file. only the second would have 100 bytes for name while the first one would use a pointer to char what could spare much space.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Many thanks Sara.
I only expect to search against fld_nm, using argv[2]. do I really need to have these?

wcscpy(binrec.fld_nm_uni, argv[2]);

wcstombs(binrec.fld_nm, argv[2], sizeof(binrec.fld_nm)-1);

Open in new window

0
sarabandeCommented:
for your purpose the wcstombs statement is sufficient. you should add a length and validity check for the argv[2] argument like

if (argc <= 2 || wcslen(argv[2]) < sizeof(binrec.fld_nm))
    return -1; // error 
wcstombs(binrec.fld_nm, argv[2], sizeof(binrec.fld_nm)-1);

Open in new window


as told the unicode string is redundant. you should remove it from structure and add a function which converts the name string to unicode:

struct nameval
{
     ....
     char fld_nm[100];
     ....
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm))); 
     }

Open in new window


with the function you always can fill a wchar_t array with the unicode string if needed,  

Sara
0
sarabandeCommented:
I only expect to search against fld_nm
std::set has a find member function which can used for search.

if (records.find(binrec) != records.end())
      std::cout << binrec.fld_nm << " found" << std::endl;

Open in new window


however, as your key already contains both the name and the val, the query for existence is not very useful. since you created the file from a set which don't has duplicates, you won't get a match when reading it back from file.

you may think of removing the val from key (in operator< and in LessComp). then your query would be for the name only and the val would be the result of such a query.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Many thanks Sara.
in your codes

struct nameval
{
     ....
     char fld_nm[100];
     ....
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm))); 
     }
     ...

Open in new window

   
do you mean I can put whatever unicode into "nm_uni[]" instead of having this

wchar_t fld_nm_uni[100];

Open in new window

?
0
HuaMin ChenProblem resolverAuthor Commented:
And how to correct this

binrec.fld_val=::tcstoi(argv[3]);

Open in new window


due to these?
1>ProA.cpp(102): error C2039: 'tcstoi' : is not a member of '`global namespace''
1>ProA.cpp(102): error C3861: 'tcstoi': identifier not found

Open in new window

0
sarabandeCommented:
you mean I can put whatever unicode into "nm_uni[]" instead of having this
no, it is not a "whatever" unicode but the name from fld_nm which was converted from char to wchar_t.

i wouldn't recommend to using the t-functions like tcstol if you don't want to switch your program from unicode to ansi. that doesn't make so much sense as it seems that you want to support both and not the one or the other.

therefore you may use the w-functions to handle wchar_t strings. the easiest function to convert wchar_t to int is the function wtoi.

int val = wtoi(argv[3]);

Open in new window

which would succeed for all input as it simply tries to convert numeric letters from left to right. if the input is not a number the result would be 0. use the wcstol  (the last character is a small 'L') function if you want to check for valid input. don't forget to check that the argv[3] is valid (the argc must be at least 4).

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Many thanks Sara.
when running the re-built project that is having these
// 
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <string>
#include <string.h>
#include <fstream>
#include <ctype.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <Windows.h>

using namespace std;

struct nameval
{
	char fld_nm[100];
	wchar_t fld_nm_uni[100]; 
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm))); 
     }     
	bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
	int fld_len;
	int fld_val;
};
nameval binrec;
bool LessComp(const nameval& a1, const nameval& a2)
{
  if(strcmp(a1.fld_nm, a2.fld_nm) < 0) return true;
  if(strcmp(a1.fld_nm, a2.fld_nm) > 0) return false;
  if(a1.fld_val < a2.fld_val) return true;
  return false;
}

int _tmain(int argc,_TCHAR* argv[])
{
	if (argc < 3)
	{
		return ERROR;
	}
	if (INVALID_FILE_ATTRIBUTES == GetFileAttributes( argv[1] ))
	{
		cout << "File does not exist!\n";
		exit(EXIT_FAILURE);
	}
    std::set<nameval> records;
	std::set<nameval>::iterator iter;
	std::ifstream istrm(argv[1], std::ios::binary | std::ios::in );

	while (istrm.read((char*)&binrec, sizeof(nameval)))
	{
		records.insert(binrec);
	}
	if (!istrm.eof())
	{
		cout << "Error reading text/binary file!\n";
		exit(EXIT_FAILURE);
	}

	if (argc <= 2 || wcslen(argv[2]) < sizeof(binrec.fld_nm))
	  {
		  cout << "\nProblem with 2nd argument!\n";
	  }
	wcstombs(binrec.fld_nm, argv[2], sizeof(binrec.fld_nm)-1);
	binrec.fld_val=_wtoi(argv[3]);
	
	iter = lower_bound(records.begin(), records.end(),
			binrec, LessComp);

	if(iter != records.end()
	  && (!LessComp(*iter, binrec) && !LessComp(binrec, *iter)))
	  {
		  cout << "\nFound it!\n";
		  cout << "(From vector record: " << iter->fld_nm
			  << ' ' << iter->fld_val << ")\n";
	  }
	else cout << "\nDidn't find it!\n";

    return 0;
}

Open in new window


why do I get this

C:\ProA\x64\Release>ProA "c:\dp4\flout.bin" "yyy[LEJ[dndxQDp@tcaQ" 1128525

Problem with 2nd argument!

Didn't find it!

Open in new window


to search against this file?
https://dl.dropboxusercontent.com/u/40211031/flout.zip
0
sarabandeCommented:
if (argc <= 2 || wcslen(argv[2]) < sizeof(binrec.fld_nm))
one of the two conditions is wrong. set a breakpoint to the line and debug.

I would assume the argc == 1 what would indicate that you started the program from visual studio ide and didn't pass any arguments,

if I am right you have to add the arguments via project properties - configuration properties - debugging - command arguments.

alternatively open a command window and navigate to the debug folder of your project. start the exe from there and pass the arguments needed.

note, command line arguments to perform a query for one single key where you have to load a million keys into a set before, is not  a good design. you better ask for the key to search in the main function by using std::getline. if you put all this into a loop after you loaded the names, you could repeat querying until you got an input to stop, for example 'quit'.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Sara,
Big appreciations to your help!

alternatively open a command window and navigate to the debug folder of your project. start the exe from there and pass the arguments needed.
I now do directly run the generated .exe file, within Command prompt

note, command line arguments to perform a query for one single key where you have to load a million keys into a set before, is not  a good design. you better ask for the key to search in the main function by using std::getline. if you put all this into a loop after you loaded the names, you could repeat querying until you got an input to stop, for example 'quit'.

I am passing parameters to the .exe file, to search against the relevant binary file. Is it really one problem to such way?
0
sarabandeCommented:
if the goal is to have a program which could used in a script or batch to check for existing names, command line arguments could be a valid means. however, if so, it would be a much better idea to do a binary search at the file rather than reading all entries to memory. that is not very difficult since your records are fixed-size.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Thanks a lot to you.

if so, it would be a much better idea to do a binary search at the file rather than reading all entries to memory. that is not very difficult since your records are fixed-size.

Can I have the relevant details to the way?
0
sarabandeCommented:
- get file status by using stat function. then you can calculate the number of records

#include <sys/stat.h>
...
struct stat fs = { 0 };
int ret = stat(strFilePath.c_str(), &fs); // iret must be 0 or error
int numRecords = (int)(fs.st_size/sizeof(nameval));

Open in new window


- open the file in binary mode:  
- define integers nbegin = 0, nend=numRecords-1 and nmid= (nbegin + nend)/2
- start a while loop with condition (nbegin <= nend)
- read record with index nmid by

nameval rec = { 0 };
ifile.seekg(nmid* sizeof(nameval));
ifile.read((char*)&rec, sizeof(nameval)); 

Open in new window


- if search_name < rec.fld_nm  :  nend = nmid-1 and nmid = (nbegin+nend)/2
- else if search_name > rec.fld_nm  :  nbegin = nmid+1 and nmid = (nbegin+nend)/2
- else: you have a match and break the while loop with match.
- if no match after loop, the searched name was not found.
- close the file.

note, you must add error handling for the above code snippets.

the advantages of the solution are:

- for 8 million names you would read a maximum of 23 records to find out whether it is a match or not cause 2^23 is greater than 8,000,000
- you don't have any memory issues

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Many many thanks Sara.
BTW, after I've opened the file in binary mode, is there any quick way to get known how many records inside it?
0
HuaMin ChenProblem resolverAuthor Commented:
Or I still need to count one by one within that?
0
sarabandeCommented:
is there any quick way to get known how many records inside it?
yes, I posted the code. see above where I used struct stat and function stat.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Thanks a lot. how to adjust this

std::ifstream istrm(argv[1], std::ios::binary | std::ios::in );

Open in new window


to further use seekg against the file opened in binary mode?
0
sarabandeCommented:
it is ok. you can call  istrm.seekg(position) and position is record_index * sizeof(record).

see sample code above.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Sorry, how to correct the last line below

struct nameval
{
	char fld_nm[100];
	...
};

int _tmain(int argc,_TCHAR* argv[])
{
	...
		nameval rec = { 0 };
		...
	while (nbegin<=nend && nstop!=-1)
	{
		nmid= (nbegin + nend)/2;

		nameval rec = { 0 };
		istrm.seekg(nmid* sizeof(nameval));
		istrm.read((char*)&rec, sizeof(nameval)); 

		if (argv[2]<rec.fld_nm)
		{
		   ...

Open in new window


due to these?
1>ReadBinaryFile.cpp(117): error C2446: '<' : no conversion from 'char *' to '_TCHAR *'
1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>ReadBinaryFile.cpp(117): error C2440: '<' : cannot convert from 'char [100]' to '_TCHAR *'
		   

Open in new window

0
sarabandeCommented:
if (argv[2]<rec.fld_nm)
the statement has two errors: one is that pointers to char or wchar_t cannot be compared with < (what would compare the addresses) but you would need to use strcmp or wcscmp.
the second is that argv[2] is wchar_t pointer (because your project is Unicode) while rec.fld_nm is a char pointer.

use the following statement to correct both issues:

if (_bstr_t(argv[2]) < _bstr_t(rec.fld_nm))

Open in new window


the class _bstr_t can take both wide and ansi strings and has operator< defined.

of course you also could (should) define a local variable

_bstr_t search_name = argv[2];

Open in new window


which then could be used in the if statement.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
sorry, using these codes

//
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <sys/stat.h>
#include <string>
#include <string.h>
#include <fstream>
#include <atlbase.h>
#include <ctype.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <Windows.h>

using namespace std;

struct stat fs = { 0 };
int ret; // iret must be 0 or error
int numRecords;

struct nameval
{
	char fld_nm[100];
	wchar_t fld_nm_uni[100];
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm))); 
     }     
	bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
	int fld_len;
	int fld_val;
};
nameval binrec;
bool LessComp(const nameval& a1, const nameval& a2)
{
  if(strcmp(a1.fld_nm, a2.fld_nm) < 0) return true;
  if(strcmp(a1.fld_nm, a2.fld_nm) > 0) return false;
  if(a1.fld_val < a2.fld_val) return true;
  return false;
}

int _tmain(int argc,_TCHAR* argv[])
{
	if (argc < 3)
	{
		return ERROR;
	}
	if (INVALID_FILE_ATTRIBUTES == GetFileAttributes( argv[1] ))
	{
		cout << "File does not exist!\n";
		exit(EXIT_FAILURE);
	}
    std::set<nameval> records;
	std::set<nameval>::iterator iter;
	std::ifstream istrm(argv[1], std::ios::binary | std::ios::in );

	ret = stat(CT2A(argv[1]), &fs);
	numRecords = (int)(fs.st_size/sizeof(nameval));

	int nbegin=0;
	int nend=numRecords-1;
	int nmid;
	int nstop=0;
	char nm_got[100];
	int val_got;

	while (nbegin<=nend && nstop!=-1)
	{
		nmid= (nbegin + nend)/2;

		nameval rec = { 0 };
		istrm.seekg(nmid* sizeof(nameval));
		istrm.read((char*)&rec, sizeof(nameval)); 

		if (CT2A(argv[2])<rec.fld_nm)
		{
			nend=nmid-1;
			nmid = (nbegin+nend)/2;
		}
		else
		{
			if (CT2A(argv[2])>rec.fld_nm)
			{
				nend=nmid+1;
				nmid = (nbegin+nend)/2;
			}
			else
			{
				nstop=-1;
				strcpy(rec.fld_nm,nm_got);
				val_got=rec.fld_val;
			}
		}
	}
	binrec.fld_val=_wtoi(argv[3]);
	if (nstop==-1)
	  {
		  cout << "\nFound it!\n";
	  }
	else cout << "\nDidn't find it!\n";

    return 0;
}

Open in new window


why do I get this
C:\ReadBinaryFile\x64\Release>ReadBinaryFile "c:\dp4\flout.bin" "yyy[LEJ[dndxQDp@tcaQ" 1128525

Didn't find it!

Open in new window


to search against this file

https://dl.dropboxusercontent.com/u/40211031/flout.zip
0
sarabandeCommented:
if (CT2A(argv[2])<rec.fld_nm)
the CT2A converts a LPCTSTR to a LPCSTR. in your case it is from 'const wchar_t *' to 'const char *'. the mistake is that by this you compare pointer values and not strings and therefore it never could  give a match (cause the pointer returned by CT2A is always different to pointers of rec.fld_nm).

I told you to using _bstr_t class which has an overloaded operator< and also explained why you should do so. it is a multiple time that I have to point to my own posted code which you should read more thoroughly.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
sorry, the reason that I use "CT2A", is due to that I encounter the problem mentioned, to the line below.

			if (_bstr_t(argv[2])>_bstr_t(rec.fld_nm))
			{
				...

1>ReadBinaryFile.cpp(125): error C3861: '_bstr_t': identifier not found
1>ReadBinaryFile.cpp(125): error C3861: '_bstr_t': identifier not found

Open in new window

0
sarabandeCommented:
the _bstr_t type is available by including <comutil.h>. it also is available if you include stdafx.h (as first include statement)but still NOT using precompiled header option.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Here are those included
#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <comutil.h>
#include <sys/stat.h>
#include <string>
#include <string.h>
#include <fstream>
#include <atlbase.h>
#include <ctype.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <Windows.h>
...

Open in new window

but I still get this
1>ReadBinaryFile.obj : error LNK2001: unresolved external symbol "void __cdecl _com_issue_error(long)" (?_com_issue_error@@YAXJ@Z)
1>ReadBinaryFile.obj : error LNK2001: unresolved external symbol "wchar_t * __cdecl _com_util::ConvertStringToBSTR(char const *)" (?ConvertStringToBSTR@_com_util@@YAPEA_WPEBD@Z)

Open in new window

0
sarabandeCommented:
nmid = (nbegin+nend)/2;
the statement at begin of the while loop is sufficient. you don't need to repeat the statements.

while (nbegin<=nend && nstop!=-1)
you could omit the 'nstop' if you use 'break;' statement if the key was found. if not found the condition (nbegin<=nend) necessarily will go false when nmid == nbegin and no match.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Can I still nstop there? And the current problem is not due to nbegin/nend, right?
0
HuaMin ChenProblem resolverAuthor Commented:
I mean to still use nstop, can I? Thanks
0
sarabandeCommented:
these linker errors are probably due to the x64 environment.

you could go back to win32 for the query program as you don't need so much memory anymore. or you use the following string class

class SimpleString
{
      char * m_psz;
public:
      SimpleString(const char * psz)
      { 
           m_psz = new char[strlen(psz)+1]; strcpy(m_psz, psz); 
      }
      SimpleString(const wchar_t * pwsz) 
     { 
          m_psz = new char[2*wcslen(pwsz)]; 
          wcstombs(m_psz, pwsz, 2*wcslen(pwsz)); 
     }
     ~SimpleString() { delete []m_psz; }
     bool operator<(const SimpleString & s) const
     {
          return (strcmp(m_psz, s.m_psz) < 0);
     }
};

Open in new window


use SimpleString instead of _bstr_t when comparing the strings.

....
SimpleString search_name = argv[2];  
while (nbegin <= nend)
{
     nmid = (nbegin+nend)/2;
     SimpleString name = rec.fld_nm;
     if (search_name < name)
     {
           nend = nmid-1;
           continue;
     }
    else if (name < search_name)
    {
         nbegin = nmid+1;
         continue;
    }
    std::cout << "name found" << std::endl;
    break;
}

Open in new window


Sara
0
sarabandeCommented:
see my last code sample. the nstop is not needed. but you can use it. it is better coding if you don't but it is not a mistake. however, you should make it a bool variable as it has only two states.

if you use SimpleString I only implemented operator< but not operator> . so you need to switch the names for comparison of 'greater-than' (or implement operator> yourself).

note, alternatively to SimpleString or _bstr_t you can convert the argv[2] to a local char array by using wcstombs. then compare by calling strcmp.

char szArgv2[512] = { 0 };
wcstombs(szArgv2, argv[2], sizeof(szArgv2));

Open in new window


Sara
0
HuaMin ChenProblem resolverAuthor Commented:
sorry Sara, I get nothing returned for long while when running this
C:\ReadBinaryFile\x64\Release>ReadBinaryFile "c:\dp4\flout.bin" "yyy[LEJ[dndxQDp@tcaQ" 1128525

Open in new window


with the project having these
// 
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <comutil.h>
#include <sys/stat.h>
#include <string>
#include <string.h>
#include <fstream>
#include <atlbase.h>
#include <ctype.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <Windows.h>

using namespace std;

struct stat fs = { 0 };
int ret; // iret must be 0 or error
int numRecords;

struct nameval
{
	char fld_nm[100];
	wchar_t fld_nm_uni[100];
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm))); 
     }     
	bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
	int fld_len;
	int fld_val;
};
nameval binrec;
bool LessComp(const nameval& a1, const nameval& a2)
{
  if(strcmp(a1.fld_nm, a2.fld_nm) < 0) return true;
  if(strcmp(a1.fld_nm, a2.fld_nm) > 0) return false;
  if(a1.fld_val < a2.fld_val) return true;
  return false;
}

int _tmain(int argc,_TCHAR* argv[])
{
	if (argc < 3)
	{
		return ERROR;
	}
	if (INVALID_FILE_ATTRIBUTES == GetFileAttributes( argv[1] ))
	{
		cout << "File does not exist!\n";
		exit(EXIT_FAILURE);
	}
    std::set<nameval> records;
	std::set<nameval>::iterator iter;
	std::ifstream istrm(argv[1], std::ios::binary | std::ios::in );

	ret = stat(CT2A(argv[1]), &fs);
	numRecords = (int)(fs.st_size/sizeof(nameval));

	int nbegin=0;
	int nend=numRecords-1;
	int nmid;
	int nstop=0;
	char nm_got[100];
	int val_got;

	char szArgv2[512] = { 0 };
	wcstombs(szArgv2, argv[2], sizeof(szArgv2));
	while (nbegin<=nend && nstop!=-1)
	{
		nmid= (nbegin + nend)/2;

		nameval rec = { 0 };
		istrm.seekg(nmid* sizeof(nameval));
		istrm.read((char*)&rec, sizeof(nameval)); 

		wcstombs(binrec.fld_nm, argv[2], sizeof(binrec.fld_nm)-1);

		if (strcmp(szArgv2,rec.fld_nm)<0)
		{
			nend=nmid-1;
			nmid = (nbegin+nend)/2;
		}
		else
		{
			if (strcmp(szArgv2,rec.fld_nm)>0)
			{
				nend=nmid+1;
				nmid = (nbegin+nend)/2;
			}
			else
			{
				nstop=-1;
				strcpy(rec.fld_nm,nm_got);
				val_got=rec.fld_val;
			}
		}
	}
	
	binrec.fld_val=_wtoi(argv[3]);
	
	if (nstop==-1)
	  {
		  cout << "\nFound it!\n";
	  }
	else cout << "\nDidn't find it!\n";

    return 0;
}

Open in new window

0
sarabandeCommented:
wcstombs(binrec.fld_nm, argv[2], sizeof(binrec.fld_nm)-1);
this statement must be removed. the binrec is not be used in the while loop


if (strcmp(szArgv2,rec.fld_nm)>0)
{
    nend=nmid+1;
    nmid = (nbegin+nend)/2;
}

because of the 'nend=nmid+1;' you have an infinite loop.

the correct statement is 'nbegin = nmid+1;'

a binary search divides the whole sorted array into two parts and analyzes the middle element. if the search name is less than the middle name, the new end is one less than the middle. if the search name is greater than the middle name the new begin is one greater than the middle. doing so the new range is always half of the old range size and the loop will end if the range width is 0 and no match.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
sorry, I still get
C:\ReadBinaryFile\x64\Release>ReadBinaryFile "c:\dp4\flout.bin" "yyy[LEJ[dndxQDp@tcaQ" 1128525

Didn't find it!

Open in new window


with these codes
// 
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <comutil.h>
#include <sys/stat.h>
#include <string>
#include <string.h>
#include <fstream>
#include <atlbase.h>
#include <ctype.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <Windows.h>

using namespace std;

struct stat fs = { 0 };
int ret; // iret must be 0 or error
int numRecords;

struct nameval
{
	char fld_nm[100];
	wchar_t fld_nm_uni[100];
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm))); 
     }     
	bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
	int fld_len;
	int fld_val;
};
nameval binrec;
bool LessComp(const nameval& a1, const nameval& a2)
{
  if(strcmp(a1.fld_nm, a2.fld_nm) < 0) return true;
  if(strcmp(a1.fld_nm, a2.fld_nm) > 0) return false;
  if(a1.fld_val < a2.fld_val) return true;
  return false;
}

int _tmain(int argc,_TCHAR* argv[])
{
	if (argc < 3)
	{
		return ERROR;
	}
	if (INVALID_FILE_ATTRIBUTES == GetFileAttributes( argv[1] ))
	{
		cout << "File does not exist!\n";
		exit(EXIT_FAILURE);
	}
    std::set<nameval> records;
	std::set<nameval>::iterator iter;
	std::ifstream istrm(argv[1], std::ios::binary | std::ios::in );

	ret = stat(CT2A(argv[1]), &fs);
	numRecords = (int)(fs.st_size/sizeof(nameval));

	int nbegin=0;
	int nend=numRecords-1;
	int nmid;
	int nstop=0;
	char nm_got[100];
	int val_got;
	char szArgv2[512] = { 0 };
	wcstombs(szArgv2, argv[2], sizeof(szArgv2));
	while (nbegin<=nend && nstop!=-1)
	{
		nmid= (nbegin + nend)/2;

		nameval rec = { 0 };
		istrm.seekg(nmid* sizeof(nameval));
		istrm.read((char*)&rec, sizeof(nameval)); 

		if (strcmp(szArgv2,rec.fld_nm)<0)
		{
			nend=nmid-1;
			nmid = (nbegin+nend)/2;
		}
		else
		{
			if (strcmp(szArgv2,rec.fld_nm)>0)
			{
				nbegin=nmid+1;
				nmid = (nbegin+nend)/2;
			}
			else
			{
				nstop=-1;
				strcpy(rec.fld_nm,nm_got);
				val_got=rec.fld_val;
			}
		}
	}
	
	binrec.fld_val=_wtoi(argv[3]);
	if (nstop==-1)
	  {
		  cout << "\nFound it!\n";
		  //cout << "(From vector record: " << iter->fld_nm
			//  << ' ' << iter->fld_val << ")\n";
		  //cout << "(From vector record: " << rec.fld_nm
			//  << ' ' << rec.fld_val << ")\n";
	  }
	else cout << "\nDidn't find it!\n";

    return 0;
}

Open in new window

0
sarabandeCommented:
i loaded the file flout.zip from dropbox and extracted flout.bin. actually the file didn't contain any keys of the kind you would  need for your query.

you should open the file by visual studio and check using hex editor that the names stored are valid.

Sara
0
sarabandeCommented:
can you post the code where you "created" the file with the nameval keys.

it seems to me that this didn't work as expected.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Thanks Sara.

the string should be inside the binary file. which Hex editor do you use to open it?

Here are the codes to generate the binary file.
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <string>
#include <ctype.h>
#include <time.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;

struct nameval
{
	char fld_nm[100];
	wchar_t fld_nm_uni[100];
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
	int fld_len;
	int fld_val;
};
nameval binrec;

int main()
{
    std::set<nameval> records;
    int cnt;
	for (cnt=0;cnt<2000000;cnt++)
	{
		try 
		{
			nameval val={0};
			int j;
			for (j=0;j<20;j++)
			{
				val.fld_nm[j] += (char)(rand () % 58 + 64);
				//val.fld_nm.push_back(rand () % 58 + 64);
			}
		
			wchar_t wbuf[100]={0};
			mbstowcs(wbuf,val.fld_nm,_countof(val.fld_nm));
			wmemcpy(val.fld_nm_uni,wbuf,100);

			val.fld_val=cnt;
			records.insert(val);
		}
		catch (exception& e)
		{
			cout << e.what() << '\n';
		}

	}

	std::ofstream ostrm("c:\\dp4\\flout.bin", std::ios::binary | std::ios::out );
	if (ostrm.is_open())
	{
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			try
			{
				ostrm.write((char *)&it, sizeof(nameval));
			}
			catch (exception& e)
			{
				cout << e.what() << '\n';
			}
		}
	}

	std::wofstream ostrm2("c:\\dp4\\flout.ord", std::ios::out );
	if (ostrm2.is_open())
	{
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			ostrm2 << "\"" << it->fld_nm << "\" " << it->fld_len << ' '  << it->fld_nm_uni << ' '<< it->fld_val << '\0' << '\n';
		}
	}

	return 0;
}

Open in new window

0
sarabandeCommented:
which Hex editor do you use to open it?
if you open the file with visual studio it was shown left side as binary and right side corresponding texts. the flout.bin from drop box deosn't contain text from fld_nm and is much too small.

ostrm.write((char *)&it, sizeof(nameval));
that is wrong. it should be

ostrm.write((char *)&(*it), sizeof(nameval));

Open in new window


an iterator is a pointer or (smart) pointer object. so if you do '&it' it is an address of the iterator and not the address of the nameval object it is pointing to. therefore the ostrm.write is writing some random "garbage" of memory around the iterator's address to file.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Thanks Sara.
I have re-gnerated the file and please see this
https://dl.dropboxusercontent.com/u/40211031/flout.zip

but when I re-run the search like
C:\ReadBinaryFile\x64\Release>ReadBinaryFile "c:\dp4\flout.bin" "yyvkmqvo^UL\lNvul^l\" 1285825

I do get the attached.
t874.png
0
sarabandeCommented:
the program works correct. i debugged it and would have had a match at position 1999973 if the key you passed by commandlinie had been correct. but actually the right key was yyvkmqvo^UL\lNvul^l" and not yyvkmqvo^UL\lNvul^l\. that was some kind of bad luck that the key you searched for, ended with a " (double quote) what was "eaten" by the command interpreter and therefore was not passed to the argv[2] correctly. i would recommend to creating keys only with alphabetical letters to avoid the issue.

val.fld_nm[j] += (char)(rand () % 26 + ((rand()%2)? 65 : 97));

Open in new window

the 1st operand creates numbers from 0 to 25 the 2nd operand is either 'A' or 'a' as base offset.

the crash you encountered doesn't come from while loop but from statement
binrec.fld_val=_wtoi(argv[3]);

Open in new window

which throws access violation if a zero pointer was passed as argument. you definitively should remove the statement which is of no value. moreover, it is highly recommendend that you add an error management whcih checks return values and input parameters before use.

Sara
0
sarabandeCommented:
you may start your program from visual studio by adding

.\flout.bin "yyvkmqvo^UL\lNvul^l""

Open in new window


(note the final duplicate " letter)

to

Configuration properties - debugging - commandline arguments

then set debug breakpoint to any of the three branches where you compare keys and have a hit.

you may open a debug window 'Local' to see the current values. or you open a Watch window via Debug - Window - Watch1 and add variables nbegin, nend, nmid, szArgv2 and rec.fld_nm as the variables to watch for.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Many many thanks Sara.

sorry for that I get this

C:\ReadBinaryFile\x64\Release>ReadBinaryFile "c:\dp4\flout.bin" "zzzuBtgteaKLzjpwTAku" 268284

Didn't find it!

Open in new window


to search against this file
https://dl.dropboxusercontent.com/u/40211031/flout.rar

that is generated by

//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <string>
#include <ctype.h>
#include <time.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;

struct nameval
{
	char fld_nm[100];
	wchar_t fld_nm_uni[100];
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
	int fld_len;
	int fld_val;
};
nameval binrec;

int main()
{
    std::set<nameval> records;
    int cnt;
	for (cnt=0;cnt<10000000;cnt++)
	{
		try 
		{
			nameval val={0};
			int j;
			for (j=0;j<20;j++)
			{
				val.fld_nm[j] += (char)(rand () % 26 + ((rand()%2)? 65 : 97));
			}
		
			wchar_t wbuf[100]={0};
			mbstowcs(wbuf,val.fld_nm,_countof(val.fld_nm));
			wmemcpy(val.fld_nm_uni,wbuf,100);

			val.fld_val=cnt;
			records.insert(val);
		}
		catch (exception& e)
		{
			cout << e.what() << '\n';
		}

	}

	std::ofstream ostrm("c:\\dp4\\flout.bin", std::ios::binary | std::ios::out );
	if (ostrm.is_open())
	{
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			try
			{
				ostrm.write((char *)&(*it), sizeof(nameval));
			}
			catch (exception& e)
			{
				cout << e.what() << '\n';
			}
		}
	}

	std::wofstream ostrm2("c:\\dp4\\flout.ord", std::ios::out );
	if (ostrm2.is_open())
	{
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			ostrm2 << "\"" << it->fld_nm << "\" " << it->fld_len << ' '  << it->fld_nm_uni << ' '<< it->fld_val << '\0' << '\n';
		}
	}

	return 0;
}

Open in new window


while the search process is having these codes
// 
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <comutil.h>
#include <sys/stat.h>
#include <string>
#include <string.h>
#include <fstream>
#include <atlbase.h>
#include <ctype.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <Windows.h>

using namespace std;

struct stat fs = { 0 };
int ret; // iret must be 0 or error
int numRecords;

struct nameval
{
	char fld_nm[100];
	wchar_t fld_nm_uni[100];
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm))); 
     }     
	bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
	int fld_len;
	int fld_val;
};
nameval binrec;
bool LessComp(const nameval& a1, const nameval& a2)
{
  if(strcmp(a1.fld_nm, a2.fld_nm) < 0) return true;
  if(strcmp(a1.fld_nm, a2.fld_nm) > 0) return false;
  if(a1.fld_val < a2.fld_val) return true;
  return false;
}

int _tmain(int argc,_TCHAR* argv[])
{
	if (argc < 3)
	{
		return ERROR;
	}
	if (INVALID_FILE_ATTRIBUTES == GetFileAttributes( argv[1] ))
	{
		cout << "File does not exist!\n";
		exit(EXIT_FAILURE);
	}
    std::set<nameval> records;
	std::set<nameval>::iterator iter;
	std::ifstream istrm(argv[1], std::ios::binary | std::ios::in );

	ret = stat(CT2A(argv[1]), &fs);
	numRecords = (int)(fs.st_size/sizeof(nameval));

	int nbegin=0;
	int nend=numRecords-1;
	int nmid;
	int nstop=0;
	char nm_got[100];
	int val_got;
	char szArgv2[512] = { 0 };
	wcstombs(szArgv2, argv[2], sizeof(szArgv2));
	while (nbegin<=nend && nstop!=-1)
	{
		nmid= (nbegin + nend)/2;

		nameval rec = { 0 };
		istrm.seekg(nmid* sizeof(nameval));
		istrm.read((char*)&rec, sizeof(nameval)); 

		if (strcmp(szArgv2,rec.fld_nm)<0)
		{
			nend=nmid-1;
			nmid = (nbegin+nend)/2;
		}
		else
		{
			if (strcmp(szArgv2,rec.fld_nm)>0)
			{
				nbegin=nmid+1;
				nmid = (nbegin+nend)/2;
			}
			else
			{
				nstop=-1;
				strcpy(rec.fld_nm,nm_got);
				val_got=rec.fld_val;
			}
		}
	}
	binrec.fld_val=_wtoi(argv[3]);
	if (nstop==-1)
	  {
		  cout << "\nFound it!\n";
		  cout << "(From vector record: " << nm_got
			  << ' ' << val_got << ")\n";
	  }
	else cout << "\nDidn't find it!\n";

    return 0;
}

Open in new window

0
sarabandeCommented:
the keys in the file flout.bin are not ordered. any entry at an even index has empty strings. i don't know how you created the file but it is not ok.

did you try to debug?

see below screenshots.

move the flout.bin to the project folder of your query program. then start the program by f5.

Sara
breakpoints.png
debug.png
watch-window.png
0
HuaMin ChenProblem resolverAuthor Commented:
Thanks a lot Sara.
How can I get into the attached screen to further put the relevant parameters?
t874.png
0
sarabandeCommented:
the screen is available via menu 'project - properties'.

or

right-click on the name of your project in the solution tree and choose '<your project> properties'.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
I have the breakpoints like the attached, and I also have put the parameter to project property after I've copied the .bin file to current project folder. but when I press F5, I see nothing happens.
t875.png
0
HuaMin ChenProblem resolverAuthor Commented:
Sorry, please disregard the last question.

I've set the breakpoints as above and have copied the .bin file to

C:\ReadBinaryFile

I also have put the parameters to project property as told by you. when I've selected "Start debugging", I then get these

'ReadBinaryFile.exe': Loaded 'C:\ReadBinaryFile\x64\Release\ReadBinaryFile.exe', Symbols loaded.
'ReadBinaryFile.exe': Loaded 'C:\Windows\System32\ntdll.dll', Cannot find or open the PDB file
'ReadBinaryFile.exe': Loaded 'C:\Windows\System32\kernel32.dll', Cannot find or open the PDB file
'ReadBinaryFile.exe': Loaded 'C:\Windows\System32\KernelBase.dll', Cannot find or open the PDB file
'ReadBinaryFile.exe': Loaded 'C:\Windows\System32\msvcp100.dll', Cannot find or open the PDB file
'ReadBinaryFile.exe': Loaded 'C:\Windows\System32\msvcr100.dll', Cannot find or open the PDB file
The program '[10936] ReadBinaryFile.exe: Native' has exited with code 1 (0x1).
0
sarabandeCommented:
did you copy the file flout.bin to the project folder? the project folder is where the file *.vcxproj resides.

the program runs in the debugger but ended with error 1 what indicates 'file not found'.
you may set a  breakpoint to the line where the status of the argv[1] file was retrieved and step by f10. then hover the mouse above 'ret' variable which would be 0 if the file was found and not 0 (probably 1 or 2) when the file was not found in the current directory.

Sara
0
sarabandeCommented:
you can ignore warnings about missing pdb files for system dlls (if you right-click in outout window you even could suppress those messages).

only the last message is important. it means that your program has exited from main function and returned 1 (what indicates an error). note, the breakpoints were not hit because of the error. you may set a breakpoint at the begin of the main function and step by f10 to see where it fails.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Many thanks Sara.
I copy the .bin file into the folder where the file *.vcxproj resides. But I get empty Watch window below. Any advice?
t877.png
0
HuaMin ChenProblem resolverAuthor Commented:
Please disregard my last reply above. I have the breakpoints to the 1st line inside _tmain, and also have the breakpoints to the 3 places inside the loop. Now it is loop the while loop and do I need to follow that by repeatedly pressing "F10"?
0
HuaMin ChenProblem resolverAuthor Commented:
I keep on press "F10" there until it finishes, but I still get "Didn't find it!" and also have got empty watch window. Please advise. Many thanks.
0
sarabandeCommented:
you can step by f10 or go to next break by f5. for your purpose f5 is ok.

to configure the watch window you simple type the name of the variable to watch in the left column of the watch window (or do drag-and-drop from edit window).

it is rather likely that the program 'didn't find the key' as i already debugged the last file you sent and had the problem that it contained empty records and was not sorted.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Sorry, the .bin file should have been sorted by the name, right? How to enhance the program to capture the records which are causing the problem, if any? thanks
0
sarabandeCommented:
note, the 'else' is not a good place for a breakpoint. use the statements with 'nmid =' and 'nstop =' instead. doing so, you always would know the result of the current comparison: if the search key was less than the current record key, it breaks in the first if block. if the search key was greater it breaks in the second if block and if the key matches (what will not happen unfortunately) it would break at the statement where you set the nstop to -1.

in the watch window you should see both the names to be compared and nbegin, nmid and nend. you will see very well how the binary search converts and that the range becomes more narrow with each iteration. but you also will see that the records you read from file contain wrong data.

Sara
0
sarabandeCommented:
the .bin file should have been sorted by the name, right? How to enhance the program to capture the records which are causing the problem, if any?

there is nothing to enhance in this program, it cannot work if the input file is wrong.

you need to correct the program that created the file.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
doing so, you always would know the result of the current comparison: if the search key was less than the current record key, it breaks in the first if block. if the search key was greater it breaks in the second if block and if the key matches (what will not happen unfortunately) it would break at the statement where you set the nstop to -1.

Hi Sara,
Is there a way to adjust the codes to detect the error case, when reading the file? Thanks a lot
0
sarabandeCommented:
if you look at the variables szArgv2 and rec.fld_nm in the watch window on break, you easily can see that the input file is wrong. the search key is "zzz...", hence the keys to find should be at end of the file, near index 999,999. the first nmid = 499,999 as your letters are out of "ABCD...YZab...xyz" a "middle" key should begin with 'Y' or 'Z' or 'a' or 'b'. But the first rec.fld_nm at 499.999 was like "AAA...." what should one of the lowest indices, if the file was correctly ordered. worse, if you do f5 the next nmid == 749998 what is an even index. for that the rec.nm_val was completely empty (binary zeroes). next name at 874999 again starts with a capital 'A', next name at even index again was empty.

so you don't need new code to detect that the file is corrupt. it is obvious. you have to check the program which created the file why it doesn't work correctly. you can set a breakpoint at the statement where the names are written to file. and you easily should see that the names are not ordered and that any second name was empty.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Many thanks Sara.
Before this, I showed the relevant codes to generate .bin file. can you please advise how I can see if there is problem within the current .bin file I put in above? which Hex editor do you use to view it?
0
HuaMin ChenProblem resolverAuthor Commented:
Hi Sara,
If there is really one problem within .bin file, like what you've mentioned, is there any way to avoid this, within the project (shown currently in above), that is generating the .bin file? Thanks a lot.
0
sarabandeCommented:
the file which had 2 million entries was ok beside it included some special characters like " in the names which makes problems when passing them via command line arguments.

the last file posted to drop box has 10 million entries and was not sorted and every second entry seems to be empty. I can't open it by visual studio because it is too big. but as told above, you could use the query program to read arbitrary records from file (simply set the nmid to a new index before read) and examine the rec variable using the debugger.

Before this, I showed the relevant codes to generate .bin file.
did you? the file which worked had 2 million entries. the file not working has 10 million entries. and I think that you might have got problems by creating a 10,000,000 entries file using std::set even when using a 64-bit program. if I am wrong, you may nevertheless create a smaller bin file and try your query with that. a smaller bin file easily can be opened in visual studio and can examined whether it was correct or not.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Hi Sara,
I really appreciate a lot to your help!

Here
https://dl.dropboxusercontent.com/u/40211031/ProB.cpp

are the codes that generate the current .bin file. could you please advise how to ensure the current codes would not generate any problematic records/lines? thanks a lot
0
HuaMin ChenProblem resolverAuthor Commented:
Hi Sara,
Here are the codes used to generate the current .bin file.
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <string>
#include <ctype.h>
#include <time.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;

struct nameval
{
	char fld_nm[100];
	wchar_t fld_nm_uni[100];
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
	int fld_len;
	int fld_val;
};
nameval binrec;

int main()
{
    std::set<nameval> records;
    int cnt;
	for (cnt=0;cnt<10000000;cnt++)
	{
		try 
		{
			nameval val={0};
			int j;
			for (j=0;j<20;j++)
			{
				val.fld_nm[j] += (char)(rand () % 26 + ((rand()%2)? 65 : 97));
			}
		
			wchar_t wbuf[100]={0};
			mbstowcs(wbuf,val.fld_nm,_countof(val.fld_nm));
			wmemcpy(val.fld_nm_uni,wbuf,100);

			val.fld_val=cnt;
			records.insert(val);
		}
		catch (exception& e)
		{
			cout << e.what() << '\n';
		}

	}

	std::ofstream ostrm("c:\\dp4\\flout.bin", std::ios::binary | std::ios::out );
	if (ostrm.is_open())
	{
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			try
			{
				ostrm.write((char *)&(*it), sizeof(nameval));
			}
			catch (exception& e)
			{
				cout << e.what() << '\n';
			}
		}
	}

	std::wofstream ostrm2("c:\\dp4\\flout.ord", std::ios::out );
	if (ostrm2.is_open())
	{
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			ostrm2 << "\"" << it->fld_nm << "\" " << it->fld_len << ' '  << it->fld_nm_uni << ' '<< it->fld_val << '\0' << '\n';
		}
	}

 	system("pause>null");

	return 0;
}

Open in new window

0
HuaMin ChenProblem resolverAuthor Commented:
thanks Phoffric.
0
sarabandeCommented:
I used your codes and set the number of record to 1000. it worked as expected.

I made two changes: I built both programs as 32-bit projects (because I don't have a working x64 environment currently) and I changed the second program to using multi-byte character set.

int main(int argc, char* argv[])
{
    if (argc < 3)
    {
        return ERROR;
    }
    std::set<nameval> records;
    std::set<nameval>::iterator iter;
    std::ifstream istrm(argv[1], std::ios::binary | std::ios::in );

    ret = stat(argv[1], &fs);
    if (ret != 0)
    {
        cout << "File does not exist!\n";
        exit(EXIT_FAILURE);
    }
    numRecords = (int)(fs.st_size/sizeof(nameval));

    int nbegin=0;
    int nend=numRecords-1;
    int nmid;
    int nstop=0;
    char nm_got[100];
    int val_got;
    char szArgv2[512] = { 0 };
    strcpy_s(szArgv2, sizeof(szArgv2), argv[2]);
    while (nbegin<=nend && nstop!=-1)
    {
        nmid= (nbegin + nend)/2;

        nameval rec = { 0 };
        istrm.seekg(nmid* sizeof(nameval));
        istrm.read((char*)&rec, sizeof(nameval)); 

        if (strcmp(szArgv2,rec.fld_nm)<0)
        {
            nend=nmid-1;
            nmid = (nbegin+nend)/2;
        }
        else
        {
            if (strcmp(szArgv2,rec.fld_nm)>0)
            {
                nbegin=nmid+1;
                nmid = (nbegin+nend)/2;
            }
            else
            {
                nstop=-1;
                strcpy(rec.fld_nm,nm_got);
                val_got=rec.fld_val;
            }
        }
    }
    //binrec.fld_val=_wtoi(argv[3]);
    if (nstop==-1)
    {
        cout << "\nFound it!\n";
        cout << "(From vector record: " << nm_got
            << ' ' << val_got << ")\n";
    }
    else cout << "\nDidn't find it!\n";

    return 0;
}

Open in new window


you may create a new win32 project for the second program as well with the above code yourself since the query program doesn't need much memory. it should work also for your bigger bin files if they were correctly ordered. navigate with the hex editor into the middle of the file and copy one of the names into clipboard.

set the arguments for debugging to "c:\dp4\flout.bin" "aGFvXMrgRCeZQoBwYeoy" where the second should be one of your keys (though it could be very well that your program creates the same keys as mine). you see the key starts with a lower-case 'a' what is in the middle of letters used to generate the names.

set breakpoints to all statements where an error exit may occur. set breakpoints to all statements where nmid was calculated and at end of main. with your x64 program you should also create smaller bin files which could be opened with visual studio and should be correctly ordered.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Thanks Sara.
I see your reply to the other thread of me.
Is there any way to ensure the binary file generated would not have any extra zero byte inside?
0
HuaMin ChenProblem resolverAuthor Commented:
Please omit my last question, to this thread. Thanks a lot.
0
HuaMin ChenProblem resolverAuthor Commented:
Many thanks Sara to your help!

Regarding your comment to the other thread, like

can you search for a key in the file? I don't know the hex editor you used but it should have a find function where you could search for text keys. you also should scroll to different places in the file and check whether the keys are correctly ordered.

I do search the binary file, and can see this string below inside that. (that is also shown on the attached)
zzzuBtgteaKLzjpwTAku
t881.png
0
sarabandeCommented:
I think I have found out what is wrong.

as told in the other thread. the file looks quite ok. can you debug the query program and set a breakpoint to the statement where the numRecords was calculated. for 10,000,000 entries we should have 3,080,000,00 bytes cause the struct size is 308. 3 billion is beyond the maximum int size which is about 2.1 billion. as we used signed int for positions nbegin, nend and nmid, we have a integer overflow at MAX_INT what makes the calculations invalid and is responsible why the program doesn't work.

change int variables numRecords, nbegin, nend, nmid to 'unsigned int'  (what has a maximum of 4 billion) and it should work.

Sara
0
sarabandeCommented:
to make your program safe for higher numbers, you may use size_t instead of int, what is typedef to a 64-bit integer. the seekg also should take size_t as argument.

another thing is that structure you are storing is much too large for the purpose you were using it. actually you only would need 20 bytes for the name and 4 bytes for the val. the Unicode string easily can be generated from fld_nm when needed. the length integer also is redundant as it could be deduced from name.

Sara
0
dbruntonQuid, Me Anxius Sum?Commented:
>>  cause the struct size is 308.

308 or 304?
0
sarabandeCommented:
308

struct nameval
{
	char fld_nm[100];
	wchar_t fld_nm_uni[100];
	int fld_len;
	int fld_val;
};

Open in new window

the member len was not filled.

Sara
0
dbruntonQuid, Me Anxius Sum?Commented:
I was looking at his binary file where it seems that he is using a struct of 304 rather than 308.

Could his ints be 2 bytes long rather than 4?

Thus the struct is 304 bytes.
0
HuaMin ChenProblem resolverAuthor Commented:
Thanks again Sara.

I have adjusted the codes, to use "size_t" for fld_len and fld_val, and to use "unsigned int" for the looping variables. I also have re-generated the .bin file. But when I press F5, within the attached screen, nothing happens. what to press to proceed to the next?
t882.png
0
sarabandeCommented:
Could his ints be 2 bytes long rather than 4?
no. but the 'len' member never was populated. hence all 4 bytes are zero bytes. if you look at the hex screenshots which show 16 bytes per line you see that the begin of the second nameval entry was displaced 4 bytes to the right what is due to 19*16 + 4  == 308. therefore the entry begins at 0x0134 what is 308 decimal.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Sara,
I have been stuck with the way to debug the program. Can you please help?
0
sarabandeCommented:
to use "size_t" for fld_len and fld_val
,
that makes no sense. the length of a name can be stored in a byte as it is less than 100. the fld_val also is maximum 10 million (if you store the index of generation as val) while the maximum int is 2 billion (2.1 * 10^9). your change would increase the sizeof(nameval) by 8 more bytes what might make again troubles when creating the names file. you better would use a nameval structure which only has fld_nm and fld_val as members.

I also have re-generated the .bin file. But when I press F5, within the attached screen, nothing happens.
I have seen that the main function of the generating program ends with system("pause"); if that is still the case, the program waits at end for you typing 'enter' in the console window. you should do that or click at the 'debug end' mini-button of your debug toolbar in visual studio. it is a little blue filled rectangle which shows 'Stop Debugging' if you hover above.

note, if you change the structure you have to change it in both programs. you could create a header file like

// nameval.h
#ifndef NAME_VAL_H
#define NAME_VAL_H

struct nameval
{
     char fld_nm[100];
     int    fld_val;

     int  get_len() { return min(strlen(fld_nm), sizeof(fld_nm); }
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm))); 
     }     
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
};

#endif

Open in new window


you would store the nameval.h in a folder which is same level as the project folders for example

c:\
c:\dp4
c:\dp4\include
c:\dp4\project1
c:\dp4\project2

then, the nameval.h could be included in cpp files of both projects by

// main.cpp
#include "stdafx.h"
...
#include "..\include\nameval.h"
....

Open in new window


of course you have to remove old struct from cpp files if doing so.

Sara
0
sarabandeCommented:
But when I press F5, within the attached screen, nothing happens.
you always should set a breakpoint at begin of main and after opening the file. if you do so and F5 still doesn't seem to have any effect. you may open the task manager and check whether your program isn't still running. if so, you have to kill the process before you could start a new instance with the debugger.

note, when writing 3 GB to a file which dynamically grows, it may last hours even on a fast system. therefore decreasing the structure size would extremely speed-up file generation.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Sorry, I get this

1>c:\dp4\readbinaryfile\readbinaryfile\..\..\include\nameval.h(10): fatal error C1057: unexpected end of file in macro expansion

Open in new window


due to this line

#include "..\..\include\nameval.h"

Open in new window


while "include" resides inside c:\dp4
0
sarabandeCommented:
the header file must start with

#ifndef NAME_VAL_H

Open in new window

and end with

#endif

Open in new window

the error message tells that there is something wrong.

note if you right-click on the include statement, the context menu should show 'Open document ...'. that way you can check whether the include path was correct.

Sara
0
sarabandeCommented:
the #ifndef NAME_VAL_H is necessary to prevent the header from being included twice by the same cpp file. since you have only one header and one cpp file in the project, you don't have to worry about this. but nevertheless it is good practice to always make header files safe this way.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
note if you right-click on the include statement, the context menu should show 'Open document ...'. that way you can check whether the include path was correct.

Thanks a lot. when I right-click the include line and then choose "Open document ...", I am able to open the .h file. How to identify the reason of the problem?
0
sarabandeCommented:
ok. that means the include path is ok.

the error says that when expanding the cpp file by including the header file, the file end (of the cpp file ) could no longer detected. that means there is an open parentheses ( [ or { in the header but no closing )  ] or }. or an #if... was not correctly closed by a corresponding #endif.

the latter is much likely the reason for your error.

please post the complete header file (select all by CTRL+A) and alos the complete cpp file where you got the compiler error. please put both the contents between code tags.

Sara
0
sarabandeCommented:
did you have precompiled header option switched on or off for your project? you can see it in the c++ properties.

if switched on, all further include statements must be placed below stdafx.h (what is recommended in any case).

Sara
0
sarabandeCommented:
int  get_len() { return min(strlen(fld_nm), sizeof(fld_nm); }
I found the pulprit. in the statement there is a closing ) missing.

change it to

int  get_len() { return min(strlen(fld_nm), sizeof(fld_nm) ) ; }

Open in new window


Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Here is .h file
// nameval.h
#ifndef NAME_VAL_H
#define NAME_VAL_H

struct nameval
{
     char fld_nm[100];
     int    fld_val;

     int  get_len() { return min(strlen(fld_nm), sizeof(fld_nm); }
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm))); 
     }     
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
};

#endif

Open in new window


and here are the codes to do the search
// 
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <comutil.h>
#include <sys/stat.h>
#include <string>
#include <string.h>
#include <fstream>
#include <atlbase.h>
#include <ctype.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include "..\..\include\nameval.h"
#include <iomanip>
#include <Windows.h>

using namespace std;

struct stat fs = { 0 };
int ret; // iret must be 0 or error
int numRecords;

nameval binrec;
bool LessComp(const nameval& a1, const nameval& a2)
{
  if(strcmp(a1.fld_nm, a2.fld_nm) < 0) return true;
  if(strcmp(a1.fld_nm, a2.fld_nm) > 0) return false;
  if(a1.fld_val < a2.fld_val) return true;
  return false;
}

int _tmain(int argc,_TCHAR* argv[])
{
	if (argc < 3)
	{
		return ERROR;
	}
	if (INVALID_FILE_ATTRIBUTES == GetFileAttributes( argv[1] ))
	{
		cout << "File does not exist!\n";
		exit(EXIT_FAILURE);
	}
    std::set<nameval> records;
	std::set<nameval>::iterator iter;
	std::ifstream istrm(argv[1], std::ios::binary | std::ios::in );

	ret = stat(CT2A(argv[1]), &fs);
	numRecords = (int)(fs.st_size/sizeof(nameval));

	unsigned int nbegin=0;
	unsigned int nend=numRecords-1;
	unsigned int nmid;
	unsigned int nstop=0;
	char nm_got[100];
	unsigned int val_got;

	char szArgv2[512] = { 0 };
	wcstombs(szArgv2, argv[2], sizeof(szArgv2));
	while (nbegin<=nend && nstop!=-1)
	{
		nmid= (nbegin + nend)/2;

		nameval rec = { 0 };
		istrm.seekg(nmid* sizeof(nameval));
		istrm.read((char*)&rec, sizeof(nameval)); 

		if (strcmp(szArgv2,rec.fld_nm)<0)
		{
			nend=nmid-1;
			nmid = (nbegin+nend)/2;
		}
		else
		{
			if (strcmp(szArgv2,rec.fld_nm)>0)
			{
				nbegin=nmid+1;
				nmid = (nbegin+nend)/2;
			}
			else
			{
				nstop=-1;
				strcpy(rec.fld_nm,nm_got);
				val_got=rec.fld_val;
			}
		}
	}
	if (nstop==-1)
	  {
		  cout << "\nFound it!\n";
		  cout << "(From vector record: " << nm_got
			  << ' ' << val_got << ")\n";
	  }
	else cout << "\nDidn't find it!\n";

	system("pause>null");

    return 0;
}

Open in new window

0
HuaMin ChenProblem resolverAuthor Commented:
Sorry, I do not see "get_len" within the codes that is to do the search. Thanks a lot.
0
HuaMin ChenProblem resolverAuthor Commented:
Sorry, my mistake and please omit my last reply in above.
0
HuaMin ChenProblem resolverAuthor Commented:
Hi Sara,
Appreciate a lot to your help!

Here is the current nameval file

// nameval.h
#ifndef NAME_VAL_H
#define NAME_VAL_H

struct nameval
{
     char fld_nm[100];
     int    fld_val;

     int  get_len() { return min(strlen(fld_nm), sizeof(fld_nm) ) ; }
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm)));
     }
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
};

#endif

Open in new window


after having applied the change you suggested.

I have some problem to loop through the codes using Debug.

I still get this

C:\dp4\ReadBinaryFile\x64\Release>ReadBinaryFile "c:\dp4\flout.bin" "zzzspXvHvKqFlpeJoxTJ"

Didn't find it!

Open in new window


while here is the recent .bin file
https://dl.dropboxusercontent.com/u/40211031/flout2.rar

inside which zzzspXvHvKqFlpeJoxTJ does reside
0
HuaMin ChenProblem resolverAuthor Commented:
Hi Sara,
Could you please see this, only if available? Thanks a lot.
0
sarabandeCommented:
can you post the code of both programs?

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Here are the codes to create the .bin file
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <string>
#include <ctype.h>
#include <time.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;


struct nameval
{
	char fld_nm[100];
	wchar_t fld_nm_uni[100]; 
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
	size_t fld_len;
	size_t fld_val;
};
nameval binrec;

int main()
{
    std::set<nameval> records;
    int cnt;
	for (cnt=0;cnt<10000000;cnt++)
	{
		try 
		{
			nameval val={0};
			int j;
			for (j=0;j<20;j++)
			{
				val.fld_nm[j] += (char)(rand () % 26 + ((rand()%2)? 65 : 97));
			}
		
			wchar_t wbuf[100]={0};
			mbstowcs(wbuf,val.fld_nm,_countof(val.fld_nm));
			wmemcpy(val.fld_nm_uni,wbuf,100);

			val.fld_val=cnt;
			records.insert(val);
		}
		catch (exception& e)
		{
			cout << e.what() << '\n';
		}

	}

	std::ofstream ostrm("c:\\dp4\\flout.bin", std::ios::binary | std::ios::out );
	if (ostrm.is_open())
	{
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			try
			{
				ostrm.write((char *)&(*it), sizeof(nameval));
			}
			catch (exception& e)
			{
				cout << e.what() << '\n';
			}
		}
	}

	std::wofstream ostrm2("c:\\dp4\\flout.ord", std::ios::out );
	if (ostrm2.is_open())
	{
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			ostrm2 << "\"" << it->fld_nm << "\" " << it->fld_len << ' '  << it->fld_nm_uni << ' '<< it->fld_val << '\0' << '\n';
		}
	}

	return 0;
}

Open in new window


here are the codes to do the search
// 
//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <comutil.h>
#include <sys/stat.h>
#include <string>
#include <string.h>
#include <fstream>
#include <atlbase.h>
#include <ctype.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include "..\..\include\nameval.h"
#include <iomanip>
#include <Windows.h>

using namespace std;

struct stat fs = { 0 };
int ret; // iret must be 0 or error
int numRecords;

nameval binrec;
bool LessComp(const nameval& a1, const nameval& a2)
{
  if(strcmp(a1.fld_nm, a2.fld_nm) < 0) return true;
  if(strcmp(a1.fld_nm, a2.fld_nm) > 0) return false;
  if(a1.fld_val < a2.fld_val) return true;
  return false;
}

int _tmain(int argc,_TCHAR* argv[])
{
	if (argc < 3)
	{
		return ERROR;
	}
	if (INVALID_FILE_ATTRIBUTES == GetFileAttributes( argv[1] ))
	{
		cout << "File does not exist!\n";
		exit(EXIT_FAILURE);
	}
    std::set<nameval> records;
	std::set<nameval>::iterator iter;
	std::ifstream istrm(argv[1], std::ios::binary | std::ios::in );

	ret = stat(CT2A(argv[1]), &fs);
	numRecords = (int)(fs.st_size/sizeof(nameval));

	unsigned int nbegin=0;
	unsigned int nend=numRecords-1;
	unsigned int nmid;
	unsigned int nstop=0;
	char nm_got[100];
	unsigned int val_got;
		
	char szArgv2[512] = { 0 };
	wcstombs(szArgv2, argv[2], sizeof(szArgv2));
	while (nbegin<=nend && nstop!=-1)
	{
		nmid= (nbegin + nend)/2;

		nameval rec = { 0 };
		istrm.seekg(nmid* sizeof(nameval));
		istrm.read((char*)&rec, sizeof(nameval)); 

		if (strcmp(szArgv2,rec.fld_nm)<0)
		{
			nend=nmid-1;
			nmid = (nbegin+nend)/2;
		}
		else
		{
			if (strcmp(szArgv2,rec.fld_nm)>0)
			{
				nbegin=nmid+1;
				nmid = (nbegin+nend)/2;
			}
			else
			{
				nstop=-1;
				strcpy(rec.fld_nm,nm_got);
				val_got=rec.fld_val;
			}
		}
	}

	if (nstop==-1)
	  {
		  cout << "\nFound it!\n";
		  cout << "(From vector record: " << nm_got
			  << ' ' << val_got << ")\n";
	  }
	else cout << "\nDidn't find it!\n";

    return 0;
}

Open in new window


here is nameval file

// nameval.h
#ifndef NAME_VAL_H
#define NAME_VAL_H

struct nameval
{
     char fld_nm[100];
     int    fld_val;

     int  get_len() { return min(strlen(fld_nm), sizeof(fld_nm) ) ; }
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm)));
     }
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
};

#endif

Open in new window

0
HuaMin ChenProblem resolverAuthor Commented:
Many many thanks to your help!
0
sarabandeCommented:
the code to create the file must include the same nameval.h file, or it cannot work.

....
#include "..\..\include\nameval.h"   
#include <iomanip>
using namespace std;

//nameval binrec;

int main()
{
    std::set<nameval> records;
    int cnt;
    for (cnt=0;cnt<10000000;cnt++)
    {
          try 
          {
                 nameval val={0};
                  int j;
                  for (j=0;j<20;j++)
                  { 
                        val.fld_nm[j] += (char)(rand () % 26 + ((rand()%2)? 65 : 97));
		  }
		
                  // the wide char field is no longer needed
                  //wchar_t wbuf[100]={0};
                  //mbstowcs(wbuf,val.fld_nm,_countof(val.fld_nm));
                  //wmemcpy(val.fld_nm_uni,wbuf,100);

                  val.fld_val=cnt;
                  records.insert(val);
		}
		catch (exception& e)
                {
                 ....

Open in new window


Sara
0
HuaMin ChenProblem resolverAuthor Commented:
sorry, how to correct these
1>------ Rebuild All started: Project: SaveBinaryFile, Configuration: Release x64 ------
1>  stdafx.cpp
1>  SaveBinaryFile.cpp
1>c:\dp4\savebinaryfile (using set) 141212\savebinaryfile\..\..\include\nameval.h(10): error C3861: 'min': identifier not found
1>c:\dp4\savebinaryfile (using set) 141212\savebinaryfile\..\..\include\nameval.h(13): error C3861: 'min': identifier not found
1>SaveBinaryFile.cpp(129): error C2039: 'fld_len' : is not a member of 'nameval'
1>          c:\dp4\savebinaryfile (using set) 141212\savebinaryfile\..\..\include\nameval.h(6) : see declaration of 'nameval'
1>SaveBinaryFile.cpp(129): error C2039: 'fld_nm_uni' : is not a member of 'nameval'
1>          c:\dp4\savebinaryfile (using set) 141212\savebinaryfile\..\..\include\nameval.h(6) : see declaration of 'nameval'
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

Open in new window


due to these codes?

//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <string>
#include <ctype.h>
#include <time.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include "..\..\include\nameval.h"   
#include <iomanip>
using namespace std;
//

//
//
//
//
//
//
//
//
//
//
//}

//
//
	//
	//
	//
	//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
nameval binrec;

int main()
{
    std::set<nameval> records;
    int cnt;
	//
	for (cnt=0;cnt<10000000;cnt++)
	{
		try 
		{
			nameval val={0};
			int j;
			//
			for (j=0;j<20;j++)
			{
				//
				val.fld_nm[j] += (char)(rand () % 26 + ((rand()%2)? 65 : 97));
				//
			}
			//
			//
			//
			//
			//
			//
			//
		
			//
			//
			//
			//

			val.fld_val=cnt;
			//
			records.insert(val);
		}
		catch (exception& e)
		{
			cout << e.what() << '\n';
		}

	}
	//

	std::ofstream ostrm("c:\\dp4\\flout.bin", std::ios::binary | std::ios::out );
	if (ostrm.is_open())
	{
		//
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			//
			//
			//
			//
			try
			{
				ostrm.write((char *)&(*it), sizeof(nameval));
			}
			catch (exception& e)
			{
				cout << e.what() << '\n';
			}
		}
	}

	//
	//
    //
	std::wofstream ostrm2("c:\\dp4\\flout.ord", std::ios::out );
	if (ostrm2.is_open())
	{
		//
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			//
			//
			ostrm2 << "\"" << it->fld_nm << "\" " << it->fld_len << ' '  << it->fld_nm_uni << ' '<< it->fld_val << '\0' << '\n';
			//
			//
		}
	}

 	system("pause>null");

	return 0;
}

Open in new window

0
sarabandeCommented:
you don't need these members. remove all statements from code which are referring to fld_len or fld_nm_uni

ostrm2 << "\"" << it->fld_nm << " " << it->fld_val  << '\n';

Open in new window


or call the member functions get_len or get_uni_nm instead.

wchar_t wtemp[100] = { L'\0' };
it->get_uni_nm(wtemp, 100);
ostrm2 << "\"" << it->fld_nm << "\" " << it->get_fld_len() << ' '  <<wtemp << ' '<< it->fld_val << '\0' << '\n';

Open in new window



Sara
0
HuaMin ChenProblem resolverAuthor Commented:
Having these
			wchar_t wtemp[100] = { L'\0' };
			it->get_uni_nm(wtemp, 100);			
			//
			ostrm2 << "\"" << it->fld_nm << "\" " << it->get_fld_len() << ' '  <<wtemp << ' '<< it->fld_val << '\0' << '\n';
			...

Open in new window

I still get these
1>c:\dp4\savebinaryfile (using set) 141212\savebinaryfile\..\..\include\nameval.h(10): error C3861: 'min': identifier not found
1>c:\dp4\savebinaryfile (using set) 141212\savebinaryfile\..\..\include\nameval.h(13): error C3861: 'min': identifier not found
1>SaveBinaryFile.cpp(130): error C2662: 'nameval::get_uni_nm' : cannot convert 'this' pointer from 'const nameval' to 'nameval &'
1>          Conversion loses qualifiers
1>SaveBinaryFile.cpp(132): error C2039: 'get_fld_len' : is not a member of 'nameval'
1>          c:\dp4\savebinaryfile (using set) 141212\savebinaryfile\..\..\include\nameval.h(6) : see declaration of 'nameval'
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

Open in new window

0
sarabandeCommented:
error C3861: 'min': identifier not found
in nameval.h add #include <algorithm>

the other errors might be solved as well by that. if not, post both the nameval.h and the savebinary.cpp such that I can compile the sources.

Sara
0
HuaMin ChenProblem resolverAuthor Commented:
sorry, I still get these
1>c:\dp4\savebinaryfile (using set) 141212\savebinaryfile\..\..\include\nameval.h(10): error C3861: 'min': identifier not found
1>c:\dp4\savebinaryfile (using set) 141212\savebinaryfile\..\..\include\nameval.h(13): error C3861: 'min': identifier not found
1>SaveBinaryFile.cpp(131): error C2662: 'nameval::get_uni_nm' : cannot convert 'this' pointer from 'const nameval' to 'nameval &'
1>          Conversion loses qualifiers
1>SaveBinaryFile.cpp(133): error C2662: 'nameval::get_len' : cannot convert 'this' pointer from 'const nameval' to 'nameval &'
1>          Conversion loses qualifiers
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

Open in new window


using these

//

#include "stdafx.h"
#include <set>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <string>
#include <ctype.h>
#include <time.h>
#include <process.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include "..\..\include\nameval.h"   
#include <iomanip>
#include <algorithm>
using namespace std;
//

//
//
//
//
//
//
//
//
//
//
//

//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
nameval binrec;

int main()
{
    std::set<nameval> records;
    int cnt;
	//
	for (cnt=0;cnt<10000000;cnt++)
	{
		try 
		{
			nameval val={0};
			int j;
			//
			for (j=0;j<20;j++)
			{
				//
				val.fld_nm[j] += (char)(rand () % 26 + ((rand()%2)? 65 : 97));
				//
			}
			//
			//
			//
			//
			//
			//
			//
		
			//
			//
			//
			//

			val.fld_val=cnt;
			//
			records.insert(val);
		}
		catch (exception& e)
		{
			cout << e.what() << '\n';
		}

	}
	//

	std::ofstream ostrm("c:\\dp4\\flout.bin", std::ios::binary | std::ios::out );
	if (ostrm.is_open())
	{
		//
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			//
			//
			//
			//
			try
			{
				ostrm.write((char *)&(*it), sizeof(nameval));
			}
			catch (exception& e)
			{
				cout << e.what() << '\n';
			}
		}
	}

	//
	//
    //
	std::wofstream ostrm2("c:\\dp4\\flout.ord", std::ios::out );
	if (ostrm2.is_open())
	{
		//
		for (std::set<nameval>::iterator it = records.begin(); it != records.end(); ++it)
		{
			//
			//
			wchar_t wtemp[100] = { L'\0' };
			it->get_uni_nm(wtemp, 100);			
			//
			ostrm2 << "\"" << it->fld_nm << "\" " << it->get_len() << ' '  <<wtemp << ' '<< it->fld_val << '\0' << '\n';
			//
			//
		}
	}

 	system("pause>null");

	return 0;
}

Open in new window


here is nameval

// nameval.h
#ifndef NAME_VAL_H
#define NAME_VAL_H

struct nameval
{
     char fld_nm[100];
     int    fld_val;

     int  get_len() { return min(strlen(fld_nm), sizeof(fld_nm) ) ; }
     void get_uni_nm(wchar_t nm_uni[], int sizfld)
     {
            mbstowcs(nm_uni, fld_nm, min(sizfld-1, strlen(fld_nm)));
     }
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
};

#endif

Open in new window

0
HuaMin ChenProblem resolverAuthor Commented:
Big appreciation to you!
0
sarabandeCommented:
you may replace the nameval.h by the following:

// nameval.h
#ifndef NAME_VAL_H
#define NAME_VAL_H

struct nameval
{
     char fld_nm[100];
     int    fld_val;

     int  get_len() const 
     {   
         int len = strlen(fld_nm);
         if (len < (int)sizeof(fld_nm))
             return len;
         return (int)sizeof(fld_nm);
     }
     void get_uni_nm(wchar_t nm_uni[], int sizfld) const
     {
         int len = get_len();
         if (len > sizfld)
             len = sizfld;
         mbstowcs(nm_uni, fld_nm, len);
     }
     bool operator< (const nameval & a2) const
     {
           if(strcmp(fld_nm, a2.fld_nm) < 0) return true;
           if(strcmp(fld_nm, a2.fld_nm) > 0) return false;
           if (fld_val < a2.fld_val) return true;
           return false;
     }
};

#endif

Open in new window


I replaced the min function by equivalent c code and declared the member functions get_len and get_nm_uni as 'const'.

Sara
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.