Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #17069 > unrolled thread

Right trim string function in C

Started bypeter <pc722@nospam.mail.com.br>
First post2012-02-10 18:17 +0000
Last post2012-02-12 14:40 +0100
Articles 20 on this page of 56 — 21 participants

Back to article view | Back to comp.lang.c


Contents

  Right trim string function in C peter <pc722@nospam.mail.com.br> - 2012-02-10 18:17 +0000
    Re: Right trim string function in C James Kuyper <jameskuyper@verizon.net> - 2012-02-10 13:36 -0500
      Re: Right trim string function in C Devil with the China Blue Dress <chine.bleu@yahoo.com> - 2012-02-10 11:00 -0800
        Re: Right trim string function in C "BartC" <bc@freeuk.com> - 2012-02-14 12:41 +0000
          Re: Right trim string function in C "BartC" <bc@freeuk.com> - 2012-02-14 14:14 +0000
            Re: Right trim string function in C Ike Naar <ike@iceland.freeshell.org> - 2012-02-15 00:03 +0000
              Re: Right trim string function in C "BartC" <bc@freeuk.com> - 2012-02-15 01:00 +0000
                Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-15 02:08 +0000
                Re: Right trim string function in C Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-02-15 03:08 -0800
                  Re: Right trim string function in C gazelle@shell.xmission.com (Kenny McCormack) - 2012-02-15 13:00 +0000
                    Re: Right trim string function in C Kaz Kylheku <kaz@kylheku.com> - 2012-02-16 00:36 +0000
                Re: Right trim string function in C Kaz Kylheku <kaz@kylheku.com> - 2012-02-16 00:28 +0000
                Re: Right trim string function in C gordonb.7bjv1@burditt.org (Gordon Burditt) - 2012-03-12 03:27 -0500
                  Re: Right trim string function in C China Blue Water Navy <chine.bleu@yahoo.com> - 2012-03-12 03:57 -0800
          Re: Right trim string function in C Devil with the China Blue Dress <chine.bleu@yahoo.com> - 2012-02-14 09:59 -0800
        Re: Right trim string function in C Kaz Kylheku <kaz@kylheku.com> - 2012-02-14 12:56 +0000
          Re: Right trim string function in C Devil with the China Blue Dress <chine.bleu@yahoo.com> - 2012-02-14 09:17 -0800
          Re: Right trim string function in C Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-02-14 10:10 -0800
    Re: Right trim string function in C Barry Schwarz <schwarzb@dqel.com> - 2012-02-10 11:30 -0800
      Re: Right trim string function in C James Kuyper <jameskuyper@verizon.net> - 2012-02-10 14:45 -0500
        Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-10 22:15 +0000
          Re: Right trim string function in C James Kuyper <jameskuyper@verizon.net> - 2012-02-10 17:21 -0500
            Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-10 23:25 +0000
            Re: Right trim string function in C Keith Thompson <kst-u@mib.org> - 2012-02-10 15:31 -0800
        Re: Right trim string function in C pete <pfiland@mindspring.com> - 2012-02-10 17:17 -0500
          Re: Right trim string function in C Devil with the China Blue Dress <chine.bleu@yahoo.com> - 2012-02-10 15:12 -0800
    Re: Right trim string function in C "Morris Keesan" <mkeesan@post.harvard.edu> - 2012-02-10 14:46 -0500
      Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-10 21:56 +0000
        Re: Right trim string function in C James Kuyper <jameskuyper@verizon.net> - 2012-02-10 17:08 -0500
          Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-10 23:14 +0000
            Re: Right trim string function in C David Thompson <dave.thompson2@verizon.net> - 2012-02-18 23:11 -0500
        Re: Right trim string function in C Keith Thompson <kst-u@mib.org> - 2012-02-11 12:06 -0800
        Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-11 20:12 +0000
        Re: Right trim string function in C Tim Rentsch <txr@alumni.caltech.edu> - 2012-03-08 13:10 -0800
    Re: Right trim string function in C "Scott Fluhrer" <sfluhrer@ix.netcom.com> - 2012-02-10 15:39 -0500
    Re: Right trim string function in C Shao Miller <sha0.miller@gmail.com> - 2012-02-11 03:52 -0500
      Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-11 13:50 +0000
        Re: Right trim string function in C Shao Miller <sha0.miller@gmail.com> - 2012-02-11 11:47 -0500
          Re: Right trim string function in C Shao Miller <sha0.miller@gmail.com> - 2012-02-11 12:20 -0500
          Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-11 20:57 +0000
            Re: Right trim string function in C Shao Miller <sha0.miller@gmail.com> - 2012-02-11 17:43 -0500
    Re: Right trim string function in C Willem <willem@toad.stack.nl> - 2012-02-11 11:57 +0000
      Re: Right trim string function in C Willem <willem@toad.stack.nl> - 2012-02-11 18:11 +0000
    Re: Right trim string function in C August Karlstrom <fusionfile@gmail.com> - 2012-02-11 18:41 +0100
      Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-11 19:58 +0000
        Re: Right trim string function in C Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-02-11 13:11 -0800
        Re: Right trim string function in C August Karlstrom <fusionfile@gmail.com> - 2012-02-11 22:18 +0100
          Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-11 23:48 +0000
            Re: Right trim string function in C August Karlstrom <fusionfile@gmail.com> - 2012-02-12 02:20 +0100
            Re: Right trim string function in C Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-02-12 03:44 -0800
              Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-12 14:01 +0000
                Re: Right trim string function in C Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-02-12 11:06 -0800
                  Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-12 19:34 +0000
                    Re: Right trim string function in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-12 23:35 +0000
      Re: Right trim string function in C Barry Schwarz <schwarzb@dqel.com> - 2012-02-11 14:27 -0800
        Re: Right trim string function in C August Karlstrom <fusionfile@gmail.com> - 2012-02-12 14:40 +0100

