Dynamic C String Question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • intercom5

    #1

    Dynamic C String Question

    I'm writing a program in C, and thus have to use C strings. The
    problem that I am having is I don't know how to reallocate the space
    for a C string outside the scope of that string. For example:


    int main(void)
    {
    char *string1;
    string1 = malloc(6);
    sprintf(string1 , "Hello");
    foo(string1);

    }

    void foo(char *string)
    {
    string = realloc(string, 12);
    strcat(string, " World");
    }


    In this example, I reallocate the space for a string declacred in
    another function in the function foo. But, after it returns to main
    from the function foo, the C string will only contain "Hello". The
    changes from the function foo have disappered. I suspect this is
    because the reallocation has gone out of scope - and I have no idea how
    to keep the changes after the function returns.
    Any help would greatly be appreciated.

    --Sachin

  • Karthik Kumar

    #2
    Re: Dynamic C String Question

    intercom5 wrote:[color=blue]
    > I'm writing a program in C, and thus have to use C strings. The
    > problem that I am having is I don't know how to reallocate the space
    > for a C string outside the scope of that string. For example:
    >
    >
    > int main(void)
    > {
    > char *string1;
    > string1 = malloc(6);
    > sprintf(string1 , "Hello");
    > foo(string1);
    >
    > }
    >
    > void foo(char *string)
    > {
    > string = realloc(string, 12);
    > strcat(string, " World");
    > }
    >
    >
    > In this example, I reallocate the space for a string declacred in
    > another function in the function foo. But, after it returns to main
    > from the function foo, the C string will only contain "Hello". The
    > changes from the function foo have disappered. I suspect this is
    > because the reallocation has gone out of scope - and I have no idea how
    > to keep the changes after the function returns.
    >[/color]

    pointer to pointer could be the answer.

    int main(void)
    {
    char *string1;
    string1 = malloc(6);
    sprintf(string1 , "Hello");
    foo(&string1);

    }

    void foo(char **string)
    {
    *string = realloc(string, 12);
    strcat(*string, " World");
    }

    Comment

    • Karthik Kumar

      #3
      Re: Dynamic C String Question

      intercom5 wrote:[color=blue]
      > I'm writing a program in C, and thus have to use C strings. The
      > problem that I am having is I don't know how to reallocate the space
      > for a C string outside the scope of that string. For example:
      >
      >
      > int main(void)
      > {
      > char *string1;
      > string1 = malloc(6);
      > sprintf(string1 , "Hello");
      > foo(string1);
      >
      > }
      >
      > void foo(char *string)
      > {
      > string = realloc(string, 12);
      > strcat(string, " World");
      > }
      >
      >
      > In this example, I reallocate the space for a string declacred in
      > another function in the function foo. But, after it returns to main
      > from the function foo, the C string will only contain "Hello". The
      > changes from the function foo have disappered. I suspect this is
      > because the reallocation has gone out of scope - and I have no idea how
      > to keep the changes after the function returns.[/color]

      Actually the subtle change is because , realloc has moved everything
      to a new address. (it is allowed to do that, of course ) because
      the requested new size is > the prev. size.

      OTOH, if you had requested less than the original size,
      then it may not move it and just reallocate memory.
      In that case, the original pointer might be still valid
      after the function returns.

      realloc is a multi-edged sword, indeed :) . Use it with care.

      Comment

      • Ravi Uday

        #4
        Re: Dynamic C String Question



        intercom5 wrote:[color=blue]
        > I'm writing a program in C, and thus have to use C strings. The
        > problem that I am having is I don't know how to reallocate the space
        > for a C string outside the scope of that string. For example:
        >
        >
        > int main(void)
        > {
        > char *string1;
        > string1 = malloc(6);
        > sprintf(string1 , "Hello");
        > foo(string1);
        >
        > }
        >
        > void foo(char *string)
        > {
        > string = realloc(string, 12); /* Where did u get this magic 12 ? not a good practise. */
        > strcat(string, " World");
        > }[/color]
        Always check for return values of *alloc functions.
        Return the string from foo !
        Modified version is:

        char *foo (char *string)
        {
        string = realloc(string, 12);
        if (string)
        strcat(string, " World");

        return string;
        }
        int main(void)
        {
        char *string1;
        string1 = malloc(6);
        if (!string1)
        return 0; /* Handle failures before returning. */

        sprintf(string1 , "Hello"); /* Just strcpy would do here -
        strcpy(string1, "Hello"); */
        string1 = foo(string1);
        puts (string1);
        return 0;
        }
        [color=blue]
        >
        >
        > In this example, I reallocate the space for a string declacred in
        > another function in the function foo. But, after it returns to main
        > from the function foo, the C string will only contain "Hello". The
        > changes from the function foo have disappered. I suspect this is
        > because the reallocation has gone out of scope - and I have no idea how
        > to keep the changes after the function returns.
        > Any help would greatly be appreciated.
        >
        > --Sachin
        >[/color]

        Comment

        • Martin Ambuhl

          #5
          Re: Dynamic C String Question

          Karthik Kumar wrote:
          [color=blue]
          > pointer to pointer could be the answer.
          >
          > int main(void)
          > {
          > char *string1;
          > string1 = malloc(6);
          > sprintf(string1 , "Hello");
          > foo(&string1);
          >
          > }
          >
          > void foo(char **string)
          > {
          > *string = realloc(string, 12);[/color]
          ^
          missing '*', innit?[color=blue]
          > strcat(*string, " World");
          > }[/color]

          Comment

          • Charlie Gordon

            #6
            Re: Dynamic C String Question

            "Karthik Kumar" <kaykaylance_no spamplz@yahoo.c om> wrote in message
            news:41c90b47$1 @darkstar...
            [color=blue]
            > Actually the subtle change is because , realloc has moved everything
            > to a new address. (it is allowed to do that, of course ) because
            > the requested new size is > the prev. size.[/color]

            It is allowed to do that in all cases !
            [color=blue]
            > OTOH, if you had requested less than the original size,
            > then it may not move it and just reallocate memory.
            > In that case, the original pointer might be still valid
            > after the function returns.[/color]

            don't rely in this : C99 just hints that the new and old pointers may be the
            same, but they may also be different, even if the size doesn't change or if it
            is reduced.
            [color=blue]
            > realloc is a multi-edged sword, indeed :) . Use it with care.[/color]

            Or even better : realloc() is too complex to use for newbies, it has an error
            prone API, it is *strongly* recommended to not use it at all !

            --
            Chqrlie.


            Comment

            • intercom5

              #7
              Re: Dynamic C String Question

              thanks guys. using a pointer to a pointer worked.

              Comment

              • infobahn

                #8
                Re: Dynamic C String Question

                intercom5 wrote:[color=blue]
                > I'm writing a program in C, and thus have to use C strings. The
                > problem that I am having is I don't know how to reallocate the space
                > for a C string outside the scope of that string. For example:
                >
                >
                > int main(void)
                > {
                > char *string1;
                > string1 = malloc(6);
                > sprintf(string1 , "Hello");
                > foo(string1);
                >
                > }
                >
                > void foo(char *string)
                > {
                > string = realloc(string, 12);[/color]

                Quite apart from the problem you know you have, you also have a couple
                of problems you don't know you have.
                [color=blue]
                > strcat(string, " World");
                > }
                >
                >
                > In this example, I reallocate the space for a string declacred in
                > another function in the function foo. But, after it returns to main
                > from the function foo, the C string will only contain "Hello". The
                > changes from the function foo have disappered. I suspect this is
                > because the reallocation has gone out of scope - and I have no idea how
                > to keep the changes after the function returns.
                > Any help would greatly be appreciated.[/color]

                If you want a function to update a value in an object available to
                the calling function, you pass that object's address to the
                function. Now, in this case your object is called string1. It
                happens to be a pointer, but that doesn't make it special. If you
                want foo() to alter the value of string1, you must pass string1's
                address to foo().

                The following code is based heavily on your own code; I have changed
                the indentation to make it more readable to others, and added error
                checking, but I haven't "fixed" the code to my own style and preference,
                tempting though the idea was.

                #include <stdio.h> /* 1 */
                #include <stdlib.h> /* 2 */

                int foo(char **); /* 3 */

                int main(void)
                {
                char *string1;
                string1 = malloc(6);
                if(string1 != NULL) /* 4 */
                {
                sprintf(string1 , "%s", "Hello"); /* 5 */
                if(foo(&string1 ) == 0) /* 6 */
                {
                printf("%s\n", string1);
                }
                free(string1); /* 7 */
                }

                return 0; /* 8 */
                }

                int foo(char **string) /* 9 */
                {
                char *p = realloc(*string , 12); /* 10 */
                if(p != NULL) /* 11 */
                {
                *string = p; /* 12 */
                strcat(*string, " World"); /* 13 */
                }
                return p == NULL; /* 14 */
                }

                Notes

                1. Prototype for sprintf (and a printf I added myself).
                2. Prototype for malloc and free.
                3. Prototype for foo. Note the change in return type,
                as well as the change in arg type.
                4. After a resource request, check that the request
                succeeded instead of just assuming it did.
                5. When sprintfing, bear in mind that your data may
                contain formatting characters relevant to sprintf
                (e.g. %). To avoid this from causing alarming
                problems, always specify a format string.
                6. Pass the ADDRESS of string1 to foo, and CHECK
                the return value.
                7. When you've finished with a resource, give it back.
                8. main() returns int, so return an int from main().
                9. We need to update a pointer and have that change
                "stick", so we accept a pointer to the pointer.
                10. Note the use of the temporary object p. This
                temporary object can catch the return value from
                realloc. If realloc fails, p will be NULL, but
                *string will remain unchanged, so we at least
                can still use the memory we started with.
                Also note the use of *string rather than string.
                11. See note 4.
                12. If the request succeeded, we can (and indeed
                MUST) update *string with the new value; the
                old value may no longer valid and should not
                be used. (If it /is/ still valid, then p == *string
                anyway, but there's no way to test for this
                without using *string's value, which - as I said -
                may not be valid!)
                13. Note again the use of *string.
                14. This function needs some way of communicating to
                its caller whether the allocation request succeeded
                or not. An easy way to do this is via an int
                return value (here, I chose 0 == success, non-0
                == failure).

                Sorry for the long reply. HTH. HAND.

                Comment

                • infobahn

                  #9
                  Re: Dynamic C String Question

                  Karthik Kumar wrote:

                  <snip>
                  [color=blue]
                  >
                  > pointer to pointer could be the answer.
                  >
                  > int main(void)
                  > {
                  > char *string1;
                  > string1 = malloc(6);
                  > sprintf(string1 , "Hello");
                  > foo(&string1);
                  >
                  > }
                  >
                  > void foo(char **string)
                  > {
                  > *string = realloc(string, 12);[/color]

                  This won't work. You meant:

                  *string = realloc(*string , 12);

                  Had you tested your code before posting, you'd have discovered this.

                  Comment

                  • Emmanuel Delahaye

                    #10
                    Re: Dynamic C String Question

                    Karthik Kumar wrote on 22/12/04 :[color=blue]
                    > void foo(char **string)
                    > {
                    > *string = realloc(string, 12);[/color]

                    *string = realloc(*string , 12);

                    --
                    Emmanuel
                    The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
                    The C-library: http://www.dinkumware.com/refxc.html

                    "Clearly your code does not meet the original spec."
                    "You are sentenced to 30 lashes with a wet noodle."
                    -- Jerry Coffin in a.l.c.c++

                    Comment

                    • infobahn

                      #11
                      Re: Dynamic C String Question

                      Charlie Gordon wrote:[color=blue]
                      > "Karthik Kumar" <kaykaylance_no spamplz@yahoo.c om> wrote in message
                      > news:41c90b47$1 @darkstar...
                      >[color=green]
                      >>realloc is a multi-edged sword, indeed :) . Use it with care.[/color]
                      >
                      >
                      > Or even better : realloc() is too complex to use for newbies, it has an error
                      > prone API, it is *strongly* recommended to not use it at all ![/color]

                      I used to think the same thing, but the reality is that realloc is
                      just too useful to discard.

                      It does take a modicum of care to use realloc correctly but, once
                      you have learned how to do it, it's actually not at all complex. Anyone
                      who cannot master realloc is going to struggle in their programming
                      career, for the simple reason that they are required to master lots
                      of stuff that is much, much more complex than realloc.

                      Comment

                      • Flash Gordon

                        #12
                        Re: Dynamic C String Question

                        On Wed, 22 Dec 2004 06:50:35 +0000 (UTC)
                        infobahn <infobahn@btint ernet.com> wrote:
                        [color=blue]
                        > Karthik Kumar wrote:
                        >
                        > <snip>
                        >[color=green]
                        > >
                        > > pointer to pointer could be the answer.
                        > >
                        > > int main(void)
                        > > {
                        > > char *string1;
                        > > string1 = malloc(6);[/color][/color]

                        You need to test to see if malloc has failed.
                        [color=blue][color=green]
                        > > sprintf(string1 , "Hello");
                        > > foo(&string1);
                        > >
                        > > }
                        > >
                        > > void foo(char **string)
                        > > {
                        > > *string = realloc(string, 12);[/color]
                        >
                        > This won't work. You meant:
                        >
                        > *string = realloc(*string , 12);
                        >
                        > Had you tested your code before posting, you'd have discovered this.[/color]

                        Also, if the realloc fails you have lost your pointer to the memory you
                        still have allocated.

                        void foo(char **my_string)
                        {
                        char *tmp = realloc(*my_str ing, 12);
                        if (tmp == NULL) {
                        /* handle error */
                        }
                        else {
                        *my_string = tmp
                        }
                        }

                        I've also changed the name because identifiers starting with str
                        followed by another letter, such as string, are reserved.
                        --
                        Flash Gordon
                        Living in interesting times.
                        Although my email address says spam, it is real and I read it.

                        Comment

                        • Al Bowers

                          #13
                          Re: Dynamic C String Question



                          infobahn wrote:

                          [color=blue]
                          >
                          > The following code is based heavily on your own code; I have changed
                          > the indentation to make it more readable to others, and added error
                          > checking, but I haven't "fixed" the code to my own style and preference,
                          > tempting though the idea was.
                          >[/color]

                          I realize that you are using the routines provided by the op, but
                          without too much trouble you can provide protection should the function
                          be called with no previous allocations, i.e. should *string == NULL.
                          If you do this then you need not worry with doing the initial allocation
                          in function main. Instead, use the function for the initial string and
                          subsequent appends.
                          [color=blue]
                          >
                          > int foo(char **string) /* 9 */
                          > {
                          > char *p = realloc(*string , 12); /* 10 */
                          > if(p != NULL) /* 11 */
                          > {
                          > *string = p; /* 12 */
                          > strcat(*string, " World"); /* 13 */
                          > }
                          > return p == NULL; /* 14 */
                          > }
                          >[/color]

                          Should *string be NULL and the allocation succeed, you would
                          need to assign string[0] the value of '\0' for the strcat
                          function to work.

                          Example:

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

                          int dCatStr(char **s, const char *catstr)
                          {
                          char *tmp;
                          size_t curlen = *s?strlen(*s):0 ;

                          if((tmp = realloc(*s,curl en+strlen(catst r)+1)) != NULL)
                          {
                          if(curlen == 0) *tmp = '\0';
                          *s = tmp;
                          strcat(*s,catst r);
                          }
                          return tmp?1:0;
                          }

                          int main(void)
                          {
                          char *string1 = NULL;

                          if(dCatStr(&str ing1,"Hello"))
                          if(dCatStr(&str ing1," World!"))
                          printf("string1 = \"%s\"\n",strin g1);
                          else puts("FAILURE: to append");
                          else puts("FAILURE: to append");
                          free(string1);
                          return 0;
                          }

                          --
                          Al Bowers
                          Tampa, Fl USA
                          mailto: xabowers@myrapi dsys.com (remove the x to send email)
                          Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!


                          Comment

                          • infobahn

                            #14
                            Re: Dynamic C String Question

                            Flash Gordon wrote:[color=blue]
                            > On Wed, 22 Dec 2004 06:50:35 +0000 (UTC)
                            > infobahn <infobahn@btint ernet.com> wrote:
                            >
                            >[color=green]
                            >>Karthik Kumar wrote:
                            >>
                            >><snip>
                            >>[color=darkred]
                            >>> pointer to pointer could be the answer.
                            >>>
                            >>>int main(void)
                            >>>{
                            >>>char *string1;
                            >>>string1 = malloc(6);[/color][/color]
                            >
                            >
                            > You need to test to see if malloc has failed.[/color]

                            Well, Earthik Kumar does. If you glance over my
                            reply to the OP, you'll find that I addressed
                            this issue, and all the others you mentioned, except ...

                            <snip>
                            [color=blue]
                            > void foo(char **my_string)
                            > {
                            > char *tmp = realloc(*my_str ing, 12);
                            > if (tmp == NULL) {
                            > /* handle error */
                            > }
                            > else {
                            > *my_string = tmp
                            > }
                            > }
                            >
                            > I've also changed the name because identifiers starting with str
                            > followed by another letter, such as string, are reserved.[/color]

                            Not local identifiers.

                            Comment

                            • infobahn

                              #15
                              Re: Dynamic C String Question

                              Al Bowers wrote:[color=blue]
                              >
                              >
                              > infobahn wrote:
                              >
                              >[color=green]
                              >>
                              >> The following code is based heavily on your own code; I have changed
                              >> the indentation to make it more readable to others, and added error
                              >> checking, but I haven't "fixed" the code to my own style and preference,
                              >> tempting though the idea was.
                              >>[/color]
                              >
                              > I realize that you are using the routines provided by the op,[/color]

                              Right.
                              [color=blue]
                              > but
                              > without too much trouble you can provide protection should the function
                              > be called with no previous allocations, i.e. should *string == NULL.
                              > If you do this then you need not worry with doing the initial allocation
                              > in function main. Instead, use the function for the initial string and
                              > subsequent appends.[/color]

                              I thought I'd squeezed all the juice out of it, but you're right - I
                              should have suggested this myself. Apologies for my omission.

                              <snip>
                              [color=blue]
                              > Example:
                              >
                              > #include <stdlib.h>
                              > #include <string.h>
                              > #include <stdio.h>
                              >
                              > int dCatStr(char **s, const char *catstr)
                              > {
                              > char *tmp;[/color]

                              It would be profitable to add an assertion here:

                              assert(s != NULL);

                              before dereferencing s. This would of course involve including
                              <assert.h> and, in C90, enclosing the remainder of the code in
                              a block { }, or separating the definition of curlen from the
                              test on *s (for the obvious reason).

                              <snip>

                              Comment

                              Working...