strupr Postmortem Analysis

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • humanmutantman@yahoo.com

    strupr Postmortem Analysis

    I found a string to upper function that looks like this:

    char *strupr(char *string)
    {
    char *s;
    if (string)
    {
    for (s = string; *s; ++s)
    *s = toupper(*s);
    }
    return string;
    }

    It works and all is ok, but I thought I could trim it down to the
    following that doesn't work:

    char *strupr(char *string)
    {
    // char *s;
    if (string)
    {
    // for (s = string; *s; ++s)
    for (string; *string; ++string)
    // *s = toupper(*s);
    *string = toupper(*string );
    }
    return string;
    }

    Can someone explain why the bottom function doesn't work? Thanks!

  • Chris Smith

    #2
    Re: strupr Postmortem Analysis

    <humanmutantman @yahoo.comwrote :
    I found a string to upper function that looks like this:
    >
    char *strupr(char *string)
    {
    char *s;
    if (string)
    {
    for (s = string; *s; ++s)
    *s = toupper(*s);
    }
    return string;
    }
    >
    It works and all is ok, but I thought I could trim it down to the
    following that doesn't work:
    >
    char *strupr(char *string)
    {
    // char *s;
    if (string)
    {
    // for (s = string; *s; ++s)
    for (string; *string; ++string)
    // *s = toupper(*s);
    *string = toupper(*string );
    }
    return string;
    }
    >
    Can someone explain why the bottom function doesn't work? Thanks!
    Yes. The original function kept a copy of the beginning of the string
    ('string'), and returned it. In the second function, you are returning
    the modified pointer, which now points to the terminating NUL character.

    --
    Chris Smith - Lead Software Developer / Technical Trainer
    MindIQ Corporation

    Comment

    • humanmutantman@yahoo.com

      #3
      Re: strupr Postmortem Analysis

      I found a string to upper function that looks like this:
      >
      char *strupr(char *string)
      {
      char *s;
      if (string)
      {
      for (s = string; *s; ++s)
      *s = toupper(*s);
      }
      return string;
      }
      >
      It works and all is ok, but I thought I could trim it down to the
      following that doesn't work:
      >
      line 1char *strupr(char *string)
      line 2{
      line 3// char *s;
      line 4 if (string)
      line 5 {
      line 6// for (s = string; *s; ++s)
      line 7 for (string; *string; ++string)
      line 8// *s = toupper(*s);
      line 9 *string = toupper(*string );
      line 10 }
      line 11 return string;
      line 12}
      >
      Can someone explain why the bottom function doesn't work? Thanks!
      I see part of the problem: line 9, "*string = toupper(*string );". I'm
      stepping over the contents of the pointer "string", yes? As the
      modified code is written, every instance through the for loop, *string
      is given some new value which then breaks, yes?

      If someone could step me through the loop that might clear things up
      for me. I'm new to pointers... Thanks.

      Comment

      • Robert Gamble

        #4
        Re: strupr Postmortem Analysis

        humanmutantman@ yahoo.com wrote:
        I found a string to upper function that looks like this:
        >
        char *strupr(char *string)
        Identifiers beginning with "str" followed by a lowercase letter are
        reserved for future string functions.
        {
        char *s;
        if (string)
        {
        for (s = string; *s; ++s)
        *s = toupper(*s);
        That should really be "*s = toupper((unsign ed char)*s);", char can be
        signed and passing a value that does not fit into an unsigned char and
        is not EOF is undefined.
        }
        return string;
        }
        >
        It works and all is ok, but I thought I could trim it down to the
        following that doesn't work:
        >
        char *strupr(char *string)
        {
        // char *s;
        if (string)
        {
        // for (s = string; *s; ++s)
        for (string; *string; ++string)
        // *s = toupper(*s);
        *string = toupper(*string );
        }
        return string;
        }
        >
        Can someone explain why the bottom function doesn't work? Thanks!
        What do you mean by "doesn't work"? What did it do differently than
        what you expected? Where is the actual code that you are using that
        demonstrates the problem?

        The second function is not functionally identical to the first one; the
        first function returns a pointer to the beginning of the string
        provided, the second function returns a pointer to the end of the
        string. If you are doing something like this:

        char s[] = "test";
        printf("%s\n", strupr(s));

        the result probably won't be what you expect whereas this:

        char s[] = "test";
        strupr(s);
        printf("%s\n", s);

        will work as expected.

        It should be noted that since the function operates on the string
        provided that something like this would result in undefined behavior:

        strupr("test");

        The first function can be reduced to something like this:

        char *strupr(char *string)
        {
        char *s = string;
        if (s)
        for (s; *s; ++s)
        *s = toupper(*s);
        return string;
        }

        (Some people would object to the lack of brackets, add them as you see
        fit.)

        or even:

        char *strupr(char *string)
        {
        char *s = string;
        if (s)
        do { *s = toupper(*s); } while (*s++);
        return string;
        }

        Robert Gamble

        Comment

        • Ian Collins

          #5
          Re: strupr Postmortem Analysis

          Robert Gamble wrote:
          humanmutantman@ yahoo.com wrote:
          >
          >>I found a string to upper function that looks like this:
          >>
          >>char *strupr(char *string)
          >
          >
          Identifiers beginning with "str" followed by a lowercase letter are
          reserved for future string functions.
          >
          >
          >>{
          > char *s;
          > if (string)
          > {
          > for (s = string; *s; ++s)
          > *s = toupper(*s);
          >
          >
          That should really be "*s = toupper((unsign ed char)*s);", char can be
          signed and passing a value that does not fit into an unsigned char and
          is not EOF is undefined.
          >
          Is it? I thought toupper and tolower return their argument unchanged if
          its value is invalid.

          --
          Ian Collins.

          Comment

          • Frederick Gotham

            #6
            Re: strupr Postmortem Analysis

            posted:
            I found a string to upper function that looks like this:

            The following is far simpler:


            #include <ctype.h>

            void StringUp( char *p )
            {
            while( *p = toupper(*p) ) ++p;
            }



            --

            Frederick Gotham

            Comment

            • Robert Gamble

              #7
              Re: strupr Postmortem Analysis

              Ian Collins wrote:
              Robert Gamble wrote:
              humanmutantman@ yahoo.com wrote:
              >I found a string to upper function that looks like this:
              >
              >char *strupr(char *string)

              Identifiers beginning with "str" followed by a lowercase letter are
              reserved for future string functions.

              >{
              char *s;
              if (string)
              {
              for (s = string; *s; ++s)
              *s = toupper(*s);

              That should really be "*s = toupper((unsign ed char)*s);", char can be
              signed and passing a value that does not fit into an unsigned char and
              is not EOF is undefined.
              Is it? I thought toupper and tolower return their argument unchanged if
              its value is invalid.
              7.4p1 (ctype.h):
              "The header <ctype.hdeclare s 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."

              7.4.2.1p3 (tolower):
              If the argument is a character for which isupper is true and there are
              one or more
              corresponding characters, as specified by the current locale, for which
              islower is true,
              the tolower function returns one of the corresponding characters
              (always the same one
              for any giv en locale); otherwise, the argument is returned unchanged.

              Robert Gamble

              Comment

              • Robert Gamble

                #8
                Re: strupr Postmortem Analysis

                Frederick Gotham wrote:
                posted:
                >
                I found a string to upper function that looks like this:
                >
                >
                The following is far simpler:
                >
                >
                #include <ctype.h>
                >
                void StringUp( char *p )
                {
                while( *p = toupper(*p) ) ++p;
                while(*p = toupper((unsign ed char)*p) ) ++p;
                }
                Simpler, yes, but it doesn't do the same thing as the function the OP
                presented, namely returning a pointer to the beginning of the string
                provided.

                Robert Gamble

                Comment

                • Ian Collins

                  #9
                  Re: strupr Postmortem Analysis

                  Robert Gamble wrote:
                  Ian Collins wrote:
                  >
                  >>Robert Gamble wrote:
                  >>
                  >>>That should really be "*s = toupper((unsign ed char)*s);", char can be
                  >>>signed and passing a value that does not fit into an unsigned char and
                  >>>is not EOF is undefined.
                  >>>
                  >>
                  >>Is it? I thought toupper and tolower return their argument unchanged if
                  >>its value is invalid.
                  >
                  >
                  7.4p1 (ctype.h):
                  "The header <ctype.hdeclare s 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."
                  >
                  7.4.2.1p3 (tolower):
                  If the argument is a character for which isupper is true and there are
                  one or more
                  corresponding characters, as specified by the current locale, for which
                  islower is true,
                  the tolower function returns one of the corresponding characters
                  (always the same one
                  for any giv en locale); otherwise, the argument is returned unchanged.
                  >
                  Can't argue with that.

                  --
                  Ian Collins.

                  Comment

                  • Frederick Gotham

                    #10
                    Re: strupr Postmortem Analysis

                    Robert Gamble posted:

                    while(*p = toupper((unsign ed char)*p) ) ++p;

                    This would imply that the integer at address "p" might be negative.

                    If the integer is negative, then do we not have a error? Forcing the
                    negative number to be positive won't solve the problem.

                    If anything, would the following not be better:

                    #include <assert.h>
                    #include <ctype.h>

                    void StringUp( char *p )
                    {
                    do assert( *p >= 0 );
                    while( *p = toupper( *p ), *p++ );
                    }

                    #include <stdio.h>

                    int main(void)
                    {
                    char array[] = "The man walked by the 3rd door and turned right.";

                    StringUp(array) ;

                    puts(array);
                    }


                    --

                    Frederick Gotham

                    Comment

                    • Chris Torek

                      #11
                      Re: strupr Postmortem Analysis

                      >Robert Gamble posted:
                      >while(*p = toupper((unsign ed char)*p) ) ++p;
                      In article <Y5Fqg.11095$j7 .315293@news.in digo.ie>
                      Frederick Gotham <fgothamNO@SPAM .comwrote:
                      >This would imply that the integer at address "p" might be negative.
                      As indeed it might.
                      >If the integer is negative, then do we not have a error?
                      Maybe, but probably not:

                      /* signed */ char buf[] = "sláinte";
                      /* signed */ char *p = buf;

                      while ((*p = toupper((unsign ed char)*p)) != '\0')
                      p++;
                      puts(buf);

                      Without the "unsigned", on my systems where plain "char" is signed,
                      the word is mangled; with it, on those same systems, it works right
                      (producing SLÁINTE).
                      --
                      In-Real-Life: Chris Torek, Wind River Systems
                      Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
                      email: forget about it http://web.torek.net/torek/index.html
                      Reading email is like searching for food in the garbage, thanks to spammers.

                      Comment

                      • Robert Gamble

                        #12
                        Re: strupr Postmortem Analysis

                        Frederick Gotham wrote:
                        Robert Gamble posted:
                        >
                        >
                        while(*p = toupper((unsign ed char)*p) ) ++p;
                        >
                        >
                        This would imply that the integer at address "p" might be negative.
                        Right, since char may be signed it is certainly possible for the values
                        of an array of char to be negative.
                        If the integer is negative, then do we not have a error?
                        What would be erroneous about it?
                        Forcing the
                        negative number to be positive won't solve the problem.
                        There isn't a problem except the fact that you can't pass a negative
                        value (except EOF) to the toupper function and casting the value to
                        unsigned char certainly does address that.
                        If anything, would the following not be better:
                        >
                        #include <assert.h>
                        #include <ctype.h>
                        >
                        void StringUp( char *p )
                        {
                        do assert( *p >= 0 );
                        Why do you think this *p can't be negative?
                        while( *p = toupper( *p ), *p++ );
                        Yuck, 0 points for style.
                        }
                        >
                        #include <stdio.h>
                        >
                        int main(void)
                        {
                        char array[] = "The man walked by the 3rd door and turned right.";
                        >
                        StringUp(array) ;
                        >
                        puts(array);
                        }
                        It is possible for char to be signed. It is also possible for, in some
                        locale, there to be letters that have negative values. The only way to
                        perform portable case conversions on these characters would be to use
                        the toupper/tolower functions and the only way to do that without
                        invoking undefined behavior is to cast them to unsigned char. The
                        implementation will be expecting to receive such characters so casted.
                        I don't understand where you think the problem lies here.

                        Robert Gamble

                        Comment

                        • humanmutantman@yahoo.com

                          #13
                          Re: strupr Postmortem Analysis

                          I found a string to upper function that looks like this:

                          char *strupr(char *string)
                          >
                          Identifiers beginning with "str" followed by a lowercase letter are
                          reserved for future string functions.
                          >
                          {
                          char *s;
                          if (string)
                          {
                          for (s = string; *s; ++s)
                          *s = toupper(*s);
                          >
                          That should really be "*s = toupper((unsign ed char)*s);", char can be
                          signed and passing a value that does not fit into an unsigned char and
                          is not EOF is undefined.
                          >
                          }
                          return string;
                          }

                          It works and all is ok, but I thought I could trim it down to the
                          following that doesn't work:

                          char *strupr(char *string)
                          {
                          // char *s;
                          if (string)
                          {
                          // for (s = string; *s; ++s)
                          for (string; *string; ++string)
                          // *s = toupper(*s);
                          *string = toupper(*string );
                          }
                          return string;
                          }

                          Can someone explain why the bottom function doesn't work? Thanks!
                          >
                          What do you mean by "doesn't work"? What did it do differently than
                          what you expected? Where is the actual code that you are using that
                          demonstrates the problem?
                          Good point :) . It did work, but sent "nothing" back to the screen... I
                          was expecting to see the capitalized version of the text that was sent
                          in.
                          The second function is not functionally identical to the first one; the
                          first function returns a pointer to the beginning of the string
                          provided, the second function returns a pointer to the end of the
                          string. If you are doing something like this:
                          >
                          char s[] = "test";
                          printf("%s\n", strupr(s));
                          >
                          the result probably won't be what you expect whereas this:
                          >
                          char s[] = "test";
                          strupr(s);
                          printf("%s\n", s);
                          >
                          will work as expected.
                          >
                          It should be noted that since the function operates on the string
                          provided that something like this would result in undefined behavior:
                          >
                          strupr("test");
                          >
                          The first function can be reduced to something like this:
                          >
                          char *strupr(char *string)
                          {
                          char *s = string;
                          if (s)
                          for (s; *s; ++s)
                          *s = toupper(*s);
                          return string;
                          }
                          >
                          (Some people would object to the lack of brackets, add them as you see
                          fit.)
                          >
                          or even:
                          >
                          char *strupr(char *string)
                          {
                          char *s = string;
                          if (s)
                          do { *s = toupper(*s); } while (*s++);
                          return string;
                          }
                          >
                          Robert Gamble
                          Most cool. Thanks for the help!

                          Comment

                          • humanmutantman@yahoo.com

                            #14
                            Re: strupr Postmortem Analysis

                            I found a string to upper function that looks like this:
                            >
                            >
                            The following is far simpler:
                            >
                            >
                            #include <ctype.h>
                            >
                            void StringUp( char *p )
                            {
                            while( *p = toupper(*p) ) ++p;
                            }
                            >
                            >
                            >
                            --
                            >
                            Frederick Gotham
                            I changed your code to this and got "null" back...

                            1 #include <ctype.h>
                            2 #include <stdio.h>
                            3
                            4 //void StringUp( char *p )
                            5 char StringUp( char *p )
                            6 {
                            7 while( *p = toupper(*p) ) ++p;
                            8 return *p;
                            9 }
                            10
                            11 int main()
                            12 {
                            13 char str[20] = {"this is a test"};
                            14 printf("--%s\n",StringUp( str));
                            15 return 0;
                            16 }

                            Is there anyway to salvage what I did to get the all caps string
                            returned from the function?

                            Comment

                            • humanmutantman@yahoo.com

                              #15
                              Re: strupr Postmortem Analysis

                              while(*p = toupper((unsign ed char)*p) ) ++p;
                              >
                              >
                              This would imply that the integer at address "p" might be negative.
                              >
                              If the integer is negative, then do we not have a error? Forcing the
                              negative number to be positive won't solve the problem.
                              >
                              If anything, would the following not be better:
                              >
                              #include <assert.h>
                              #include <ctype.h>
                              >
                              void StringUp( char *p )
                              {
                              do assert( *p >= 0 );
                              while( *p = toupper( *p ), *p++ );
                              }
                              >
                              #include <stdio.h>
                              >
                              int main(void)
                              {
                              char array[] = "The man walked by the 3rd door and turned right.";
                              >
                              StringUp(array) ;
                              >
                              puts(array);
                              }
                              >
                              >
                              --
                              >
                              Frederick Gotham
                              That looks interesting. I tried to convert your code to a function that
                              would return a value and came up with this that seg faults:

                              1 #include <assert.h>
                              2 #include <stdio.h>
                              3
                              4 char StringUp( char *p )
                              5 {
                              6 do assert( *p >= 0 );
                              7 while( *p = toupper( *p ), *p++ );
                              8 return *p;
                              9 }
                              10
                              11 int main(void)
                              12 {
                              13 char array[] = "The man walked by the 3rd door and turned
                              right.";
                              14 printf("--%s\n",StringUp( array));
                              15 }

                              I would think that line 8 should be "return p", but I get:
                              test.c:8: warning: return makes integer from pointer without a cast

                              Once I get the code right to return a value I want to stick some
                              printf's in the function to trace what's going on. Right now I'm not
                              100%... Thanks!

                              Comment

                              Working...