Page 2 of 3 — ← Prev page 1 [2] 3  Next page →


#17086

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-02-10 22:15 +0000
Message-ID<0.c20ab90332b1b9d6672c.20120210221526GMT.87fweibaip.fsf@bsb.me.uk>
In reply to#17077
James Kuyper <jameskuyper@verizon.net> writes:

> On 02/10/2012 02:30 PM, Barry Schwarz wrote:
>> On 10 Feb 2012 18:59:36 GMT, ram@zedat.fu-berlin.de (Stefan Ram)
>> wrote:
>> 
>>> peter <pc722@nospam.mail.com.br> writes:
> [snipage restored:]
>>>>         Is there a right trim function that will remove the
>>>> trailing spaces and make *str look like "Hello Dolly\0"?
> ...
>> Why have all the solutions so far changed all the trailing blanks to
>> nuls? ...
>
> Because that's what the OP requested (see above).

Only one blank needs to be changed to a null to satisfy the OP's
request.  So far, the solutions have done more than that.  It's not
wrong, but it is noteworthy.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#17088

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-02-10 17:21 -0500
Message-ID<4F359875.9050809@verizon.net>
In reply to#17086
On 02/10/2012 05:15 PM, Ben Bacarisse wrote:
> James Kuyper <jameskuyper@verizon.net> writes:
> 
>> On 02/10/2012 02:30 PM, Barry Schwarz wrote:
>>> On 10 Feb 2012 18:59:36 GMT, ram@zedat.fu-berlin.de (Stefan Ram)
>>> wrote:
>>>
>>>> peter <pc722@nospam.mail.com.br> writes:
>> [snipage restored:]
>>>>>         Is there a right trim function that will remove the
>>>>> trailing spaces and make *str look like "Hello Dolly\0"?
>> ...
>>> Why have all the solutions so far changed all the trailing blanks to
>>> nuls? ...
>>
>> Because that's what the OP requested (see above).
> 
> Only one blank needs to be changed to a null to satisfy the OP's
> request.  So far, the solutions have done more than that.  It's not
> wrong, but it is noteworthy.

He asked to have the trailing blanks removed. That's "blanks", plural -
removing only a single blank doesn't do the job. It's possible that what
you're suggesting is what he actually meant, but I've worked in
situations where it was important to zero-out the unused portion of a
buffer containing a string, and that's what I assumed he was looking
for. Several others seem to agree.


[toc] | [prev] | [next] | [standalone]


#17098

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-02-10 23:25 +0000
Message-ID<0.a2d1e01b405f69fff027.20120210232527GMT.87mx8q9spk.fsf@bsb.me.uk>
In reply to#17088
James Kuyper <jameskuyper@verizon.net> writes:

> On 02/10/2012 05:15 PM, Ben Bacarisse wrote:
>> James Kuyper <jameskuyper@verizon.net> writes:
>> 
>>> On 02/10/2012 02:30 PM, Barry Schwarz wrote:
>>>> On 10 Feb 2012 18:59:36 GMT, ram@zedat.fu-berlin.de (Stefan Ram)
>>>> wrote:
>>>>
>>>>> peter <pc722@nospam.mail.com.br> writes:
>>> [snipage restored:]
>>>>>>         Is there a right trim function that will remove the
>>>>>> trailing spaces and make *str look like "Hello Dolly\0"?
>>> ...
>>>> Why have all the solutions so far changed all the trailing blanks to
>>>> nuls? ...
>>>
>>> Because that's what the OP requested (see above).
>> 
>> Only one blank needs to be changed to a null to satisfy the OP's
>> request.  So far, the solutions have done more than that.  It's not
>> wrong, but it is noteworthy.
>
> He asked to have the trailing blanks removed. That's "blanks", plural -
> removing only a single blank doesn't do the job. It's possible that what
> you're suggesting is what he actually meant, but I've worked in
> situations where it was important to zero-out the unused portion of a
> buffer containing a string, and that's what I assumed he was looking
> for. Several others seem to agree.

That seems unlikely.  For one thing, people have not followed the
request literally.  The OP said "spaces" and yet everyone has happily
ignored that and tested for isspace.  Why take one thing literally and
ignore another?

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#17099

FromKeith Thompson <kst-u@mib.org>
Date2012-02-10 15:31 -0800
Message-ID<ln4nuyl0zb.fsf@nuthaus.mib.org>
In reply to#17088
James Kuyper <jameskuyper@verizon.net> writes:
> On 02/10/2012 05:15 PM, Ben Bacarisse wrote:
[...]
>> Only one blank needs to be changed to a null to satisfy the OP's
>> request.  So far, the solutions have done more than that.  It's not
>> wrong, but it is noteworthy.
>
> He asked to have the trailing blanks removed. That's "blanks", plural -
> removing only a single blank doesn't do the job. It's possible that what
> you're suggesting is what he actually meant, but I've worked in
> situations where it was important to zero-out the unused portion of a
> buffer containing a string, and that's what I assumed he was looking
> for. Several others seem to agree.

