473,740 Members | 10,529 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Comment on trim string function please

Just looking for a few eyes on this code other than my own.

void TrimCString(cha r *str)
{
// Trim whitespace from beginning:
size_t i = 0;
size_t j;

while(isspace(s tr[i]))
{
i++;
}
if(i 0)
{
for(j = 0; i < strlen(str); j++, i++)
{
str[j] = str[i];
}
str[j] = '\0';
}

// Trim whitespace from end:
i = strlen(str) - 1;

while(isspace(s tr[i]))
{
i--;
}
if(i < (strlen(str) - 1))
{
str[i + 1] = '\0';
}
}
Jul 10 '08 #1
121 5120
sw***********@g mail.com <sw***********@ gmail.comwrote:
Just looking for a few eyes on this code other than my own.
void TrimCString(cha r *str)
{
// Trim whitespace from beginning:
I guess I would trim from the end first since then you have less
copying to do afterwards.
size_t i = 0;
size_t j;
while(isspace(s tr[i]))
isspace() expects an int and not a char as it's argument.
{
i++;
}
if(i 0)
{
for(j = 0; i < strlen(str); j++, i++)
{
str[j] = str[i];
}
str[j] = '\0';
}
An alternative would be to use memmove() here, so you don't
have to do it byte by byte. Also callling strlen() each time
through the loop is a bit of a waste of time - it doesn't
change and can be replaced by a check if str[i] is '\0'.
// Trim whitespace from end:
i = strlen(str) - 1;
Careful: This could set 'i' to -1 (if the string consistet of white
space only) and then the rest won't work anymore.
while(isspace(s tr[i]))
{
i--;
}
if(i < (strlen(str) - 1))
{
str[i + 1] = '\0';
}
}
Here's an alternative version using pointers (and trying to
minimize the number of calls of strlen()):

void
TrimCString( char *str )
{
char *p,
*q;

/* Check that we've got something that looks like a string */

if ( ! str || ! * str )
return;

/* Trim from end */

for ( p = str + strlen( str ) - 1; p != str && isspace( ( int ) *p ); p-- )
/* empty */ ;

if ( p == str ) /* only white space in string */
{
*str = '\0';
return;
}

*++p = '\0';

/* Trim from start */

for ( q = str; isspace( ( int ) *q ); q++ )
/* empty */ ;

if ( q != str )
memmove( str, q, p - q + 1 );
}
Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\______________ ____________ http://toerring.de
Jul 10 '08 #2
sw***********@g mail.com wrote:
Just looking for a few eyes on this code other than my own.

void TrimCString(cha r *str)
Why not return a char *, like most other string functions?

char *TrimCString(ch ar *str)

using char * enables you to piggyback your function in the
middle of other functions, eg
printf("%s\n", TrimCString(som eString));
{
// Trim whitespace from beginning:
size_t i = 0;
size_t j;

while(isspace(s tr[i]))
{
i++;
}
if(i 0)
{
for(j = 0; i < strlen(str); j++, i++)
move the strlen() outside the loop.
Maybe use memmove() instead of the loop.
{
str[j] = str[i];
}
str[j] = '\0';
}

// Trim whitespace from end:
i = strlen(str) - 1;
Use the strlen you computed before, when
you moved it out of the for loop above :)
>
while(isspace(s tr[i]))
{
i--;
}
if(i < (strlen(str) - 1))
{
str[i + 1] = '\0';
No need for the test.
when i >= (strlen(str) - 1) -- it can only be equal, anyway -- the
assignment overwrites a '\0' with a brand new '\0'.
Anyway, if you want to keep the test, use the computed strlen.
}
}

A couple what-if's

* what if a pass NULL to the function?
TrimCString(NUL L);

* what if I pass a constant string literal to the function?
TrimCString(" 4 spaces at both ends ");
Jul 10 '08 #3
sw***********@g mail.com wrote:
Just looking for a few eyes on this code other than my own.
This pair of eyes sees three bugs, two occurring twice each
and the other perhaps due to too much snippage. There are also
some opportunities to improve speed and style. So, here we go:

