Archived

This topic is now archived and is closed to further replies.

ELS1

detecting if a string has spaces or is empty

Recommended Posts

i wrote this function, but its VERY unstable...it doesnt detect if it recieves nothing... im trying to learn a lot of string manipulation recently..and i got stuck on this. any help will be appreciated!
  
bool IsNull(char* String) {
	int Counter = 0 ;
	int StringLength = 0 ;

	StringLength = strlen(String) ;

if(StringLength == 0) {
return 1 ;
}

	for(Counter; String[Counter] && String[Counter] != '' ''; Counter++)
	{
		if(Counter)
		{
			return 1 ;
		}else{
			return 0 ;
		}
	}

	return 0 ;
}
  

Share this post


Link to post
Share on other sites
Personaly, I gave up char for string manipulations a while ago and anyway it's mainly to parse files at load time so no problemo there.

with strings it would look like that.


    
bool IsNull(std::string Text)
{
if (Text.lenght() == 0 || Text.find(" ") != -1)
return false;
else
return true;
}


Note that I havent played with find in a while so there might be a syntax error or something and I cant test it here ^_^.

Oh yeah about your problem, I'm guessing that it happens because you're not checking if the string is null. Also if the string has a bad pointer it will display garbage until it hits the null terminated string symbol '\o'.

[edited by - Dark Rain on March 21, 2002 4:37:08 PM]

[edited by - Dark Rain on March 21, 2002 4:38:38 PM]

Share this post


Link to post
Share on other sites
im trying to stay away from std::String(learning purposes)

i wrote my own String class that propery allocates and de allocates memory.

Share this post


Link to post
Share on other sites
functions.cpp

  
ConsoleString::ConsoleString() {
IsAllocated = 0 ;
}

ConsoleString::~ConsoleString() {
if (IsAllocated == 1) {
delete []NewString ;
}
}

char* ConsoleString::GetCommand(char* String) {
NewString = 0 ;
IsAllocated = 1 ;
int SpaceCounter = 0 ;
int Counter = 0 ;

SpaceCounter = strlen(String) - strlen(strchr(String, '' '')) ;
NewString = new char[SpaceCounter + 1] ;

for(Counter = 0; Counter <= SpaceCounter; Counter++)
{
NewString[Counter] = String[Counter] ;
}
NewString[SpaceCounter] = ''\0'' ;

return NewString ;
}

char* ConsoleString::GetArguments(char* String) {
IsAllocated = 1 ;
int SpaceCounter = 0 ;
int StringLength = 0 ;
int NewStringLength = 0 ;
int Counter = 0 ;
int Counter2 = 0 ;
NewString = 0 ;

SpaceCounter = strlen(String) - strlen(strchr(String, '' '')) + 1 ;
StringLength = strlen(String) ;
NewStringLength = strlen(strchr(String, '' '')) ;

NewString = new char[NewStringLength + 1] ;

for(Counter = SpaceCounter; Counter <= StringLength; Counter++)
{
NewString[Counter2] = String[Counter] ;
Counter2++ ;
}
NewString[NewStringLength] = ''\0'' ;

return NewString ;
}

bool ConsoleString::IsNull(char* String) {
int Counter = 0 ;
int StringLength = 0 ;

StringLength = strlen(String) ;

for(Counter; String[Counter] && String[Counter] != '' ''; Counter++)
{
if(Counter)
{
return 1 ;
}else{
return 0 ;
}
}

return 0 ;
}