Setting just the first trailing blank to '\0' does remove all the
trailing blanks *from the string*, but not from the array.

This is an argument for clear problem statements.  This sometimes
requires a bit of back-and-forth to clarify ambiguities; it's not
realistic to expect that every problem statement will be completely
unambiguous in its initial form.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#17087

Frompete <pfiland@mindspring.com>
Date2012-02-10 17:17 -0500
Message-ID<4F35975C.72BB@mindspring.com>
In reply to#17077
James Kuyper wrote:
> 
> On 02/10/2012 02:30 PM, Barry Schwarz wrote:
> > On 10 Feb 2012 18:59:36 GMT, ram@zedat.fu-berlin.de (Stefan Ram)
> > wrote:
> >
> >> peter <pc722@nospam.mail.com.br> writes:
> [snipage restored:]
> >>>         Is there a right trim function that will remove the
> >>> trailing spaces and make *str look like "Hello Dolly\0"?
> ...
> > Why have all the solutions so far changed all the trailing blanks to
> > nuls? ...
> 
> Because that's what the OP requested (see above).

I interpreted it the way that Barry Scharwz did:
that the string is the thing 
from which the trailing spaces should be removed.

-- 
pete

[toc] | [prev] | [next] | [standalone]


#17092

FromDevil with the China Blue Dress <chine.bleu@yahoo.com>
Date2012-02-10 15:12 -0800
Message-ID<chine.bleu-03198D.15115810022012@news.eternal-september.org>
In reply to#17087
In article <4F35975C.72BB@mindspring.com>, pete <pfiland@mindspring.com> wrote:

> James Kuyper wrote:
> > 
> > On 02/10/2012 02:30 PM, Barry Schwarz wrote:
> > > On 10 Feb 2012 18:59:36 GMT, ram@zedat.fu-berlin.de (Stefan Ram)
> > > wrote:
> > >
> > >> peter <pc722@nospam.mail.com.br> writes:
> > [snipage restored:]
> > >>>         Is there a right trim function that will remove the
> > >>> trailing spaces and make *str look like "Hello Dolly\0"?
> > ...
> > > Why have all the solutions so far changed all the trailing blanks to
> > > nuls? ...
> > 
> > Because that's what the OP requested (see above).
> 
> I interpreted it the way that Barry Scharwz did:
> that the string is the thing 
> from which the trailing spaces should be removed.

Zeroing all trailing blanks is simple design. The alternative is to find the 
last space, then zero just that. That's two steps instead of one to avoid stores 
which will have teensy impact (because the zeroed bytes will already be in 
cache). The second design also stores a zero in a zero byte which the second 
design avoid; if most lines do not end in blanks, the 'efficient' design will do 
more stores. You can avoid those useless stores by storing the zero 
conditionally, much makes the design even more complicated for questionable 
efficiency.

-- 
My name Indigo Montoya.      |         It's Coraline, not Caroline.
You flamed my father.        |       I'm whoever you want me to be.
Prepare to be spanked.       |  Annoying Usenet one post at a time.
Stop posting that!           |    At least I can stay in character.

[toc] | [prev] | [next] | [standalone]


#17078

From"Morris Keesan" <mkeesan@post.harvard.edu>
Date2012-02-10 14:46 -0500
Message-ID<op.v9hajzxp5qv6o3@toshiba-laptop>
In reply to#17069
On Fri, 10 Feb 2012 13:59:36 -0500, Stefan Ram <ram@zedat.fu-berlin.de>  
wrote:

> peter <pc722@nospam.mail.com.br> writes:
>> char *str = "Hello Dolly     \0";
> (...)
>> In PYTHON there is a useful function for this: str.rstrip();
>
>   Untested and assuming that the string is in a mutable buffer:
>
> #include <ctype.h>
> #include <string.h>
>
> void rstrip( char * const string )
> { char * last = string + strlen( string )- 1;
>   while( last >= string && isspace( last ))*last-- = 0; }

I believe that this invokes undefined behavior if strlen(string) == 0.

-- 
Morris Keesan -- mkeesan@post.harvard.edu

[toc] | [prev] | [next] | [standalone]


#17084

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-02-10 21:56 +0000
Message-ID<0.6430c14d237a7d688fd1.20120210215638GMT.87pqdmbbe1.fsf@bsb.me.uk>
In reply to#17078
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>>void rstrip( char * const string )
>>{ char * p = string + strlen( string );
>>  while( p-- > string && isspace( p ))*p = 0; }

Both here and below you meant to write isspace(*p).

>   or, more careful:
>
> void rstrip( char * const string )
> { char * p = string + strlen( string ); if( p > string )
>   while( p-- > string && isspace( p ))*p = 0; }

No, that has a similar problem.  Unfortunately you've cut the context so
it won't be clear what you were correcting.  The problem was
constructing an invalid pointer that points before the start of the
string and this code can also do that when the string is all spaces.

In addition to being careful about the pointers, you need to finesse the
mess that is isspace (and friends) when char might be signed.  It's a
shame that what should be a simple function is really quite tricky.

  char *rstrip(unsigned char *string)
  {
      char *ep = strchr(0);
      while (ep > string && isspace(ep[-1])) --ep;
      *ep = 0;
      return string;
  }