Bug: Since you're using isspace() and strlen(), you need to
#include <ctype.hand <string.hto get their declarations.
Without the declarations, a compiler operating under C99 rules
must generate a diagnostic. Under C89 rules the code will work,
but might not be as fast as if the vendor's "magic" declarations
were present.
void TrimCString(cha r *str)
{
// Trim whitespace from beginning:
size_t i = 0;
Style: Instead of initializing `i' at its declaration and then
relying on the initial value later on, consider initializing it
closer to its use. The `for' statement is convenient for such
purposes.
size_t j;

while(isspace(s tr[i]))
Bug: If `str' contains negative-valued characters, this use
may violate the "contract" of isspace() by passing an out-of-range
argument. Use `while (isspace( (unsigned char)str[i] ))'. (This
is one of those occasions where a cast is almost always required
and almost always omitted, as opposed to the more usual situation
where a cast is almost always inserted and almost always wrong.)
{
i++;
}
if(i 0)
{
for(j = 0; i < strlen(str); j++, i++)
Speed: This loop calculates strlen(str) on every iteration.
Since it will return the same value each time, all calls after the
first are wasted effort. Call strlen() once before the loop and
store the result in a variable, and use that variable to control
the loop.
{
str[j] = str[i];
}
str[j] = '\0';
}

// Trim whitespace from end:
i = strlen(str) - 1;
Bug: If `str' is the empty string (either because it was
empty to begin with or because it contained only white space),
this calculation will produce a very large `i' that is almost
assuredly wrong, R-O-N-G.
while(isspace(s tr[i]))
Bug: Same missing cast as above.
{
i--;
}
if(i < (strlen(str) - 1))
Bug: Same mishandling of the empty string as above.

Speed: strlen(str) is still the same as it was a few lines
ago, so there's no point in computing it again.
{
str[i + 1] = '\0';
Speed: It's probably quicker -- and certainly less verbose --
to do this assignment unconditionally than to test whether it's
needed. If it isn't, you'll just store a zero on top of an
existing zero, which is harmless.
}
}
Summary: Not quite ready for prime time, but not as bad as
some attempts I've seen.

Challenge: See if you can think of a way to do the job in
just one pass over the string (calling strlen() counts as a
"pass"). Hint: During the copy-to-front operation, can you
somehow figure out where the final '\0' should land without
going back and inspecting the moved characters a second time?

--
Er*********@sun .com
Jul 10 '08 #4
On Jul 10, 1:32*pm, j...@toerring.d e (Jens Thoms Toerring) wrote:
swengineer...@g mail.com <swengineer...@ gmail.comwrote:
Just looking for a few eyes on this code other than my own.
void TrimCString(cha r *str)
{
* * * * // Trim whitespace from beginning:

I guess I would trim from the end first since then you have less
copying to do afterwards.
* * * * size_t i = 0;
* * * * size_t j;
* * * * while(isspace(s tr[i]))

isspace() expects an int and not a char as it's argument.
Doesn't this promotion happen implicitly and without loss of
information since I am actually dealing with characters and not using
the char as a holder for small integers?
>
* * * * {
* * * * * * * * i++;
* * * * }
* * * * if(i 0)
* * * * {
* * * * * * * * for(j = 0; i < strlen(str); j++, i++)
* * * * * * {
* * * * * * * * * * * * str[j] = str[i];
* * * * * * * * }
* * * * * * * * str[j] = '\0';
* * * * }

An alternative would be to use memmove() here, so you don't
have to do it byte by byte. Also callling strlen() each time
through the loop is a bit of a waste of time - it doesn't
change and can be replaced by a check if str[i] is '\0'.
* * * * // Trim whitespace from end:
* * * * i = strlen(str) - 1;

Careful: This could set 'i' to -1 (if the string consistet of white
space only) and then the rest won't work anymore.
i is of type size_t which I believe can't be negative?
>
* * * * while(isspace(s tr[i]))
* * * * {
* * * * * * * * i--;
* * * * }
* * * * if(i < (strlen(str) - 1))
* * * * {
* * * * * * * * str[i + 1] = '\0';
* * * * }
}

Here's an alternative version using pointers (and trying to
minimize the number of calls of strlen()):

void
TrimCString( char *str )
{
* * char *p,
* * * * * * **q;

* * /* Check that we've got something that looks like a string */

* * * * if ( ! str || ! * str )
* * * * * * * * return;

* * * * /* Trim from end */

* * for ( p = str + strlen( str ) - 1; p != str && isspace( ( int) *p ); p-- )
* * * * * * /* empty */ ;

* * * * if ( p == str ) * * */* only white space in string */
* * * * {
* * * * * * *str = '\0';
* * * * * * * * return;
* * }

* * * * *++p = '\0';

* * /* Trim from start */

* * * * for ( q = str; isspace( ( int ) *q ); q++ )
* * * * /* empty */ ;

* * if ( q != str )
* * * * memmove( str, q, p - q + 1 );}
Thanks for the code and the comments. This is useful.
Jul 10 '08 #5
On Jul 10, 1:39*pm, badc0...@gmail. com wrote:
swengineer...@g mail.com wrote:
Just looking for a few eyes on this code other than my own.
void TrimCString(cha r *str)

