|
Hello, I'm new to this forum/website/ and C++!
The problem I'm having is that my loop repeats even when I enter a value of 'Y', 'y', 'N', or 'n'. I want it to break after one of these values have been entered and return it. Please advise.
Even if I enter Y, N, y, or n it still does the while loop. I'm trying to get it to repeat the loop ONLY if the value of the variable isn't one of the above. Please advise.
char searchAgain()
{
char rSearch;
do
{
cout << "Search again? (Y/N): ";
cin >> rSearch;
}while (rSearch != 'Y' || rSearch != 'y' || rSearch != 'N' || rSearch != 'n');
return rSearch;
}
"Criticism comes easier than craftsmanship" - Zeuxis
|
|
|
|
|
CarteBlanche wrote:
(rSearch != 'Y' || rSearch != 'y' || rSearch != 'N' || rSearch != 'n');
Change the || to && and it should do what you want.
right now you're saying if it's not Y or y or N or n, then continue looping... but, if you switch it to "if it's not Y and y and N and n", it'll exit the loop. or, it should at least.
|
|
|
|
|
Ahh, ok. That makes sense now. Thank you kindly
|
|
|
|
|
This is because you use the standard input stream (cin). This will read characters from the input stream into the designated buffer. As you will first type 'Y' and then press enter, the rSearch will end up showing the NULL character '\0'.
If you are using Visual Studio and/or Windows OS, consider utilizing the _getch function instead of the standard input stream. See MSDN with a keyword for more information about the function.
Code example:
#include <conio.h><DIV>
char rSearch;
do
{
cout << "Search again ? (Y/N): ";
_getch( rSearch );
rSearch = toupper( rSearch );
} while ( rSearch != 'Y' && rSearch != 'N' );
If you are programming on Linux and thus have no access _getch , consider creating a buffer of two or more characters, then using the input stream operation again, only this time checking the first character of the buffer. However, if user inserts more characters than the buffer can hold, the result is unpredictable. You can fix this by using the cin.get routine instead, with a fixed amount of characters read.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Wow, thanks. Much appreciated.
|
|
|
|
|
Hi,
What is the syntax to count the number of characters in a CString ?
Ehsan Behboudi
|
|
|
|
|
You should get able to use the GetLength function.
strMyString.GetLength();
- monrobot13
|
|
|
|
|
If you want to save to file, you may want to use GetLength()*sizeof(TCHAR), where TCHAR in Unicode environment is defined as two byte type.
|
|
|
|
|
hi mr2003,
you know what, you have a complete part of Visual Studio called MSDN... have you ever heard about it ?
if you have a look at CString Class members, i'm sure you can find that answer by yourself...
nevermind, everybody start to learn one day...
see you later i hope
TOXCCT
|
|
|
|
|
we all have good days and bad days, my friend !!!
Ehsan Behboudi
|
|
|
|
|
ey guy, that was just... a joke! humor!!!
You're probably better than me in coding, so keep cool man !
TOXCCT
|
|
|
|
|
Hello!
Right!
But anyway I know many good coders that know nothing about MFC
By the way: there exist empty global CString object (I am talking about vc60). By changing that object, every empty one will be initialized by the changed value. It can be achieved by changing newly created CString object in incorrect way of course. (Something like getting to inner char pointer, or calling GetBuffer without a release)
Funny results
|
|
|
|
|
I need to insert a page break after every hyperlink, if I try the InsertBreak then it replaces the hyperlink text/link, how do it make it happen after this link ?
Many Thanks,
Lee.
Hyperlinks hyplnks;
Hyperlink hyplnk;
Range rg = testDoc.GetContent();
hyplnks.AttachDispatch(rg.GetHyperlinks());
for (long j=1;j<=hyplnks.GetCount()-1;j++)
{
COleVariant n = COleVariant((long)j);
hyplnk.AttachDispatch(hyplnks.Item(n));
Range oSecRange = hyplnk.GetRange();
oSecRange.InsertBreak(COleVariant((long)7)); // 7 = wdPageBreak
}
|
|
|
|
|
Is it possible to have a CArray of structures that contain other CArrays? For example:
struct COMPLEX
{
CString original;
int changed;
CString new;
};
struct INV
{
CString zValue;
int valence;
int dependence;
int layerNum;
CArray<complex, complex=""> complexes;
};
struct INVISIBLE
{
CArray<inv, inv=""> invisible;
};
I have tried this, and I get an error referring to initializing the second CArray (the complexes array). Is this actually possible or should I start re-thinking my way of doing this?
Thanks
|
|
|
|
|
CArray is templated, are you doing that (or is it this BB stripping them out)
It should be,
CArray<COMPLEX, COMPLEX&> complexes;
Is that what you have?
|
|
|
|
|
oops, sorry i didn't realize that it didn't print out properly... let's try this again. i wasn't using the & sign though, what does that do?
struct COMPLEX
{
CString original;
int changed;
CString new;
};
struct INV
{
CString zValue;
int valence;
int dependence;
int layerNum;
CArray<COMPLEX, COMPLEX> complexes;
};
struct INVISIBLE
{
CArray<INV, INV> invisible;
};
|
|
|
|
|
these are the errors I get when I compile. I haven't done anything to my code other than adding the COMPLEX struct, and adding the CArray into the INV struct.
c:\program files\microsoft visual studio\vc98\mfc\include\afxtempl.h(255) : error C2558: struct 'INV' : no copy constructor available
c:\program files\microsoft visual studio\vc98\mfc\include\afxtempl.h(1566) : while compiling class-template member function 'struct INV __thiscall CArray<struct inv,struct="" inv="">::GetAt(int) const'
C:\Program Files\Microsoft Visual Studio\MyProjects\GUPIXWIN\DefineMatrixElementDialog.cpp(252) : error C2664: 'Add' : cannot convert parameter 1 from 'struct INV' to 'struct INV'
No copy constructor available for struct 'INV'
the one about adding is coming from this line:
ma_invisible.Add(invElement);
where ma_invisible is a CArray of INV structures and invElement is of type INV.
Does anyone have any ideas?
|
|
|
|
|
Like the errors say, try implementing a copy constructor inside the INV struct. This constructor is needed to implement a CArray of objects, unless you use the ampersand (&) as the second parameter of the CArray template instantation.
See any good C++ book for instructions on how copy constructors work.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Antti Keskinen wrote:
unless you use the ampersand (&) as the second parameter of the CArray template instantation.
with which CArray would i use the & with? the complexes or invisible one? (or both?)
thanks.
|
|
|
|
|
I think you should use it with both. So that the first TYPE is the struct's identifier, and the next is a reference to it. The default implementation uses a constant reference. They would e.g. become as
CArray< INV, INV& > INVArray;
For simple objects and members of the MFC collection, the usage of the class name only in the second parameter of CArray instantation works, because most of the classes have both copy constructors and operator= implemented. I believe you used a ready source code piece as an example of implementing it, and thus did not consider this issue.
Perhaps it works with this alteration. I am not sure, I'd need to test it myself to see what it says.. But this is pretty much as far as I can help you. Perhaps you should create a small test project just to create several structures with CArrays inside them and them fiddle about with them for a little to see how they work ?
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Basically,
The first paramater is the type stored in the array, so type INV in this case, the second is the type used in method calls - INV& avoids having to make a copy of the INV struct for each method call in the template that takes type INV.
Your problem basically comes down to the fact that CArray doesnt have a copy constructor. Without the embedded CArray in the INV struct, the compiler would just provide a default copy constructor for the INV struct. With the embedded CArray, it can't do it, so you need to provide a copy construtor for your INV struct that does a value by value copy of the "complexes" CArray member, plus the other ones too. It's needed because methods like GetAt return by value - IE make a copy of the item in the array and return that.
|
|
|
|
|
Antti Keskinen wrote:
instructions on how copy constructors work.
Just adding the ampersand didn't seem to do it... so I think I have to go the way of using copy constructors.
I don't have access (at the moment at least) to any (good) C++ books, so I was going through the help section of ms vc++ and came across some information that is useful. now, the examples they gave in the article entitled: BUG: Error C2664 and C2582 While Using CArray Class uses an example where a class containing a CArray is nested within another class. This is similar to what i am doing, i think, except they are using classes, where i'm using structs.
How do I implement a copy constructor for a CArray which is embedded within a struct? For example, I believe the only copy constructor I have to create is for my 'complexArray' CArray, which is embedded in a structure... I'm pretty sure I can't just put the copy constructor within the structure, so I'm not sure where I should define this copy constructor...
Thanks for all your help eveyone!
|
|
|
|
|
You define a copy contstructor for the structure itself, not the array inside it.
If your application required a copy constructor for the CArray, you would require to derive from CArray and implement a new class yourself: in this way, you would be able to define it's copy constructor. But that is not what you need.
Here is an example on implementing a copy constructor for a struct:
struct MyStruct
{
public:
MyStruct(const MyStruct& oldStruct);<DIV>
int iInteger;
double dDouble;<DIV>
};<DIV>
MyStruct::MyStruct( const MyStruct& oldStruct )
{
} The struct works pretty much in a similar way as a class does, but it has it's limitations, like member functions and so on. The access-level specification at the start of the struct is just a precaution: structures are public by default.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Just adding the & wont do it because functions like GetAt return by value, ie make a copy of what they return, so you need a copy constructor.
The & is just an optomisation that prevents all the function arguments in the template being passed by value, and therefor you needing to make a copy there too, so say if CArray had a template function called dosomething, like this:
template<type STORE_TYPE, type ARG_TYPE>
CArray::DoSomething(ARG_TYPE blah)
{
}
Here, the second paramater you specify to the template (INV& in this case) represents the type that is used in function calls. By saying INV refrence (ie with the &) rather than plain old INV, you avoid the complier having to make a copy of the passed in value every time a CArray method is called, quite significant if the INV is quite big, which it might be with it's embedded array.
To actually implmemnt the copy constructor, see post below for declaration, then in the declaration you copy each memeber of the passed in struct to the same memeber in the "this" struct, and in the case of the embedded array you will need to loop round each element in the passed in struct, then manually add it to the this struct.
You might be better going for STL as stated below, STL is much better at this sort of thing, and the MFC collection stuff was only really written because STL wasn't about/finised then.
Use stl::vector instead of CArray and you get a free copy constructor.
Use stl::set and you get other stuff too.
The only down side to STL is the documentation is total crap.
|
|
|
|
|
I made a little test project just to try this all out before actually implementing it in my own project. I created a separate header file that contains all my structures, and also this new copy constructor stuff. I have included this header file in CMainFrame. I'm getting link errors now when I compile, I looked everywhere for information on these errors yesterday and have come to the conclusion that things are being linked in the wrong order or something, but I wasn't able to actually fix the problem. This is what my new header file looks like (we'll call it MyStructures.h):
#include "afxtempl.h"
#include "stdafx.h"
..other structs defined here...
struct INV
{
public:
INV(const INV& oldStruct);
INV();
INV& operator=( const INV &s );
int number;
CArray<COMPLEX, COMPLEX&> complexArray;
};
//INV constructor
INV::INV()
{}
// Copy constructor implementation
INV::INV( const INV& oldStruct )
{
number = oldStruct.number;
//copy the complex array here
}
//operator= implementation
INV& INV::operator= ( const INV &s )
{
number = s.number;
//copy the complex array here
return *this;
}
..other structs defined here...
these are the errors i'm getting:
MainFrm.obj : error LNK2005: "public: __thiscall INV::INV(void)" (??0INV@@QAE@XZ) already defined in CopyConstructorTest.obj
MainFrm.obj : error LNK2005: "public: __thiscall INV::INV(struct INV const &)" (??0INV@@QAE@ABU0@@Z) already defined in CopyConstructorTest.obj
MainFrm.obj : error LNK2005: "public: struct INV & __thiscall INV::operator=(struct INV const &)" (??4INV@@QAEAAU0@ABU0@@Z) already defined in CopyConstructorTest.obj
Debug/CopyConstructorTest.exe : fatal error LNK1169: one or more multiply defined symbols found
|
|
|
|