(The unsigned char * just is to avoid cluttering the code with a cast or
Tim's exotic compound literal union.)
 
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#17085

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-02-10 17:08 -0500
Message-ID<4F359542.6010306@verizon.net>
In reply to#17084
On 02/10/2012 04:56 PM, Ben Bacarisse wrote:
...
>   char *rstrip(unsigned char *string)
>   {
>       char *ep = strchr(0);

	strchr(string, 0)?

[toc] | [prev] | [next] | [standalone]


#17094

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-02-10 23:14 +0000
Message-ID<0.136441344235011b7d20.20120210231417GMT.87sjii9t86.fsf@bsb.me.uk>
In reply to#17085
James Kuyper <jameskuyper@verizon.net> writes:

> On 02/10/2012 04:56 PM, Ben Bacarisse wrote:
> ...
>>   char *rstrip(unsigned char *string)
>>   {
>>       char *ep = strchr(0);
>
> 	strchr(string, 0)?

Yes, thanks.  Glad I followed protocol in posting an error in a
correction :-)

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#17591

FromDavid Thompson <dave.thompson2@verizon.net>
Date2012-02-18 23:11 -0500
Message-ID<bqe0k7l5spamvgbohg3c42f5qs5nfuge8j@4ax.com>
In reply to#17094
On Fri, 10 Feb 2012 23:14:17 +0000, Ben Bacarisse
<ben.usenet@bsb.me.uk> wrote:

> James Kuyper <jameskuyper@verizon.net> writes:
> 
> > On 02/10/2012 04:56 PM, Ben Bacarisse wrote:
> > ...
> >>   char *rstrip(unsigned char *string)
> >>   {
> >>       char *ep = strchr(0);
> >
> > 	strchr(string, 0)?
> 

  unsigned char * ep = (unsigned char *) strchr ( (char*)string, 0)
to achieve the stated simplification of isspace() call.
Which at this point might not really be worth it.

Or change string back to plain char *, don't cast the strchr argument,
but do cast in the comparison. Not really a whole lot easier.

> Yes, thanks.  Glad I followed protocol in posting an error in a
> correction :-)

Is an incomplete correction a new error?

<ObControversy> Maybe if it's volatile. </>

[toc] | [prev] | [next] | [standalone]


#17121

FromKeith Thompson <kst-u@mib.org>
Date2012-02-11 12:06 -0800
Message-ID<lnzkcpjfse.fsf@nuthaus.mib.org>
In reply to#17084
ram@zedat.fu-berlin.de (Stefan Ram) writes:
> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>>In addition to being careful about the pointers, you need to finesse the
>>mess that is isspace (and friends) when char might be signed.  
>
>   Ok, I admit that I do not understand this. After
>
> #include <ctype.h>
>
>   , and in the scope of something like
>
> char c;
>
>   , the expression
>
> isspace( c )
>
>   will be nonzero, when c is a standard white-space character
>   (or is one of a locale-specific set of characters).
>
>   Where is the problem Ben refers to?

N1570 7.4p1:

    ... the argument is an int, the value of which shall be
    representable as an unsigned char or shall equal the value of
    the macro EOF. If the argument has any other value, the behavior
    is undefined.

If plain char is signed and the value of c is negative (and not
equal to EOF), then the behavior of isspace(c) is undefined.

This can be avoided by writing:

    isspace((unsigned char)c)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#17124

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-02-11 20:12 +0000
Message-ID<0.f5dcd4d74fa5b5129c11.20120211201210GMT.87hayxb04l.fsf@bsb.me.uk>
In reply to#17084
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>>In addition to being careful about the pointers, you need to finesse the
>>mess that is isspace (and friends) when char might be signed.  
>
>   Ok, I admit that I do not understand this. After
>
> #include <ctype.h>
>
>   , and in the scope of something like
>
> char c;
>
>   , the expression
>
> isspace( c )
>
>   will be nonzero, when c is a standard white-space character
>   (or is one of a locale-specific set of characters).
>
>   Where is the problem Ben refers to?

7.4 p1:

  The header <ctype.h> declares several functions useful for classifying
  and mapping characters. In all cases the argument is an int, the value
  of which shall be representable as an unsigned char or shall equal the
  value of the macro EOF. If the argument has any other value, the
  behavior is undefined.

If char is signed, not all values of (int)c (the effect of the argument
promotion) are representable as an unsigned char.  Also, there may be
a character for which (int)c == EOF.

If you know that char is unsigned or that all values of c are positive,
then there's no problem, but in portable code you need to take some
evasive action.  The "usual" solution is to write

  isspace((unsigned char)c);

but there was a recent thread where it was suggested that is not always
100% portable and correct depending on where the characters come from
and what representation the machine uses.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#18350

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-03-08 13:10 -0800
Message-ID<kfn4ntyssro.fsf@x-alumni2.alumni.caltech.edu>
In reply to#17084
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>
>> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>>>void rstrip( char * const string )
>>>{ char * p = string + strlen( string );
>>>  while( p-- > string && isspace( p ))*p = 0; }
>
> Both here and below you meant to write isspace(*p).
>
>>   or, more careful:
>>
>> void rstrip( char * const string )
>> { char * p = string + strlen( string ); if( p > string )
>>   while( p-- > string && isspace( p ))*p = 0; }
>
> No, that has a similar problem.  Unfortunately you've cut the context so
> it won't be clear what you were correcting.  The problem was
> constructing an invalid pointer that points before the start of the
> string and this code can also do that when the string is all spaces.
>
> In addition to being careful about the pointers, you need to finesse the
> mess that is isspace (and friends) when char might be signed.  It's a
> shame that what should be a simple function is really quite tricky.

My solution had two statements and one single-line macro definition.


>   char *rstrip(unsigned char *string)
>   {
>       char *ep = strchr(0);
>       while (ep > string && isspace(ep[-1])) --ep;
>       *ep = 0;
>       return string;
>   }
>
> (The unsigned char * just is to avoid cluttering the code with a cast

I think you've got your unsigned-ness in the wrong place.

> or Tim's exotic compound literal union.)

Exotic?!???  Why that's ridiculous. :) :) :)

More seriously, this sort of thing should be bundled up in a macro
definition, and with C11 now coming to the fore, a macro around
a _Generic expression should work quite nicely.

[toc] | [prev] | [next] | [standalone]


#17082

From"Scott Fluhrer" <sfluhrer@ix.netcom.com>
Date2012-02-10 15:39 -0500
Message-ID<1328906232.68669@rcdn-nntpcache-2>
In reply to#17069
"peter" <pc722@nospam.mail.com.br> wrote in message 
news:jh3n08$6hs$1@speranza.aioe.org...
> Hello C programmers,
>        I was wondering does anybody knows how or is there
> a right trim string function available in C?
>
>        Eg. Suppose I have the following:
>
>           char *str = "Hello Dolly     \0";
>
>        Is there a right trim function that will remove the
> trailing spaces and make *str look like "Hello Dolly\0"?

Other people have given you advice about how to do it (it isn't difficult), 
but they mentioned that the string must be in a "mutable buffer", without 
spelling out what that is.

Here's the issue; when you use a constant string using the "string" context, 
as in:

   char *str = "Hello Dolly     \0";

that string lies in memory that you're not supposed to modify.  If you do 
modify it, well, C doesn't say what happens; the compiler can do whatever it 
thinks is appropriate (which might not what you think is appropriate).  In 
practice, common behaviors could be:
- The program terminates (yes, really)
- The string is not changed, but the program continues anyways
- The string gets modified as you would expect
- The string gets modified, and in addition, other strings throughout the 
program also get modified

If you have such a string, and you want to modify it, you'll need to copy 
it, and modify the copy.

The exception to the above rule is if you declare str to be an array of 
char's, as:

    char str[] = "Hello Dolly     \0";

If you do that, you can modify str to your hearts content (as long as you 
don't write past the end of the array)...


Now, if you're doing this on nonfixed strings (say, strings you read from a 
file), well, this isn't an issue, or as a wise woman once said: "Never Mind"

-- 
poncho

[toc] | [prev] | [next] | [standalone]


#17107

FromShao Miller <sha0.miller@gmail.com>
Date2012-02-11 03:52 -0500
Message-ID<jh5a2l$gtc$1@dont-email.me>
In reply to#17069
On 2/10/2012 13:17, peter wrote:
> Hello C programmers,
>          I was wondering does anybody knows how or is there
> a right trim string function available in C?
>
>          Eg. Suppose I have the following:
>
>             char *str = "Hello Dolly     \0";
>
>          Is there a right trim function that will remove the
> trailing spaces and make *str look like "Hello Dolly\0"?
>
> In PYTHON there is a useful function for this: str.rstrip();

Maybe you would like this?:

   /* Also available at http://ideone.com/JBT2Y */

   #include <stddef.h>
   #include <stdlib.h>
   #include <string.h>
   #include <stdio.h>

   static int in_set(
       register const int c,
       register const char * chars
     ) {
       register int test;

       while ((test = *chars)) {
           if (c == test)
             return 1;
           ++chars;
           continue;
         }
       return 0;
     }

   char * rstrip(
       register const char * string,
       register const char * const chars
     ) {
       register char c;
       register const char * cur_pos = string;
       register const char * one_past_end = string + 1;
       register ptrdiff_t diff;
       register char * copy;

       if (!chars) {
           while ((c = *cur_pos)) {
               if (!isspace(c))
                 one_past_end = cur_pos + 2;
               ++cur_pos;
               continue;
             }
         } else {
           while ((c = *cur_pos)) {
               if (!in_set(c, chars))
                 one_past_end = cur_pos + 2;
               ++cur_pos;
               continue;
             }
         }
       diff = one_past_end - string;
       copy = malloc(diff);
       if (!copy)
         return NULL;

       --diff;
       copy[diff] = '\0';
       return memcpy(copy, string, diff);
     }

   int main(void) {
       char *tests[] = {
           "",
           " ",
           "        ",
           "f",
           " f",
           "   f",
           "   f   ",
           "   f ",
           "f   ",
           "f ",
           "foo bar   baz",
           " foo bar   baz",
           "                  foo bar   baz",
           "                  foo bar   baz                 ",
           " foo bar   baz                ",
           "foo bar   baz                ",
           "foo bar   baz ",
           "mississippi",
         };
       int i;
       char * stripped;

       for (i = 0; i < (sizeof tests / sizeof *tests) - 1; ++i) {
           stripped = rstrip(tests[i], NULL);
           if (stripped)
             printf("[%s]\n", stripped);
           free(stripped);
           continue;
         }
       stripped = rstrip(tests[i], "ipz");
       if (stripped)
         printf("[%s]\n", stripped);
       free(stripped);

       return EXIT_SUCCESS;
     }

[toc] | [prev] | [next] | [standalone]


#17111

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-02-11 13:50 +0000
Message-ID<0.f8fccc7281548c125715.20120211135021GMT.8762fdcwde.fsf@bsb.me.uk>
In reply to#17107
Shao Miller <sha0.miller@gmail.com> writes:

> On 2/10/2012 13:17, peter wrote:
>> Hello C programmers,
>>          I was wondering does anybody knows how or is there
>> a right trim string function available in C?
>>
>>          Eg. Suppose I have the following:
>>
>>             char *str = "Hello Dolly     \0";
>>
>>          Is there a right trim function that will remove the
>> trailing spaces and make *str look like "Hello Dolly\0"?
>>
>> In PYTHON there is a useful function for this: str.rstrip();
>
> Maybe you would like this?:
>
>   /* Also available at http://ideone.com/JBT2Y */
>
>   #include <stddef.h>
>   #include <stdlib.h>
>   #include <string.h>
>   #include <stdio.h>
>
>   static int in_set(
>       register const int c,
>       register const char * chars
>     ) {
>       register int test;
>
>       while ((test = *chars)) {
>           if (c == test)
>             return 1;
>           ++chars;
>           continue;
>         }
>       return 0;
>     }
>
>   char * rstrip(
>       register const char * string,
>       register const char * const chars
>     ) {
>       register char c;
>       register const char * cur_pos = string;
>       register const char * one_past_end = string + 1;
>       register ptrdiff_t diff;
>       register char * copy;
>
>       if (!chars) {
>           while ((c = *cur_pos)) {
>               if (!isspace(c))
>                 one_past_end = cur_pos + 2;
>               ++cur_pos;
>               continue;
>             }
>         } else {
>           while ((c = *cur_pos)) {
>               if (!in_set(c, chars))
>                 one_past_end = cur_pos + 2;
>               ++cur_pos;
>               continue;
>             }
>         }
>       diff = one_past_end - string;
>       copy = malloc(diff);
>       if (!copy)
>         return NULL;
>
>       --diff;
>       copy[diff] = '\0';
>       return memcpy(copy, string, diff);
>     }

This is a very good effort, but, I am sorry to say, I was able to
understand it eventually.  You might want to study the code posted by
Stefan Ram.  He is undoubtedly ahead of you in matters of pure layout,
but your use of a little-used statement in a position where it is both
suggestive and pointless is a stoke of genius!

If you want to develop your own layout further, I'd humbly suggest that
indenting a closing } by half the indent used for the body could be
improved.  Yes, there's nothing to line the } up with visually, but an
indent of 2 is just about enough for the human eye to follow without
that clue.

As for the semantics, I thought the idea of keeping "one_past_end" one
greater than it needs to be (thereby toying, teasingly, with UB all the
time) was a very nice touch -- it's always nice to see a '+ 2' in a
string-walking loop.  And what can I say about the omission of #include
<ctype.h>?  I had to check the standard so see if the implied
declaration, together with the default argument promotions, made the
code valid.  A masterful flourish.

Some things are low-blows, though.  Did you really think anyone would be
confused by the fact that only one of the parameters to rstrip is const?
Shame on you!  The register declarations hide it, but it's a fair bet
the people won't even notice!

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#17112

FromShao Miller <sha0.miller@gmail.com>
Date2012-02-11 11:47 -0500
Message-ID<jh65sd$2dh$1@dont-email.me>
In reply to#17111
On 2/11/2012 08:50, Ben Bacarisse wrote:
> Shao Miller<sha0.miller@gmail.com>  writes:
>
>> On 2/10/2012 13:17, peter wrote:
>>> Hello C programmers,
>>>           I was wondering does anybody knows how or is there
>>> a right trim string function available in C?
>>>
>>>           Eg. Suppose I have the following:
>>>
>>>              char *str = "Hello Dolly     \0";
>>>
>>>           Is there a right trim function that will remove the
>>> trailing spaces and make *str look like "Hello Dolly\0"?
>>>
>>> In PYTHON there is a useful function for this: str.rstrip();
>>
>> Maybe you would like this?:
>>
>
> This is a very good effort, but, I am sorry to say, I was able to
> understand it eventually.

No need to apologize.  I'm glad that you eventually understood it 
without any comments to follow along with.  If it had been a more 
instructive example, it would have included comments.

> You might want to study the code posted by
> Stefan Ram.

I studied it before typing my code.

His code walks to the end of the string via 'strlen' and then walks 
backwards to the first non-space.  My code does not walk over elements 
of the original string twice until the 'memcpy'.

His code does not return a trimmed copy of the original string.  Mine 
attempts to, akin to the OP's Python reference, which the OP apparently 
enjoys.

His code does not accept a set of characters to be used for trimming the 
right side of a string.  Mine attempts to, akin to the OP's Python 
reference, which the OP apparently enjoys.

> He is undoubtedly ahead of you in matters of pure layout,

What do you mean?  Stylistically?  In regards to program flow?  In 
regards to object usage?  His program and mine do different things, so...

> but your use of a little-used statement in a position where it is both
> suggestive and pointless is a stoke of genius!
>

Are you referring to the keyword (not statement) 'register'?  If so, 
it's a storage-class specifier.  While it suggests that access to 
so-specified objects "be as fast as possible," it also ensures that the 
address of a so-specified object cannot be taken.  In this fashion, it 
is used in my code to prevent accidentally taking the address of the 
corresponding objects.  I believe that this is similar to how 'const' 
can be removed from a well-behaved program without changing the 
behaviour.  Am I mistaken?

> If you want to develop your own layout further, I'd humbly suggest that
> indenting a closing } by half the indent used for the body could be
> improved.  Yes, there's nothing to line the } up with visually, but an
> indent of 2 is just about enough for the human eye to follow without
> that clue.
>

If you don't like it, I'm sorry about that.  That's currently my 
preference and maybe that will change some day.  My rationale is that 
any continuation of a statement be indented further than the beginning 
line of the statement, as I think you noticed.  I also sometimes do:

   int ok;

   int ok = (
       condition1 &&
       condition2 &&
       condition3 ||
       condition4
     );
   if (ok)
     foo();
     else
     bar();

instead of:

   if (condition1 && condition2 &&
       condition3 || condition4) {
     foo();
   }
   else {
     bar();
   }

Whose 'else' is that, anyway?

If the conditions are someday changed, the 'diff' for the former looks a 
bit different than the 'diff' of the latter.  I enjoy the former more.

> As for the semantics, I thought the idea of keeping "one_past_end" one
> greater than it needs to be (thereby toying, teasingly, with UB all the
> time) was a very nice touch -- it's always nice to see a '+ 2' in a
> string-walking loop.

Why is it one greater than it needs to be?  If 'c' is not the null 
terminator, then one past the end of the string is at least two 
characters away.  That distance seems useful for the 'malloc'.

> And what can I say about the omission of #include
> <ctype.h>?  I had to check the standard so see if the implied
> declaration, together with the default argument promotions, made the
> code valid.  A masterful flourish.
>

Actually, it was absolutely unintentional.  That's what I get for 
hastily pasting code at 3:52 am.  Thank you for pointing that out.  I'm 
glad that it worked out anyway. ;)

> Some things are low-blows, though.  Did you really think anyone would be
> confused by the fact that only one of the parameters to rstrip is const?
> Shame on you!  The register declarations hide it, but it's a fair bet
> the people won't even notice!

Another unintentional.  At one point I had the 'const' in, but was 
trying to save objects and considered re-purposing 'string', so I took 
it out.  I forgot to put it back in.  Thank you for pointing that out, 
too.  Fortunately, 'const' and 'register' can be removed from the 
entirety, but can be used to prevent accidents...  Except for forgetting 
to use them. ;)