Why not return a char *, like most other string functions?

char *TrimCString(ch ar *str)

* * * * using char * enables you to piggyback your function in the
* * * * middle of other functions, eg
* * * * printf("%s\n", TrimCString(som eString));
Good point, I had not thought of it.
>
{
* *// Trim whitespace from beginning:
* *size_t i = 0;
* *size_t j;
* *while(isspace( str[i]))
* *{
* * * * * *i++;
* *}
* *if(i 0)
* *{
* * * * * *for(j = 0; i < strlen(str); j++, i++)

move the strlen() outside the loop.
Maybe use memmove() instead of the loop.
* * * *{
* * * * * * * * * *str[j] = str[i];
* * * * * *}
* * * * * *str[j] = '\0';
* *}
* *// Trim whitespace from end:
* *i = strlen(str) - 1;

Use the strlen you computed before, when
you moved it out of the for loop above :)
the length of the string has changed since then, possibly.
>

* *while(isspace( str[i]))
* *{
* * * * * *i--;
* *}
* *if(i < (strlen(str) - 1))
* *{
* * * * * *str[i + 1] = '\0';

No need for the test.
when i >= (strlen(str) - 1) -- it can only be equal, anyway -- the
assignment overwrites a '\0' with a brand new '\0'.
Anyway, if you want to keep the test, use the computed strlen.
* *}
}

A couple what-if's

* what if a pass NULL to the function?
* TrimCString(NUL L);
I added a check for this.
>
* what if I pass a constant string literal to the function?
* TrimCString(" * *4 spaces at both ends * *");
How can I account for this?

Jul 10 '08 #6
On Jul 10, 1:41*pm, Eric Sosman <Eric.Sos...@su n.comwrote:
swengineer...@g mail.com wrote:
Just looking for a few eyes on this code other than my own.

* * *This pair of eyes sees three bugs, two occurring twice each
and the other perhaps due to too much snippage. *There are also
some opportunities to improve speed and style. *So, here we go:

* * *Bug: Since you're using isspace() and strlen(), you need to
#include <ctype.hand <string.hto get their declarations.
Without the declarations, a compiler operating under C99 rules
must generate a diagnostic. *Under C89 rules the code will work,
but might not be as fast as if the vendor's "magic" declarations
were present.
void TrimCString(cha r *str)
{
* *// Trim whitespace from beginning:
* *size_t i = 0;

* * *Style: Instead of initializing `i' at its declaration and then
relying on the initial value later on, consider initializing it
closer to its use. *The `for' statement is convenient for such
purposes.
* *size_t j;
* *while(isspace( str[i]))

* * *Bug: If `str' contains negative-valued characters, this use
may violate the "contract" of isspace() by passing an out-of-range
argument. *Use `while (isspace( (unsigned char)str[i] ))'. *(This
is one of those occasions where a cast is almost always required
and almost always omitted, as opposed to the more usual situation
where a cast is almost always inserted and almost always wrong.)
* *{
* * * * * *i++;
* *}
* *if(i 0)
* *{
* * * * * *for(j = 0; i < strlen(str); j++, i++)

* * *Speed: This loop calculates strlen(str) on every iteration.
Since it will return the same value each time, all calls after the
first are wasted effort. *Call strlen() once before the loop and
store the result in a variable, and use that variable to control
the loop.
* * * *{
* * * * * * * * * *str[j] = str[i];
* * * * * *}
* * * * * *str[j] = '\0';
* *}
* *// Trim whitespace from end:
* *i = strlen(str) - 1;

* * *Bug: If `str' is the empty string (either because it was
empty to begin with or because it contained only white space),
this calculation will produce a very large `i' that is almost
assuredly wrong, R-O-N-G.
* *while(isspace( str[i]))

* * *Bug: Same missing cast as above.
* *{
* * * * * *i--;
* *}
* *if(i < (strlen(str) - 1))

* * *Bug: Same mishandling of the empty string as above.

* * *Speed: strlen(str) is still the same as it was a few lines
ago, so there's no point in computing it again.
* *{
* * * * * *str[i + 1] = '\0';

* * *Speed: It's probably quicker -- and certainly less verbose --
to do this assignment unconditionally than to test whether it's
needed. *If it isn't, you'll just store a zero on top of an
existing zero, which is harmless.
* *}
}

* * *Summary: Not quite ready for prime time, but not as bad as
some attempts I've seen.

* * *Challenge: See if you can think of a way to do the job in
just one pass over the string (calling strlen() counts as a
"pass"). *Hint: During the copy-to-front operation, can you
somehow figure out where the final '\0' should land without
going back and inspecting the moved characters a second time?