void ProcessCommand(HWND ConsoleScreen, HWND EditBox) {
ConsoleString CommandString ;

char* Command = 0 ;
int CommandLength = 0 ;

int EditBoxLength = GetWindowTextLength(EditBox) + 1 ;
int ConsoleScreenLength = GetWindowTextLength(ConsoleScreen) + 1 ;

char* NewEditBoxString = new char[EditBoxLength] ;

GetWindowText(EditBox, NewEditBoxString, EditBoxLength) ;
SendMessage(EditBox, WM_SETTEXT, 0, (LPARAM)"") ;

CommandString.IsNull(NewEditBoxString) ;

if(!strcmp(strupr(NewEditBoxString), "
/COMMANDS")) {
AddConsoleText(ConsoleScreen, "
**Commands") ;
}else if(!strcmp(strupr(CommandString.GetCommand(NewEditBoxString)), "
/ECHO")) {
AddConsoleText(ConsoleScreen, CommandString.GetArguments(NewEditBoxString)) ;
}else {
AddConsoleText(ConsoleScreen, "
Invalid Command!") ;
}

delete []NewEditBoxString ;
}

void AddConsoleText(HWND ConsoleScreen, char* Text) {
char* LineFeed = "
\r\n" ;
int ConsoleScreenLength = GetWindowTextLength(ConsoleScreen) + 1 ;
int LineFeedLength = (int)strlen(LineFeed) + 1 ;
int TextLength = (int)strlen(Text) + 1 ;
int CombinedLength = LineFeedLength + TextLength ;

char* NewTextString = new char[CombinedLength] ;

strcpy(NewTextString, Text) ;
strcat(NewTextString, LineFeed) ;

SendMessage(ConsoleScreen, EM_SETSEL, (WPARAM)ConsoleScreenLength, (LPARAM)ConsoleScreenLength) ;
SendMessage(ConsoleScreen, EM_REPLACESEL, 0,(LPARAM)NewTextString) ;

delete []NewTextString ;
}


header file:

  
class ConsoleString {
bool IsAllocated ;
char* NewString ;
public:
ConsoleString() ;
~ConsoleString() ;
char* GetCommand(char* String) ;
char* GetArguments(char* String) ;
bool IsNull(char* String) ;
} ;

Share this post


Link to post
Share on other sites
There is probably a way to do it much faster, but is that what you need?


  
int IsNull(char * String)
{
unsigned int counter = 0;
if (!String) return 1;

for (;String[counter] && (String[counter] != ' '); counter++)
{}


if ((!counter) || (String[counter] == ' ') return 1;
return 0;
}


EDIT: Damn IE!!! added the source tag

[edited by - kefdman1 on March 21, 2002 5:16:02 PM]

Share this post


Link to post
Share on other sites
I have several comments, which are intended to be constructive criticism.

First off - const correctness. You have several functions which do not change the object state (IsNull for example). They should be const. You also have various variables and formal parameters which should be const, such as StringLength and String of the IsNull() function. const correctness is a good habit to get into, as it will help to make your code clearer, and help avoid silly mistakes and bugs creeping in. It may also allow certain optimisations too.

Next off, why do you pass a string into IsNull() as if it were a non-member function? If it is part of the class interface, it should be operating on the string within the class.

Depency management. What''re HWNDs doing in the interface of the class members? You are tying in a dependency here, and I''m not convinced it''s required.

There are other points, but I don''t want to go on. The only other comment worth making is that your IsNull() always returns 0. You set counter to 0, then say "if counter is 0, return 0" which will always be true.

Share this post


Link to post
Share on other sites
quote:
Original post by ELS1
im trying to stay away from std::String(learning purposes)

Fine. Do you also wish to stay away from Standard C Library functions? If not, why not use strtok?

Anyway, testing if a C string is null is this simple:

bool IsNull(char * string )
{
char * p = string;
while( p != ''\0'' )
{
if( p != '' '' && p != ''\0'' )
return false;
}
return true;
}


[ GDNet Start Here | GDNet Search Tool | GDNet FAQ | MS RTFM [MSDN] | SGI STL Docs | Google! ]
Thanks to Kylotan for the idea!

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan

Depency management. What''re HWNDs doing in the interface of the class members? You are tying in a dependency here, and I''m not convinced it''s required.


http://adrian.planetcpp.com/console/

im getting text from 2 Edit Controls.

thanks for the pointers

Share this post


Link to post
Share on other sites
quote:
Original post by Oluseyi


There are some mistakes in this code.
First, you dont increment p, so your only testing the first character.
Second, you're doing all your tests on the char* pointer, not the values it references.
Third, your if (...) would make the function return at the first iteration, unless the string is all spaces.


bool IsNull(char * string )
{
char * p = string;
while( p != '\0' )
{
if( p != ' ' && p != '\0' )
return false;
}
return true;
}



Here's probably what you meant:


bool IsNull(char * string )
{
char * p = string;
while( *p != '\0' )
{
if( *p == ' ' ) // testing twice for '\0' is redundant
return true;
p++; // incrementing p
}
if (p == string) return true; // if length == 0
return false;
}


This function will return true whenever the string has a length of zero or contains any space, that's what you need, right?

[edited by - kefdman1 on March 22, 2002 8:09:53 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I''m assuming you wanted to detect if it was blank, or was FILLED with spaces, not just contained a single space?


  
bool IsNull(char *String)
{
if (!String) //Is our pointer null?

return 1; //if so, then no string!

while (*String && *String=='' '') //not Terminated && a Space?

++String; //Increment our pointer to next value

if (!*String) //Did our loop go to our terminating char?

return 1; //Nothing found!

return 0; //It contains something other than spaces!

}


Billy - BillyB@mrsnj.com

ps. If you need anything else, you can directly contact me at my email address provided.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
SabreMan:
"First off - const correctness."

Const correctness doesn''t allow you to optomize at all.. actually.. the opposite. Check out my function and try to replace it with a "const correct" function and see how much optomization it gives you.

By saying that String is to be constant, you are forcing yourself to create at least 1 variable to point or to count with. You could make this a static variable so it''s only created once.. but then you just wasted 4 bytes of memory and an assignment (the assignment per call). Const does help in some readability I guess, but don''t say that it can help optomize, because... well.. there is NOTHING you can''t do with a normal pointer that you can do with a const pointer, inversely, there are things you can do with a non const pointer that you can''t do with a const one.

Secondly: I kind of agree with this one, but could disagree on this particular case (most cases I would have agreed though, as working with the members is what the function "should" be doing). But, what is he losing by passing it as an argument instead of using it directly (again, refer to my function). If he used it directly, he would have to make another pointer to the original or use an index variable... either way, it''s not any more efficient. Also, he can now call this function from outside of the class and use it if necessary... but, it probably wouldn''t be a bad idea for him to not pass anything to this one, and just use his class member variables.

3rd: Agreed.

Billy - BillyB@mrsnj.com

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
SabreMan:
"First off - const correctness."

Const correctness doesn''t allow you to optomize at all..

Yes it does, albeit only rarely. "ROMable" PODs can have better code generated.

quote:
actually.. the opposite. Check out my function and try to replace it with a "const correct" function and see how much optomization it gives you.

By saying that String is to be constant, you are forcing yourself to create at least 1 variable to point or to count with.

Not at all. For a NTCS, at the very least you should pass a const char*. This copies the pointer, but ensures that it''s a pointer to const char. You don''t have to create another variable to point, you use the one passed by value, but you ensure you can''t accidentally modify the characters of the string.

quote:
You could make this a static variable so it''s only created once.. but then you just wasted 4 bytes of memory and an assignment (the assignment per call). Const does help in some readability I guess, but don''t say that it can help optomize, because... well.. there is NOTHING you can''t do with a normal pointer that you can do with a const pointer,

On the contrary. The pointer to a const variable can point to ROM or otherwise read-only memory.

Why is this of consequence?

If you declare the function as taking const char*, you can pass any string -- including ones from, for instance, std::string::c_str(), and strings that are pooled in read-only memory (as most optimizing compilers will do) -- strings where you''re not allowed to modify the data.

If you declare the function as taking char*, you can''t -- not without casting away the constness, at least.

quote:
inversely, there are things you can do with a non const pointer that you can''t do with a const one.

Which aren''t pertinent here. The pointer is being passed by value, we can modify that all we like. It''s modifying the pointed-at things which is dangerous, which is why we want to prevent it with a const-correct function.

Share this post


Link to post
Share on other sites
As Oluseyi said there are standard c library functions for this sort of thing. However instead of using strtok I suggest strchr (to find if a string has a space) or strspn (to find if a string is all spaces).

Another thing to keep in mind if you''re trying to validate input is that you probably care about more just spaces. You usually don''t want your string to have control characters or whitespace in general (i.e. tabs, newlines, etc). To do this, take any of the for/while loop solutions above and replace the (*p=='' '') test with (isspace(*p) || !isprint(*p)).

Also don''t forget about leading/trailing spaces in otherwise valid strings. i.e. "foo bar" might be ok but you might not want "foo bar ".

-Mike

Billy, I don''t understand why you''re wailing about const correctness. You can make your function const correct simply by replacing "bool IsNull(char *String)" with "bool IsNull(const char *String)" and VC will generate the *exact* same code. for both versions.

Share this post


Link to post
Share on other sites
quote:
Original post by Anon Mike
Billy, I don''t understand why you''re wailing about const correctness. You can make your function const correct simply by replacing "bool IsNull(char *String)" with "bool IsNull(const char *String)" and VC will generate the *exact* same code. for both versions.

That''s not the point really - const correctness helps catch errors. So that if he accidentally typed *String = '' '' instead of *String == '' '', it would catch it at compile time.



[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost ]

Share this post


Link to post
Share on other sites