Why didn't you point out the redundancy of my 'continue's?  Doesn't it 
seem like another "extra" like 'register' and 'const'?

I originally started writing the whole thing as a 'while' with no body 
but a complex controlling expression.  Then I thought it'd be clearer 
without that.

Here is the corrected code:

   /* Also available at http://ideone.com/Y5sz6 */

   #include <stddef.h>
   #include <ctype.h>
   #include <stdlib.h>
   #include <string.h>
   #include <stdio.h>

   static int in_set(
       register const int c,
       register const char * chars
     ) {
       register int test;

       while ((test = *chars)) {
           if (c == test)
             return 1;
           ++chars;
           continue;
         }
       return 0;
     }

   char * rstrip(
       register const char * const string,
       register const char * const chars
     ) {
       register char c;
       register const char * cur_pos = string;
       register const char * one_past_end = string + 1;
       register ptrdiff_t diff;
       register char * copy;

       if (!chars) {
           while ((c = *cur_pos)) {
               if (!isspace(c))
                 one_past_end = cur_pos + 2;
               ++cur_pos;
               continue;
             }
         } else {
           while ((c = *cur_pos)) {
               if (!in_set(c, chars))
                 one_past_end = cur_pos + 2;
               ++cur_pos;
               continue;
             }
         }
       diff = one_past_end - string;
       copy = malloc(diff);
       if (!copy)
         return NULL;

       --diff;
       copy[diff] = '\0';
       return memcpy(copy, string, diff);
     }

   int main(void) {
       char *tests[] = {
           "",
           " ",
           "        ",
           "f",
           " f",
           "   f",
           "   f   ",
           "   f ",
           "f   ",
           "f ",
           "foo bar   baz",
           " foo bar   baz",
           "                  foo bar   baz",
           "                  foo bar   baz                 ",
           " foo bar   baz                ",
           "foo bar   baz                ",
           "foo bar   baz ",
           "mississippi",
         };
       int i;
       char * stripped;

       for (i = 0; i < (sizeof tests / sizeof *tests) - 1; ++i) {
           stripped = rstrip(tests[i], NULL);
           if (stripped)
             printf("[%s]\n", stripped);
           free(stripped);
           continue;
         }
       stripped = rstrip(tests[i], "ipz");
       if (stripped)
         printf("[%s]\n", stripped);
       free(stripped);

       return EXIT_SUCCESS;
     }