--
Eric.Sos...@sun .com
Thanks for the input. Someone else had pointed out one of the issues
you mentioned but I didn't understsnd what he was saying until I read
your description.
Jul 10 '08 #7
Here is my second go at it after reading the comments provided.

//This was in my original file but just not immediately before this
function
#include <ctype.h>
#include <string.h>

//Added char* return as suggested
char* TrimCString(cha r *str)
{
// Trim whitespace from beginning:
size_t i = 0;
size_t j;

//Added validation of the argument for NULL
if(str == NULL)
{
return str;
}

//Added cast as suggested. I have always avoided casts for various
reasons
//discussed in the FAQ and elsewhere but it is good to know this
case
while(isspace(( unsigned char)str[i]))
{
i++;
}
if(i 0)
{
//Calculate length once
size_t length = strlen(str);
//Decided to leave the bytewise copy I just think I can
understand it a little better
for(j = 0; i < length; j++, i++)
{
str[j] = str[i];
}
str[j] = '\0';
}

// Trim whitespace from end:
//Added check to catch the empty string
i = (strlen(str) ? (strlen(str) - 1) : 0);

while(isspace(( unsigned char)str[i]))
{
i--;
}
//Removed check that was not needed
str[i + 1] = '\0';
}
Jul 10 '08 #8
sw***********@g mail.com wrote:
On Jul 10, 1:39 pm, badc0...@gmail. com wrote:
swengineer...@g mail.com wrote:
Just looking for a few eyes on this code other than my own.
* what if I pass a constant string literal to the function?
TrimCString(" 4 spaces at both ends ");
How can I account for this?
Well ... you can't!
But you can do (at least) one of two things:

a) add a comment forbidding the caller to pass a string literal.
The comment goes near the function in the file with the code,
it also goes in the header file and in the documentation
provided for TrimCString()

b) Rewrite TrimCString to write the trimmed string to a
different memory area (variable, array, whatever), a bit
like strcpy() works

char *TrimCString(ch ar *dest, const char *source)
/* caller must ensure `dest` has enough space for
the trimmed string */
/* if source is NULL, trims `dest` in-place. `dest`
*MUST* be writable */
Jul 10 '08 #9
Eric Sosman <Er*********@su n.comwrites:
sw***********@g mail.com wrote:
>Just looking for a few eyes on this code other than my own.
<snip>
> size_t i = 0;

Style: Instead of initializing `i' at its declaration and then
relying on the initial value later on, consider initializing it
closer to its use. The `for' statement is convenient for such
purposes.
If you are suggesting replacing the while (isspace(str[i]) with a
for (int i = 0; isspace((unsign ed char)str[i]; i++); then this will not
allow i to tested outside the for:
> while(isspace(s tr[i]))
{
i++;
}
if(i 0)
here.

--
Ben.
Jul 10 '08 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

22
9746
by: Terry Olsen | last post by:
I have an app that makes decisions based on string content. I need to make sure that a string does not contain only spaces or newlines. I am using the syntax 'Trim(String)" and it works fine. I thought I'd change it to the VB ..NET method "String.Trim" but that throws an object exception. Which brings the question: is it compliant to use Trim(String), or is it more within etiquette to use If Not String Is Nothing Then String.Trim?
31
2909
by: rkk | last post by:
Hi, I've written a small trim function to trim away the whitespaces in a given string. It works well with solaris forte cc compiler, but on mingw/cygwin gcc it isn't. Here is the code: char *trim(char *s) { char *begin,*end; begin = s;
27
6874
by: FAQ server | last post by:
----------------------------------------------------------------------- FAQ Topic - How do I trim whitespace - LTRIM/RTRIM/TRIM? ----------------------------------------------------------------------- Using Regular Expressions (JavaScript 1.2/JScript 4+) : String.prototype.LTrim=new Function("return this.replace(/^\\s+/,'')") String.prototype.RTrim=new Function("return this.replace(/\\s+$/,'')") String.prototype.Trim= new...
5
3521
by: Marjeta | last post by:
I'm trying to very that the user actually entered something in the form, and not just spaces. I guess the problem is in the first line of isBlank() function. I've tried the following: elem.value.trim(); elem.value=elem.value.trim(); elem.value=trim(elem.value); elem.value.replace(/^\s+|\s+$/g,"");and none works. It correctly gives me an error message if I leave the field completely blank.But if there's anything in the field, it does not...
0
8794
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9484
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9342
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
6756
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6056
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4572
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3286
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2748
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2195
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.