Solved

Problem to the codes

Posted on 2014-11-28
114
200 Views
Last Modified: 2014-12-16
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

0
Comment
Question by:HuaMinChen
  • 55
  • 48
  • 3
  • +2
114 Comments
 
LVL 30

Expert Comment

by:Zoppo
ID: 40470240
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
 
LVL 30

Expert Comment

by:Zoppo
ID: 40470241
Sorry, please ignore my last comment, I wrote it without understanding the messages ...
0
 
LVL 30

Expert Comment

by:Zoppo
ID: 40470242
Do you use UNICODE in you program?
0
 
LVL 86

Expert Comment

by:jkr
ID: 40470660
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40471451
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40472444
Many thanks to you. Is there any other help?
0
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40472970
Yes, I have unicode to the record.
0
 
LVL 86

Expert Comment

by:jkr
ID: 40473018
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40473116
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40473206
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40473213
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40473255
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40473288
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40473342
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40473346
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40473368
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40473395
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40475083
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40475334
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40475384
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40475530
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40475531
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40475679
- 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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40477896
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40477899
Or I still need to count one by one within that?
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40477957
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40478007
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40478077
it is ok. you can call  istrm.seekg(position) and position is record_index * sizeof(record).

see sample code above.

Sara
0
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40478193
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40478310
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40479965
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40480216
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40480261
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40480285
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40480292
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40480303
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40480312
Can I still nstop there? And the current problem is not due to nbegin/nend, right?
0
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40480321
I mean to still use nstop, can I? Thanks
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40480343
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40480351
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40480416
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40480434
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40482091
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40482907
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40482929
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40484290
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40484378
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40484395
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40484569
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40484579
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40485364
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40485536
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40486042
Thanks a lot Sara.
How can I get into the attached screen to further put the relevant parameters?
t874.png
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40486272
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40486277
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
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 10

Author Comment

by:HuaMinChen
ID: 40486293
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40486361
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40486368
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40486371
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40486414
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40486421
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40486436
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40486446
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40486447
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40486461
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40488012
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40488484
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40488542
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40490977
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40491030
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40493098
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40493153
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40493154
thanks Phoffric.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40493312
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40493454
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40493459
Please omit my last question, to this thread. Thanks a lot.
0
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40493469
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40493470
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40493479
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
 
LVL 47

Expert Comment

by:dbrunton
ID: 40494592
>>  cause the struct size is 308.

308 or 304?
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40495185
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
 
LVL 47

Expert Comment

by:dbrunton
ID: 40495218
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40495590
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40495603
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40495633
Sara,
I have been stuck with the way to debug the program. Can you please help?
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40495637
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40495655
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40495663
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40495679
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40495685
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40495699
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40495716
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40495720
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40495727
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40495743
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40495744
Sorry, I do not see "get_len" within the codes that is to do the search. Thanks a lot.
0
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40497489
Sorry, my mistake and please omit my last reply in above.
0
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40497493
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40498825
Hi Sara,
Could you please see this, only if available? Thanks a lot.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40499914
can you post the code of both programs?

Sara
0
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40500020
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40500022
Many many thanks to your help!
0
 
LVL 32

Assisted Solution

by:sarabande
sarabande earned 500 total points
ID: 40500033
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40501813
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
 
LVL 32

Assisted Solution

by:sarabande
sarabande earned 500 total points
ID: 40501962
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40502007
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
 
LVL 32

Expert Comment

by:sarabande
ID: 40502069
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40502083
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
 
LVL 10

Author Comment

by:HuaMinChen
ID: 40502094
Big appreciation to you!
0
 
LVL 32

Accepted Solution

by:
sarabande earned 500 total points
ID: 40502267
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

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
In a recent article here at Experts Exchange (http://www.experts-exchange.com/articles/18880/PaperPort-14-in-Windows-10-A-First-Look.html), I discussed my nine-month sandbox testing of the Windows 10 Technical Preview, specifically with respect to r…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now