[toc] | [prev] | [next] | [standalone]


#17113

FromShao Miller <sha0.miller@gmail.com>
Date2012-02-11 12:20 -0500
Message-ID<jh67qq$e3r$1@dont-email.me>
In reply to#17112
On 2/11/2012 11:47, Shao Miller wrote:
> On 2/11/2012 08:50, Ben Bacarisse wrote:
>> but your use of a little-used statement in a position where it is both
>> suggestive and pointless is a stoke of genius!
>>
> Are you referring to the keyword (not statement) 'register'? If so, it's
> a storage-class specifier. While it suggests that access to so-specified
> objects "be as fast as possible," it also ensures that the address of a
> so-specified object cannot be taken. In this fashion, it is used in my
> code to prevent accidentally taking the address of the corresponding
> objects. I believe that this is similar to how 'const' can be removed
> from a well-behaved program without changing the behaviour. Am I mistaken?
>
>
> Why didn't you point out the redundancy of my 'continue's? Doesn't it
> seem like another "extra" like 'register' and 'const'?
>

It just occurred to me that you were talking about the jump statement 
'continue', rather than the storage-class specifier 'register'.  It's in 
there as a habit because of the ability to hook it with a macro for 
debugging purposes.

   #if DEBUG_ITERATIONS
   #define continue \
     if (1) { \
         puts("Continuing iteration"); \
         continue; \
       } else do ; while (0)
   #endif

[toc] | [prev] | [next] | [standalone]


#17126

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-02-11 20:57 +0000
Message-ID<0.71bf05819c758b1cde8e.20120211205709GMT.87aa4pay1m.fsf@bsb.me.uk>
In reply to#17112
Shao Miller <sha0.miller@gmail.com> writes:

> On 2/11/2012 08:50, Ben Bacarisse wrote:
>> Shao Miller<sha0.miller@gmail.com>  writes:
>>
>>> On 2/10/2012 13:17, peter wrote:
>>>> Hello C programmers,
>>>>           I was wondering does anybody knows how or is there
>>>> a right trim string function available in C?
>>>>
>>>>           Eg. Suppose I have the following:
>>>>
>>>>              char *str = "Hello Dolly     \0";
>>>>
>>>>           Is there a right trim function that will remove the
>>>> trailing spaces and make *str look like "Hello Dolly\0"?
>>>>
>>>> In PYTHON there is a useful function for this: str.rstrip();
>>>
>>> Maybe you would like this?:
>>>
>>
>> This is a very good effort, but, I am sorry to say, I was able to
>> understand it eventually.
>
> No need to apologize.  I'm glad that you eventually understood it
> without any comments to follow along with.  If it had been a more
> instructive example, it would have included comments.

My post was an attempt at humour that seems to have failed.  Sorry about
that.  Because style discussions are generally unproductive (people who
use non-standard styles always know that the reasons they do it are
worth it) I wanted to say "Personally, I don't like your choices and BTW
you forgot to include ctype.h" in a more interesting way than that.

I'm sorry if it was not funny.

>> You might want to study the code posted by
>> Stefan Ram.
<snip>
>> He is undoubtedly ahead of you in matters of pure layout,
>
> What do you mean?  Stylistically?  In regards to program flow?  In
> regards to object usage?  His program and mine do different things,
> so...

Yes, stylistically.  I find his highly non-standard layout very hard to
read.

>> but your use of a little-used statement in a position where it is both
>> suggestive and pointless is a stoke of genius!
>
> Are you referring to the keyword (not statement) 'register'?

No, as you later posted it was the continue at the bottom of every loop.

>  If so,
> it's a storage-class specifier.  While it suggests that access to
> so-specified objects "be as fast as possible," it also ensures that
> the address of a so-specified object cannot be taken.  In this
> fashion, it is used in my code to prevent accidentally taking the
> address of the corresponding objects.

You see?  I was sure you'd have a reason for that,  Just chuckle at my
Luddite failure to perceive the value of it.

<snip>
>> As for the semantics, I thought the idea of keeping "one_past_end" one
>> greater than it needs to be (thereby toying, teasingly, with UB all the
>> time) was a very nice touch -- it's always nice to see a '+ 2' in a
>> string-walking loop.
>
> Why is it one greater than it needs to be?  If 'c' is not the null
> terminator, then one past the end of the string is at least two
> characters away.  That distance seems useful for the 'malloc'.

It's swings and roundabouts.  You need to --diff to set the null and do
the memcpy and if you keep the pointer "nearer" you need to +1 when you
malloc.  The latter is, at least, a common idiom.  I.e.:

     char c;
     const char * cur_pos = string;
     const char * one_past_end = string;
     ptrdiff_t diff;
     char * copy;

     if (!chars) {
          while ((c = *cur_pos++))
               if (!isspace(c))
                    one_past_end = cur_pos;
     }
     else {
          while ((c = *cur_pos++))
               if (!in_set(c, chars))
                    one_past_end = cur_pos;
     }
     diff = one_past_end - string;
     copy = malloc(diff + 1);
     if (!copy)
          return NULL;

     copy[diff] = '\0';
     return memcpy(copy, string, diff);

Personally, I'd then change "diff" to "length".  I've also moved the ++
of cur_pos to the loop, but if you don't like that you can go back to

     while ((c = *cur_pos)) {
         if (!isspace(c))
             one_past_end = cur_pos + 1;
         ++cur_pos;
     }

but it's then clear that the ++cur_pos could go above the "if" and thus
into the loop condition.

<snip>

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


Page 2 of 3 — ← Prev page 1 [2] 3  Next page →

Back to top | Article view | comp.lang.c


csiph-web